[Article] Informations to make a map reader (Vel) + sources

This is a sub forum dedicated to an open source map editor.
Don't post in it about another subject

Moderators: osRose dev team, ospRose dev team, osiRose dev team, Moderators

Forum rules
This is a sub forum dedicated to an open source map editor.
Don't post in it about another subject

[Article] Informations to make a map reader (Vel) + sources

Postby Vel on Fri Nov 07, 2008 9:24 pm

25.JPG


Fist off all.
In order to do something like this you need to know some coding language with OOP bases and off course you need to know something about OpenGL (here are some good tutorials NEHE) and GLSL.
Post your comments if you don't understand something and Ill fix an article. If you are ready lets begin :)

So how is this working? To load Rose map (only terrain) you need to know how to open *.HIM, *.TIL and *.ZON files. More information about them can be found here: http://rose.br19.com/

*.HIM
Those are just an array of height values of each terrain point and quadtree data (I don't work with it, but it shouldn't be so difficult). To understand

look at this pictures for an example of the heights array:

20208b.gif
terrain
20208b.gif (3.47 KiB) Viewed 35773 times

3.JPG
lines


I am using VBO to render my terrain, this means that all points data are sent in one big array sent in one shot into the video card. It will ensure good performance. If you have any questions about VBO, look here: http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=45

There is nothing too hard about this as you can see. So to load whole map we need to load all ".HIM" data in one array.
Something like this:
  1. void GLMegaTerrain::LoadHIMData(const char *path, int sizeX, int sizeY, int Scale)
  2. {
  3.     HIM_DATA = new float[65*65*sizeX*(sizeY)];
  4.     //array for all heights of terrain
  5.     char *temp_path = new char[255];
  6.     strcpy(temp_path, path);
  7.     strncat(temp_path, "30_30.him", 9);
  8.    //make whole path to him file
  9.  
  10.     int ofs = 0;
  11.     int l = 0;
  12.  
  13.     while(path[l] != NULL)
  14.     {
  15.         if(path[l] == '/')
  16.             ofs = l;
  17.         l++;
  18.     }
  19.    
  20.     PATH_OFFSET = 1;  //this value needs to know from what file begins map 30_30 or 31_31
  21.     int temp;                //Ofcose there are maps that begins from 32 ... so it needs to upgrade
  22.     int offset = 49;
  23.  
  24.     FILE *t;
  25.     bool close_flag = true;
  26.  
  27.     temp_path[ofs+2] = (char)(offset);
  28.     temp_path[ofs+5] = (char)(offset-1);
  29.  
  30.     if((t=fopen(temp_path,"rb"))==NULL)
  31.     {
  32.         PATH_OFFSET = 0;
  33.         //If 30_30.him existing PATH_OFFSET = 0 else PATH_OFFSET = 1
  34.         close_flag = false;
  35.     }
  36.  
  37.     if(close_flag)
  38.         fclose(t);
  39.  
  40.     int index = 0;
  41.  
  42.     for(int i=0;i<sizeX;i++)
  43.         for(int j=0;j<sizeY;j++)
  44.         {
  45.             temp_path[ofs+2] = (char)(i+offset);
  46.             temp_path[ofs+5] = (char)(j+offset-PATH_OFFSET);
  47.  
  48.             FILE *f;
  49.  
  50.             if((f=fopen(temp_path,"rb"))==NULL)
  51.             {
  52.                 cout<<"\nCannot open file: "<<temp_path<<endl;
  53.                 continue;
  54.             }  
  55.  
  56.             int width, height, unk;
  57.             float basic_float;
  58.  
  59.             fread(&width,sizeof(width),1,f);
  60.             fread(&height,sizeof(height),1,f);
  61.             fread(&unk,sizeof(unk),1,f);
  62.             fread(&basic_float,sizeof(basic_float),1,f);
  63.                
  64.             int HIM_OFFSET = (index)*65*65;
  65.            
  66.             for(int i=0;i<width*height;i++)
  67.             {
  68.                 fread(&HIM_DATA[i+HIM_OFFSET],sizeof(HIM_DATA[i+HIM_OFFSET]),1,f);
  69.  
  70.                 HIM_DATA[i + HIM_OFFSET]/=(200/ Scale);
  71.                
  72.             }
  73.                         index++;
  74.                         // quadtrees here
  75.             fclose(f);
  76.         }
  77.  }


Maybe there are some errors in code, but you got now the main idea. Just simple working with strings. After this all ".HIM" data will be saved in an array like this:

  1. {30_30,30_31,30_32,31_30,31_31,31_32...}


Then.
If you try NEHE ex.45 with VBO you can understand how it's working so let's go next.

The next step is very important.
We need to split whole map into block of 4x4 points it's the way it's connected to each other, why? This is need in texturing part of map loading. Look at this screenshot to understand what I am talking about:
4.JPG
no tex


Dark lines are borders of each 4x4 piece. So you need to place them in the right position and add the needed heights. Like this:

  1. void GLMegaTerrain::Load(char *path, int sX, int sY, int DivSize)
  2. {
  3.     strcpy(MapPath, path);
  4.  
  5.     DIV_SIZE = DivSize;
  6.     LoadHIMData(path, sX, sY, 3);//last param is terrain block scale
  7.  
  8.     SIZEX = sX*(64/DivSize);
  9.     SIZEY = sY*(64/DivSize);
  10.  
  11.         ...
  12.  
  13.     data = new GLTerrain[SIZEX*SIZEY];  // data is array of terrains 4x4 that make whole map
  14.  
  15.     int offset = 49; //offset to translate int into char
  16.  
  17.     int index = 0;
  18.  
  19.     for(int i=0;i<SIZEX;i++) //
  20.     {
  21.         for(int j=0;j<SIZEY;j++)
  22.         {                      
  23.             char *TIL_PATH = new char[255];
  24.             strcpy(TIL_PATH, path);
  25.             strncat(TIL_PATH, "31_31.til", 9);
  26.  
  27.             char *Shadow_path = new char[255];
  28.             strcpy(Shadow_path, path);
  29.             strncat(Shadow_path, "31_30/31_30_PLANELIGHTINGMAP.dds", 32);
  30.  
  31.                         //Incrase names in path
  32.             TIL_PATH[1+p_index] = (char)(int(i/(64/DivSize))+offset);
  33.             TIL_PATH[4+p_index] = (char)(int(j/(64/DivSize))+offset-PATH_OFFSET);  
  34.  
  35.             Shadow_path[1+p_index] = (char)(int(i/(64/DivSize))+offset);
  36.             Shadow_path[7+p_index] = (char)(int(i/(64/DivSize))+offset);
  37.  
  38.             Shadow_path[4+p_index] = (char)(int(j/(64/DivSize))+offset-PATH_OFFSET);
  39.             Shadow_path[10+p_index] = (char)(int(j/(64/DivSize))+offset-PATH_OFFSET);
  40.  
  41.             LoadTextures(TIL_PATH, i, j, index); //
  42.  
  43.             data[index].SHADOW_TEXTURE = TManager.LoadDDSTexture(Shadow_path);
  44.        
  45.             int gr = DivSize;
  46.             data[index].Create(j*(gr*3),i*(gr*3),gr,gr,3);
  47.                         //j*(gr*3),i*(gr*3) is x and y position of piace, gr is size
  48.             data[index].SetHeights(RetHeights(i, j), i, j, DivSize);
  49.             data[index].BuildVBOs();
  50.  
  51.             index++;
  52.         }
  53.     }
  54. }


What is data[index].SetHeights(RetHeights(i, j), i, j, DivSize); doing? It actually sets heights of 4x4 pieces.
-RetHeights(int i, int j) returns a 64x64 array of heights that is in the ".HIM", in the part for this 4x4 piace.

Very simple function:
  1. float* GLMegaTerrain::RetHeights(int i, int j)
  2. {
  3.    
  4.     int s = 65*65;
  5.     float *z = new float[s];
  6.  
  7.     int l =( int(i/(64/DIV_SIZE))* s *(SIZEY/(64/DIV_SIZE)) ) + ( ( int(j/(64/DIV_SIZE)) * s ));
  8.  
  9.     for(int i=0;i<s;i++)
  10.         z[i] = HIM_DATA[i+l];
  11.    
  12.     return z;
  13.     delete z;
  14. }


SetHeights:
  1. void GLTerrain::SetHeights(float *z, const int offsetX, const int offsetY, int size)
  2. {
  3.     int count = 0;
  4.  
  5.     int tx = offsetX;
  6.     if(tx > (64/size)-1 ) tx = tx % (64/size);
  7.    
  8.     int ty = offsetY;
  9.     if(ty > (64/size)-1 ) ty = ty % (64/size);
  10.  
  11.     for(int i=0;i<sizeX+1;i++)
  12.         for(int j=1;j<sizeY+1;j++)
  13.             AddPoint(i,j, z[(i+ty*size)*65+(j+tx*size)-1]);
  14.             //set height of  [i, j] point in current 4x4 piece
  15. }


AddPoint(i,j, z[(i+ty*size)*65+(j+tx*size)-1]) adds a height to i,j point of terrain,
[(i+ty*size)*65+(j+tx*size)-1] is just an offset to find needed heights of 4x4 piece.

So we have now the whole terrain with applied heights:
GLSLProgram.rar
(3.79 KiB) Downloaded 2700 times

3DDATA/MAPS/JUNON/JG01/

Texturing
To texture terrain I use GLSL shader, it isn't very hard to understand. I also use this code to work with shaders:
17.JPG


*.ZON info
In this file you need to read TEXTURELIST (just array of strings that are the paths of all textures used in this map) and TILELIST info.

*.TIL info
This is an array of 16x16 by 4x4 pieces texture data where tile_id matches number in TILELIST. Then base1+offset1 is number of bottom texture (number maches TEXTURELIST) and base2+offset2 top texture. Orientation is rotation of the texture.
  1. if(Orientation == 1)
  2.        data[index].TexCoordOrient = Vector2D(1,1);
  3.     else if(Orientation == 2)
  4.         data[index].TexCoordOrient = Vector2D(-1,1);
  5.     else if(Orientation == 3)
  6.         data[index].TexCoordOrient = Vector2D(1,-1);
  7.     else if(Orientation == 4)
  8.         data[index].TexCoordOrient = Vector2D(-1,-1);


It turns like this:
Orient. : 1 2 3 4
Rose Editor (for osRose).rar
Sources
(2.45 MiB) Downloaded 1524 times


So why we split whole terrain in 4x4 blocks? It is for easy texturing, I think that Rose developers did the same. I use my shader on this block and texture it with 3 textures in one time.

Now you have 2 textures of current 4x4 piece and it is time to texture it. But don't forget rotation.

Here are some main steps to run shader:
1. Init shaders
  1. void GLMegaTerrain::InitShaders()
  2. {
  3.     if(program.loadShaders("Shaders/Terrain/t1.vsh", "Shaders/Terrain/t1.fsh"))
  4.         cout<<"---Shaders loaded!---"<<endl;
  5.     else cout<<"---ERROR in loading shaders---"<<endl;
  6.        
  7.     program.bind ();
  8.    
  9.     program.setTexture( "Texture0", 0);
  10.     program.setTexture( "Texture1", 1);
  11.     program.setTexture( "Shadow", 2);
  12.  
  13.     program.unbind();
  14. }


You must call InitShaders() after you create GLMegaTerrain object (or whatever you named you terrain class).

2. Then at the render state bind/unbind program and set new textures to get performance. And also set vector of rotation and vector of shadow texture coords:

  1. GLMegaTerrain::Render()
  2. {
  3.  
  4.     program.bind();
  5.     for(int i=0;i<SIZEX*SIZEY;i++)
  6.     {
  7.  
  8.         program.setUniformVector("TexC", data[i].TexCoordOrient);
  9.         program.setUniformVector("ShaTC", data[i].ShadowOffset);
  10.         data[i].Render();
  11.     }
  12.     program.unbind();
  13. }


And shader itself. Fragment program:

  1. uniform sampler2D Texture0;
  2. uniform sampler2D Texture1;
  3. uniform sampler2D Shadow;
  4.  
  5. uniform vec2   TexC;
  6. uniform vec2   ShaTC;
  7.  
  8. varying vec2 texCoord;
  9.  
  10. varying   vec3 l;
  11. varying vec3 v;
  12. varying vec3 n;
  13.  
  14. void main(void)
  15. {
  16.    vec2 v = vec2(texCoord.x*TexC.x, texCoord.y*TexC.y);
  17.    
  18.    vec2 shv = vec2(texCoord);
  19.    
  20.    shv /= 16.0;        
  21.    shv += ShaTC;  
  22.  
  23.    vec4 a = texture2D( Texture0, v ) ;
  24.    vec4 b = texture2D( Texture1, v ) ;
  25.    
  26.    vec4 shadow = texture2D( Shadow, shv ) ;
  27.      
  28.    const vec4   diffColor = vec4 ( 0.6, 0.6, 0.6, 0.5 );
  29.  
  30.    vec3   n2   = normalize ( n );
  31.    vec3   l2   = normalize ( l );
  32.  
  33.    vec4   diff = diffColor * max ( dot ( n2, l2 ), 0.0 );  
  34.      
  35.    gl_FragColor = (dot ( n2, l2 ) *3.0 )* mix(a, b, b.a) *shadow;;  
  36. }


Vertex program:
  1. varying vec2  texCoord;
  2.  
  3. varying vec3 l;
  4. varying vec3 n;
  5. varying vec3 v;
  6.  
  7. uniform vec4    lightPos;
  8. uniform vec4    eyePos;
  9.  
  10. void main(void)
  11. {
  12.        texCoord    = gl_MultiTexCoord0.xy;
  13.  
  14.     vec3    p = vec3 ( gl_ModelViewMatrix * gl_Vertex );    // transformed point to world space
  15.  
  16.     l = normalize ( vec3 ( lightPos ) - p );                    // vector to light source
  17.     v = normalize ( vec3 ( eyePos )   - p );                    // vector to the eye
  18.     n = normalize ( gl_NormalMatrix * gl_Normal );                      // transformed n
  19.  
  20.     gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
  21. }


Optimization:
To speed up your fps you can use Quad-tree optimization as used by Rose online client. There are a lot of information about this metod in web just use google :)

Seems like this is all. Yeah this is huge article and it's hard to understand all about loading rose map from it.
You need to know many things to do that, but I hope it will help someone :) If you dont understand somehing ask and I'll try to help you.

Thaks to Imame for translation help.

ADDED:

So here are sources, I wrote them in Visual Studio 2003 so if you are using another version you can get some small errors.


Rose Editor (for osRose).rar
Sources
(2.45 MiB) Downloaded 1524 times


How to use
- Compile
- Copy Rose Etior.exe in extracted ROSE data
- Copy shaders from my project in the same catalog
- run
mouse+right button - camera move;
shift+mouse - up, down;


Rose Editor (for osRose).rar
Sources
(2.45 MiB) Downloaded 1524 times


tex.JPG
tex.JPG (3.21 KiB) Viewed 35770 times
Attachments
20208a.gif
2d array
20208a.gif (1.44 KiB) Viewed 35772 times
Last edited by Vel on Tue Mar 17, 2009 10:55 pm, edited 3 times in total.
Sorry for terrible english. My native language is C++
User avatar
Vel
Pomic
Pomic
 
Posts: 120
Joined: Mon Nov 03, 2008 9:13 am
Location: Ukraine, Kharkov.

Re: [Article] Informations to make a map reader (Vel)

Postby lmame on Wed Jan 14, 2009 11:14 pm

Ok, article splitted from main thread so it'll be better for questions :)

Nice article ;)
The world is full of love and peace ^_^
Image
User avatar
lmame
Admin
Admin
 
Posts: 8997
Joined: Mon Aug 06, 2007 4:42 pm
Location: July City

Re: [Article] Informations to make a map reader (Vel)

Postby Vel on Wed Jan 14, 2009 11:15 pm

Thanks :D
Sorry for terrible english. My native language is C++
User avatar
Vel
Pomic
Pomic
 
Posts: 120
Joined: Mon Nov 03, 2008 9:13 am
Location: Ukraine, Kharkov.

Re: [Article] Informations to make a map reader (Vel)

Postby Maxxon on Wed Jan 14, 2009 11:20 pm

wow Vel good work thanks :)
Image
an anymous comment on a program called reloader:
what if a fatal error happens, will it restart it?
User avatar
Maxxon
Hawker's pet
Hawker's pet
 
Posts: 1305
Joined: Sat Nov 10, 2007 12:42 pm

Postby kiu on Thu Jan 15, 2009 1:39 am

nice article thx Vel :mrgreen:
kiu
Pomic
Pomic
 
Posts: 130
Joined: Sat Aug 11, 2007 3:25 am

Re: [Article] Informations to make a map reader (Vel)

Postby Vel on Thu Jan 15, 2009 4:34 pm

I have a question about .him file format. What is in it after heights?
There are :
  1. BSTR unk1 ( =”quad”? )
  2. DWORD medium_squares
  3. :FOREACH( medium_squares )
  4. DWORD minZ
  5. DWORD maxZ
  6. :ENDFOR
  7. DWORD big_squares
  8. :FOREACH( big_squares )
  9. DWORD minZ
  10. DWORD maxZ
  11. :ENDFOR


Or something more?
Sorry for terrible english. My native language is C++
User avatar
Vel
Pomic
Pomic
 
Posts: 120
Joined: Mon Nov 03, 2008 9:13 am
Location: Ukraine, Kharkov.

Re: [Article] Informations to make a map reader (Vel)

Postby xadet3 on Thu Jan 15, 2009 4:59 pm

It's used for picking and culling.
xadet3
Pero pero
Pero pero
 
Posts: 727
Joined: Tue Jan 08, 2008 11:51 pm
Location: Norwich, England.

Re: [Article] Informations to make a map reader (Vel)

Postby lmame on Thu Jan 15, 2009 7:29 pm

xadet3 wrote:It's used for picking and culling.


Sounds like Stargate Atlantis to me :lol:
The world is full of love and peace ^_^
Image
User avatar
lmame
Admin
Admin
 
Posts: 8997
Joined: Mon Aug 06, 2007 4:42 pm
Location: July City

Re: [Article] Informations to make a map reader (Vel)

Postby Rescudo on Thu Jan 15, 2009 7:35 pm

Good to see you have learned from your past mistakes. Nice article :)
SEARCH - it's there for a reason!
User avatar
Rescudo
El Verloon Marshall
El Verloon Marshall
 
Posts: 872
Joined: Tue Mar 11, 2008 7:20 am

Re: [Article] Informations to make a map reader (Vel)

Postby Vel on Thu Jan 15, 2009 7:47 pm

xadet3 wrote:It's used for picking and culling.

I got it. But I want to know whole structure of .HIM file becose I want to save it correctly, I am not shure about part after heights, can you tell what next?

Rescudo
Thanks.
Sorry for terrible english. My native language is C++
User avatar
Vel
Pomic
Pomic
 
Posts: 120
Joined: Mon Nov 03, 2008 9:13 am
Location: Ukraine, Kharkov.

Next

Return to [Project] Map Editor

Who is online

Users browsing this forum: No registered users and 4 guests