Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (538)
Games in Android Showcase (132)
games submitted by our members
Games in WIP (601)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Cutting up Heightmaps into smaller squares...  (Read 9590 times)
0 Members and 1 Guest are viewing this topic.
Offline Trussell

Junior Devvie




Game Developer


« Posted 2008-08-21 00:31:40 »

Hey all,

This is a more general topic (general meaning non-engine-specific) so I figure this may be a better place to ask my question.

First off, a little background. I have a tile-loader which loads tiles which consist of a terrain-splatting technique and a heightmap. The TileManager class detects (based on your coordinates in the world) what "tile" you would be standing on, and then tries to find the heightmap file in the heightmap directory. If it can't find it, it simply loads a default heightmap (to give us endless terrain).

I am creating my worlds (both heightmaps and texturing via alpha maps) in FreeWorld3D (www.freeworld3d.org), so I was wondering if anybody could offer input as to take a heightmap and cut it into smaller squares?

What I want to do is calculate how many new heightmaps will come out of the original (i.e. 1024 64x64 heightmaps from 1 2048x2048), then create them and name them appropriately. The naming will be very specific to my application and should be based on their coordinates within the image (i.e. 0,0.bmp; 1,1.bmp; 3,4.bmp).

Does anybody have some example code which can take a BMP image and create new smaller images based on subimages? If you do, I'd appreciate it very much.

I was originally using RAW heightmaps, but because of the difficulty of doing this conversion with RAW heightmaps I think I'll be using BMP heightmaps.

-Tyler

I am a noob attempting to make a video game.
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 840
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #1 - Posted 2008-08-21 00:57:58 »

Stick with RAW. BMP has only 8 bits per color-channel, and 256 heightvalues just won't cut it. Further, I don't see what would make RAW any harder to split up too...

lets say you have a heightmap in a short[w*h]

1  
2  
3  
4  
5  
6  
7  
8  
public static short[] sub(short[] sOrg, int wOrg, int x, int y, int wSub, int hSub)
{
   short[] sSub = new short[w*h];
   for(int i=0; i<wSub; i++)
      for(int k=0; k<hSub; k++)
         sSub[k*w+i] = sOrg[(y+k)*wOrg+(x+i)];
   return sSub;
}




I assume you ask this in the context of your MMORPG highschool project. In that case, I'll give you some advise you might not like:

Stay away from building a fancy terrain-renderer with LODing and fancy re-triangulation. This is a project in itself, and will take a long time. Time you could have spent on gameplay! Programming gameplay/interaction is hard enough.

For the sake of building the game, instead of a 'glorified model viewer', i'd advise you to keep the world like 64x64 tiles for the next few months, to keep your framerate high, so you can work on other things without being tempted into optimizing terrain.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Offline Trussell

Junior Devvie




Game Developer


« Reply #2 - Posted 2008-08-21 01:02:23 »

I don't have anything fancy at all, really... the TileLoader just grabs heightmaps and converts them into Terrain Geometry then textures them based on if it has designated alphas in the different layer areas.

The only reason I wish to convert from 1 big map to many small maps is because it's easier to design on a larger scale and then split the maps up... that way I can have a big hill that is in the middle of four different maps and it'll still look fine.

My program (FW3D) exports 24- or 32-bit BMP... is what you said still a problem?

The reason I would like to do BMP is because it allows me to simultaneously cut up the heightmap itself, then the alpha maps... along with the fact that I have no idea how to write a 16-bit RAW heightmap file...

I am a noob attempting to make a video game.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Trussell

Junior Devvie




Game Developer


« Reply #3 - Posted 2008-08-21 04:48:20 »

Well the BMP heightmaps didn't work out so spectacularly. There are spaces between each tile and the heights are all wrong. I loved RAW heightmaps, but was never able to cut them up. Let me show you what progress I have made, and perhaps you can tell me if you see something wrong.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
package heightmapsplitter;

import com.jmex.terrain.util.RawHeightMap;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;

/**
 *
 * @author Tyler Trussell
 */

public class HeightMapSplitterTest
{
    public static void main(String args[]) throws FileNotFoundException, IOException
    {
        int oldSize = 512;
        int newSize = 64;
       
        String originalName = "mymap.raw";
        String fileName = "output/";
       
        int startX = 0;
        int startY = 0;
       
        int numMaps = oldSize / newSize;
       
        RawHeightMap oldMap;
        int[] oldMapData;
       
        oldMap = new RawHeightMap(HeightMapSplitterTest.class.getClassLoader().getResource(originalName), oldSize + 1, RawHeightMap.FORMAT_16BITLE, false);
        oldMapData = oldMap.getHeightMap();
       
       
        for(int i=0; i<numMaps; i++) //x
        {
            for(int n=0; n<numMaps; n++) //y
            {
                int[] newMap = new int[newSize * newSize];
                for (int x = 0; x < newSize; x++)
                {
                    for (int y = 0; y < newSize; y++)
                    {
                        newMap[y * newSize + x] = oldMapData[(n + y) * oldSize + (i + x)];
                    }
                }
                for(int r=0; r<newMap.length; r++)
                    System.out.print(newMap[i] + " ");
                System.out.println();
                FyrestoneMap map = new FyrestoneMap(newMap);
                map.save(fileName + (i+startX) + "," + (n+startY) + ".raw");
            }
        }
       
    }
}


But the heightmap files never work out.

I am a noob attempting to make a video game.
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 840
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #4 - Posted 2008-08-21 05:59:29 »

I see this:
"oldSize + 1"

that basically says that your old heightmap has a dimension of 513, right? (to render 512x512 tiles you need 513x513 heightvalues)

Further, you seemed to have misinterpreted my code. the X and Y are the cell offset, not the tile offset.




PLEASE use method-calls... as the above is hardly maintainable.
To take this into account in your own code:
1  
sub(oldMapData, oldSize+1, i*newSize, n*newSize, newSize+1, newSize+1);


Imagine to write this without the method-call, and things get very messy.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Offline Trussell

Junior Devvie




Game Developer


« Reply #5 - Posted 2008-08-21 06:14:25 »

I've always seen it as an array of integers... I guess it doesn't really matter since it's independent of the Game Engine.

Is there a header for a 16-bit LE RAW heightmap, or is it literally just an array of integers / shorts?

I am a noob attempting to make a video game.
Offline cylab

JGO Ninja


Medals: 55



« Reply #6 - Posted 2008-08-21 07:49:16 »

You may be interested in L3DT (http://www.bundysoft.com/L3DT/) which is able to export tilemaps out of the box (it's called mosaik map there)

Mathias - I Know What [you] Did Last Summer!
Offline Trussell

Junior Devvie




Game Developer


« Reply #7 - Posted 2008-08-21 18:09:23 »

From the gallery, that looks like a program designed for high-quality renderings (like TerraGen)... ATM I am unable to test the editor. Does it have an interface designed for level-building (i.e. you can see the terrain, rendered, while you build it, supports texturing and alphamaps, etc)?

I am a noob attempting to make a video game.
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 840
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #8 - Posted 2008-08-21 18:35:37 »

RAW does not have a header.



So.... what is the file size?
512x512x2 bytes or 513x513x2 bytes ?


Does rendering work with the non-splitted-data?



As you didn't really respond to my comment about how you misinterpretated the code-sample, I fear you might still be using it wrong. Your last provided code will behave like getting 'random' samples from the big map: very spiky, as you noticed.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Offline Trussell

Junior Devvie




Game Developer


« Reply #9 - Posted 2008-08-21 19:28:55 »

I crashed my development machine, so I am unable to get to my projects folder and edit the code at the moment, which is the reason I haven't responded to anything. I'm not sure about the file size... I know that it's an array of integers with a size of mapSize * mapSize... Other than that I'm not really an expert on the subject.

I am a noob attempting to make a video game.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Trussell

Junior Devvie




Game Developer


« Reply #10 - Posted 2008-08-24 18:22:28 »

wait so if it doesnt' have a file size couldn't I just use an ObjectOutputStream to output an array of integers and name it ".raw" and it would work?

I am a noob attempting to make a video game.
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 840
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #11 - Posted 2008-08-24 18:39:23 »

Say what?


I just ask you the file size because i want to know the grid dimensions.
The dimensions are used in the calculations to split up the map.


But how that relates to an ObjectOutputStream...?

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Offline Trussell

Junior Devvie




Game Developer


« Reply #12 - Posted 2008-08-24 18:53:53 »

I was responding to the "RAW does not have a header." If it doesn't have a header, then all I have to do is write an array of integers to a file using ObjectOutputStream, and I have a RAW file... is that correct?

I am a noob attempting to make a video game.
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 840
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #13 - Posted 2008-08-24 20:08:20 »

Yup, but then I'd advice DataOutputStream

However, these classes write ints and shorts in BigEndian, while you probably have LittleEndian byte order in your original RAW files.

Writing your own LittleEndianDataOutputStream is trivial, ofcourse.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Offline erikd

JGO Ninja


Medals: 16
Projects: 4
Exp: 14 years


Maximumisness


« Reply #14 - Posted 2008-08-24 20:54:20 »

IIRC using an ObjectOutputStream to write a RAW file won't work because it will write more than just the int values (i.e. it will have headers).
For the rest, do as Riven says: use DataOutputStream and be aware of potential endianness issues.

Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 840
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #15 - Posted 2008-08-24 21:17:52 »

AFAIK ObjectOutputStream has headers after writeObject has been invoked for the first time, but I might need to check the sourcecode...

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Offline cylab

JGO Ninja


Medals: 55



« Reply #16 - Posted 2008-08-24 22:48:32 »

Normally I abuse MemoryCacheImageInputStream to read raw data.

From the gallery, that looks like a program designed for high-quality renderings (like TerraGen)... ATM I am unable to test the editor. Does it have an interface designed for level-building (i.e. you can see the terrain, rendered, while you build it, supports texturing and alphamaps, etc)?

It's a terrain generator, not a real editor. In the editor you can "paint" a coarse design map from which the generator generates high detail height-, texture-, alpha-, light-, normal-, water- and attribute-maps. You can also regenerate parts or aspects of the terrain after you edit some details in the dataset or generation configuration.

Although there is a 3D component to view the generated terrain in realtime and adjust the heightmap, it is not an interactive editor to build a level and the generation can take up to multiple hours depending on the terrain size (1024+1024 should be pretty quick, though).

Just try it out if it suits your need.

Btw. If you want to use L3DTs own heightmap format, you can use http://xith3d.svn.sourceforge.net/viewvc/xith3d/trunk/src/org/xith3d/terrain/HF2Map.java?view=markup, it also contains code to read from raw files.

Mathias - I Know What [you] Did Last Summer!
Offline Trussell

Junior Devvie




Game Developer


« Reply #17 - Posted 2008-08-24 23:22:58 »

I tried L3DT but it wasn't suitable for my needs, but thank you very much for the recommendation!

As for the DataOutputStream and creating my own, I don't even know the difference between Little/Big Endian (but you are right--the original heightmaps ARE LE, I only know this because I tried both BE and LE on my importer and LE worked).

If you could describe to me the differences between BE and LE so I could get started writing my output stream, it would be much appreciated.

I am a noob attempting to make a video game.
Offline Wildern

Junior Devvie





« Reply #18 - Posted 2008-08-25 00:25:31 »

If you could describe to me the differences between BE and LE so I could get started writing my output stream, it would be much appreciated.

Take a look here.
Offline Trussell

Junior Devvie




Game Developer


« Reply #19 - Posted 2008-08-25 00:26:47 »

Thanks very much!

I am a noob attempting to make a video game.
Offline Trussell

Junior Devvie




Game Developer


« Reply #20 - Posted 2008-08-25 00:32:29 »

That was very enlightening but doesn't help me understand how to write integers in Little-Endian format... seems like that has more to do with memory, etc.

What would be the difference in writing in Little Endian vs. Big Endian when I'm writing specifically in this context?

I am a noob attempting to make a video game.
Offline Wildern

Junior Devvie





« Reply #21 - Posted 2008-08-25 02:16:19 »

I think it would be something similar to this.
Basically, you are shifting the bytes off the end of the in-memory number and isolating them one at a time so you can store them in reverse order.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
static const int bytesInInteger = 4;
static const int bytesInLong = 8;

void outputAsLittleEndian(int bigEndianInt) {
    byte[] bytes = new bytes[bytesInInteger ];
    for (int i = 0 ; i < bytesInInteger ; i++) {
        bytes[i] = (bigEndianInt >> ((i & 7) << 3)) & 0xFF;
    }
    for (i = 0 ; i < bytesInInteger ; i++) {
        System.out.println(bytes[i]);
    }

void outputAsLittleEndian(long bigEndianLong) {
    byte[] bytes = new bytes[bytesInLong ];
    for (int i = 0 ; i < bytesInLong ; i++) {
        bytes[i] = (bigEndianLong >> ((i & 7) << 3)) & 0xFF;
    }
    for (i = 0 ; i < bytesInLong ; i++) {
        System.out.println(bytes[i]);
    }
}
Offline Trussell

Junior Devvie




Game Developer


« Reply #22 - Posted 2008-08-26 06:11:00 »

I think I may solve this in a way very specific to what I am doing... I could do an ObjectOutputStream for the height data stored in an array of Integers and that would plug in directly with jME's RawHeightMap class... somehow.

I am a noob attempting to make a video game.
Offline erikd

JGO Ninja


Medals: 16
Projects: 4
Exp: 14 years


Maximumisness


« Reply #23 - Posted 2008-08-27 19:34:24 »

I just checked, using ObjectOutputStream will not work to write a RAW file.

There's something below that should work for you for writing an array of ints. Written for clarity: I'm not claiming it's the bestest & fastest way but it should work fine and it should illustrate endianness. Check the output in a hex editor:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
...
        // does not work, will have a header:
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("oos.obj")));
        oos.writeInt(1);
        oos.writeInt(2);
        oos.writeInt(3);
        oos.writeInt(4);
        oos.close();
       
        // below works:
        FileOutputStream fos;
        int[] i = {1,2,3,4};

        // 32bit little endian:
        fos = new FileOutputStream(new File("myints32le.dat"));
        writeLE(i, fos);
        fos.close();

        // 32bit big endian:
        fos = new FileOutputStream(new File("myints32be.dat"));
        writeBE(i, fos);
        fos.close();

        // 16bit little endian:
        fos = new FileOutputStream(new File("myints16le.dat"));
        writeLE16(i, fos);
        fos.close();

        // 16bit big endian:
        fos = new FileOutputStream(new File("myints16be.dat"));
        writeBE16(i, fos);
        fos.close();


...

    private void writeLE(int[] values, OutputStream os) throws IOException {
        for (int i : values) {
            os.write(i & 0xff);
            os.write((i >> 8) & 0xff);
            os.write((i >> 16) & 0xff);
            os.write((i >>> 24) & 0xff);
        }
    }

    private void writeBE(int[] values, OutputStream os) throws IOException {
        for (int i : values) {
            os.write((i >>> 24) & 0xff);
            os.write((i >> 16) & 0xff);
            os.write((i >> 8) & 0xff);
            os.write(i & 0xff);
        }
    }
   
    private void writeLE16(int[] values, OutputStream os) throws IOException {
        for (int i : values) {
            os.write(i & 0xff);
            os.write((i >> 8) & 0xff);
        }
    }

    private void writeBE16(int[] values, OutputStream os) throws IOException {
        for (int i : values) {
            os.write((i >> 8) & 0xff);
            os.write(i & 0xff);
        }
    }



Offline cylab

JGO Ninja


Medals: 55



« Reply #24 - Posted 2008-08-27 20:30:08 »

You can use ImageOutputStream implementations (like e.g FileImageOutputStream) and use the setByteOrder() method to set the endianness.

Mathias - I Know What [you] Did Last Summer!
Offline Trussell

Junior Devvie




Game Developer


« Reply #25 - Posted 2008-08-28 04:42:54 »

So if I have the height values stored as int[] can I just do fileImageOutputStream.write(int[]), or will that store it in a more complicated way?

I am a noob attempting to make a video game.
Offline cylab

JGO Ninja


Medals: 55



« Reply #26 - Posted 2008-08-28 07:33:12 »

You can use writeInts(int[] i, int off, int len) for this.

Mathias - I Know What [you] Did Last Summer!
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 840
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #27 - Posted 2008-08-29 18:10:26 »

erikd gave you the code, what else do you need

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

rwatson462 (30 views)
2014-12-15 09:26:44

Mr.CodeIt (20 views)
2014-12-14 19:50:38

BurntPizza (42 views)
2014-12-09 22:41:13

BurntPizza (76 views)
2014-12-08 04:46:31

JscottyBieshaar (37 views)
2014-12-05 12:39:02

SHC (50 views)
2014-12-03 16:27:13

CopyableCougar4 (48 views)
2014-11-29 21:32:03

toopeicgaming1999 (114 views)
2014-11-26 15:22:04

toopeicgaming1999 (102 views)
2014-11-26 15:20:36

toopeicgaming1999 (30 views)
2014-11-26 15:20:08
Resources for WIP games
by kpars
2014-12-18 10:26:14

Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!