Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
quadsquare.cpp
Go to the documentation of this file.
1 
12 #include <stdio.h>
13 #include <float.h>
14 #include <math.h>
15 #include <assert.h>
16 #include "quadsquare.h"
17 #include "gfxlib.h"
18 #include "aux_texture.h"
19 using std::vector;
20 
21 unsigned int*quadsquare::VertexAllocated;
22 unsigned int*quadsquare::VertexCount;
23 GFXVertexList*quadsquare:: vertices;
24 GFXVertexList*quadsquare:: blendVertices = NULL;
25 std::vector< TextureIndex >quadsquare::indices;
26 std::vector< unsigned int >*quadsquare::unusedvertices;
27 IdentityTransform*quadsquare::nonlinear_trans;
28 std::vector< TerrainTexture >*quadsquare::textures;
29 Vector quadsquare:: normalscale;
30 Vector quadsquare:: camerapos;
31 quadsquare*quadsquare::neighbor[4] = {NULL, NULL, NULL, NULL};
32 
33 unsigned int quadsquare::SetVertices( GFXVertex *vertexs, const quadcornerdata &pcd )
34 {
35  unsigned int half = 1<<pcd.Level;
36  Vector v[5];
37  v[0].i = pcd.xorg+half;
38  v[0].k = pcd.zorg+half;
39  v[1].i = pcd.xorg+half*2;
40  v[1].k = pcd.zorg+half;
41  v[2].i = pcd.xorg+half;
42  v[2].k = pcd.zorg;
43  v[3].i = pcd.xorg;
44  v[3].k = pcd.zorg+half;
45  v[4].i = pcd.xorg+half;
46  v[4].k = pcd.zorg+half*2;
47  for (unsigned int i = 0; i < 5; i++) {
48  v[i].j = Vertex[i].Y;
49  vertexs[Vertex[i].vertindex].SetTexCoord( nonlinear_trans->TransformS( v[i].i,
50  (*textures)[Vertex[i].GetTex()].scales ),
51  nonlinear_trans->TransformT( v[i].k, (*textures)[Vertex[i].GetTex()].scalet ) );
52  vertexs[Vertex[i].vertindex].SetVertex( nonlinear_trans->Transform( v[i].Cast() ).Cast() );
53  //if (vertexs[Vertex[i].vertindex].y>10000||vertexs[Vertex[i].vertindex].z>32768||vertexs[Vertex[i].vertindex].x>32768)
54  //not important...debug only to catch certain case VSFileSystem::Fprintf (stderr,"high %f", vertexs[Vertex[i].vertindex].y);
55  }
56  return half;
57 }
58 
59 //Verts mapping:
60 //1-0
61 //| |
62 //2-3
63 //
64 //Vertex mapping:
65 //+-2-+
66 //| | |
67 //3-0-1
68 //| | |
69 //+-4-+
70 static void InterpolateTextures( VertInfo res[5], VertInfo in[4], const quadcornerdata &cd )
71 {
72  //const float epsilon;
73  res[0].SetTex( 0.25*( ( ( (float) in[0].Rem )+in[1].Rem+in[2].Rem+in[3].Rem )/256.+in[0].Tex+in[1].Tex+in[2].Tex+in[3].Tex ) );
74  res[1].SetTex( 0.5*( ( ( (float) in[0].Rem )+in[3].Rem )/256.+(in[3].Tex)+in[0].Tex ) );
75  res[2].SetTex( 0.5*( ( ( (float) in[0].Rem )+in[1].Rem )/256.+(in[0].Tex)+in[1].Tex ) );
76  res[3].SetTex( 0.5*( ( ( (float) in[1].Rem )+in[2].Rem )/256.+(in[1].Tex)+in[2].Tex ) );
77  res[4].SetTex( 0.5*( ( ( (float) in[2].Rem )+in[3].Rem )/256.+(in[2].Tex)+in[3].Tex ) );
78  /*
79  * float pos[5];
80  * int half = 1<< cd.Level;
81  * pos[0] = (cd.xorg + half+ cd.zorg + half);
82  * pos[1] = (cd.xorg + half*2+ cd.zorg + half);
83  * pos[2] = (cd.xorg + half+ cd.zorg);
84  * pos[3] = (cd.xorg+ cd.zorg + half);
85  * pos[4] = (cd.xorg + half+ cd.zorg + half*2);
86  *
87  *
88  * for (int i = 0; i < 5; i++) {
89  *
90  * res[i].SetTex(((int)((pos[i])/5000))%10);
91  * }
92  */
93  res[0].Y = (unsigned short) ( 0.25*( ( (float) in[0].Y )+in[1].Y+in[2].Y+in[3].Y ) );
94  res[1].Y = (unsigned short) ( 0.5*( ( (float) in[3].Y )+in[0].Y ) );
95  res[2].Y = (unsigned short) ( 0.5*( ( (float) in[0].Y )+in[1].Y ) );
96  res[3].Y = (unsigned short) ( 0.5*( ( (float) in[1].Y )+in[2].Y ) );
97  res[4].Y = (unsigned short) ( 0.5*( ( (float) in[2].Y )+in[3].Y ) );
98 }
99 
101 {
102  pcd->Square = this;
103  //Set static to true if/when this node contains real data, and
104  //not just interpolated values. When static == false, a node
105  //can be deleted by the Update() function if none of its
106  //vertices or children are enabled.
107  Static = false;
108  int i;
109  for (i = 0; i < 4; i++)
110  Child[i] = NULL;
111  EnabledFlags = 0;
112  for (i = 0; i < 2; i++)
113  SubEnabledCount[i] = 0;
114  //Set default vertex positions by interpolating from given corners.
115  //Just bilinear interpolation.
116  InterpolateTextures( Vertex, pcd->Verts, *pcd );
117  for (i = 0; i < 2; i++)
118  Error[i] = 0;
119  for (i = 0; i < 4; i++)
120  Error[i
121  +2] =
122  (unsigned short) (fabs( (double) ( (Vertex[0].Y
123  +pcd->Verts[i].Y)-(Vertex[i+1].Y+Vertex[( (i+1)&3 )+1].Y) ) )*0.25);
124  //Compute MinY/MaxY based on corner verts.
125  MinY = MaxY = (unsigned short) pcd->Verts[0].Y;
126  for (i = 1; i < 4; i++) {
127  float y = pcd->Verts[i].Y;
128  if (y < MinY) MinY = (unsigned short) y;
129  if (y > MaxY) MaxY = (unsigned short) y;
130  }
131  GFXVertex **vertexs = &(vertices->BeginMutate( 0 )->vertices);
132  GFXVertex v[5];
133  v[0].SetNormal( ( (*vertexs)[pcd->Verts[0].vertindex].GetNormal()+(*vertexs)[pcd->Verts[1].vertindex].GetNormal()
134  +(*vertexs)[pcd->Verts[2].vertindex].GetNormal()
135  +(*vertexs)[pcd->Verts[3].vertindex].GetNormal() ).Normalize() );
136  v[1].SetNormal(
137  ( (*vertexs)[pcd->Verts[0].vertindex].GetNormal()+(*vertexs)[pcd->Verts[3].vertindex].GetNormal() ).Normalize() );
138  v[2].SetNormal(
139  ( (*vertexs)[pcd->Verts[0].vertindex].GetNormal()+(*vertexs)[pcd->Verts[1].vertindex].GetNormal() ).Normalize() );
140  v[3].SetNormal(
141  ( (*vertexs)[pcd->Verts[1].vertindex].GetNormal()+(*vertexs)[pcd->Verts[2].vertindex].GetNormal() ).Normalize() );
142  v[4].SetNormal(
143  ( (*vertexs)[pcd->Verts[2].vertindex].GetNormal()+(*vertexs)[pcd->Verts[3].vertindex].GetNormal() ).Normalize() );
144  //FIXME fill in st!
145  for (i = 0; i < 5; i++) {
146  //v[i].y= Vertex[i].Y;
147  if ( unusedvertices->size() ) {
148  (*vertexs)[unusedvertices->back()] = v[i];
149  Vertex[i].vertindex = unusedvertices->back();
150  unusedvertices->pop_back();
151  } else {
152  Vertex[i].vertindex = *VertexCount;
153  if ( (*VertexCount)+1 >= (*VertexAllocated) ) {
154  (*VertexAllocated) *= 2;
155  (*vertexs) = (GFXVertex*) realloc( (*vertexs), (*VertexAllocated)*sizeof (GFXVertex) );
156  }
157  (*vertexs)[*VertexCount] = v[i];
158  (*VertexCount)++;
159  }
160  }
161  SetVertices( *vertexs, *pcd );
162  vertices->EndMutate( *VertexCount );
163  //interpolate from other vertices;
164 }
165 
167 {
168  //Recursively delete sub-trees.
169  int i;
170  for (i = 0; i < 5; i++)
171  unusedvertices->push_back( Vertex[i].vertindex );
172  for (i = 0; i < 4; i++) {
173  if (Child[i]) delete Child[i];
174  Child[i] = NULL;
175  }
176 }
177 
183 void quadsquare::SetStatic( const quadcornerdata &cd )
184 {
185  if (Static == false) {
186  Static = true;
187  //Propagate static status to ancestor nodes.
188  if (cd.Parent && cd.Parent->Square)
189  cd.Parent->Square->SetStatic( *cd.Parent );
190  }
191 }
192 
194 {
195 //Debugging function. Counts the number of nodes in this subtree.
196  int count = 1; //Count ourself.
197  //Count descendants.
198  for (int i = 0; i < 4; i++)
199  if (Child[i]) count += Child[i]->CountNodes();
200  return count;
201 }
202 
207 float quadsquare::GetHeight( const quadcornerdata &cd, float x, float z, Vector &normal ) //const
208 {
209  int half = 1<<cd.Level;
210  float lx = (x-cd.xorg)/float(half);
211  float lz = (z-cd.zorg)/float(half);
212  int ix = (int) floor( lx );
213  int iz = (int) floor( lz );
214  //Clamp.
215  if (ix < 0) return -FLT_MAX; //ix = 0;
216  if (ix > 1) return -FLT_MAX; //ix = 1;
217  if (iz < 0) return -FLT_MAX; //iz = 0;
218  if (iz > 1) return -FLT_MAX;
219 
220  int index = ix^(iz^1)+(iz<<1); //FIXME gcc computes ix^((iz^1)+(iz<<1)).. Was this the intent? Who can understand this code?
221  if (Child[index] && Child[index]->Static) {
222  //Pass the query down to the child which contains it.
224  SetupCornerData( &q, cd, index );
225  return Child[index]->GetHeight( q, x, z, normal );
226  }
227  //Bilinear interpolation.
228  lx -= ix;
229  if (lx < 0) lx = 0;
230  if (lx > 1) lx = 1;
231  lz -= iz;
232  if (lx < 0) lz = 0; //FIXME did this mean to say "if (lz < 0) lz = 0;" ? It says "if (lx..."
233  if (lz > 1) lz = 1;
234  float s00, s01, s10, s11;
235  switch (index)
236  {
237  default:
238  case 0:
239  s00 = Vertex[2].Y;
240  s01 = cd.Verts[0].Y;
241  s10 = Vertex[0].Y;
242  s11 = Vertex[1].Y;
243  break;
244  case 1:
245  s00 = cd.Verts[1].Y;
246  s01 = Vertex[2].Y;
247  s10 = Vertex[3].Y;
248  s11 = Vertex[0].Y;
249  break;
250  case 2:
251  s00 = Vertex[3].Y;
252  s01 = Vertex[0].Y;
253  s10 = cd.Verts[2].Y;
254  s11 = Vertex[4].Y;
255  break;
256  case 3:
257  s00 = Vertex[0].Y;
258  s01 = Vertex[1].Y;
259  s10 = Vertex[4].Y;
260  s11 = cd.Verts[3].Y;
261  break;
262  }
263  normal = ( Vector( 0, s10-s00, half ) ).Cross( Vector( half, s01-s00, 0 ) );
264  return (s00*(1-lx)+s01*lx)*(1-lz)+(s10*(1-lx)+s11*lx)*lz;
265 }
266 
267 quadsquare* quadsquare::GetFarNeighbor( int dir, const quadcornerdata &cd ) const
268 {
269 //Traverses the tree in search of the quadsquare neighboring this square to the
270 //specified direction. 0-3 --> { E, N, W, S }.
271 //Returns NULL if the neighbor is outside the bounds of the tree.
272  //If we don't have a parent, then we don't have a neighbor.
273  //(Actually, we could have inter-tree connectivity at this level
274  //for connecting separate trees together.)
275  if (cd.Parent == 0)
276  return neighbor[dir];
277  //Find the parent and the child-index of the square we want to locate or create.
278  quadsquare *p = 0;
279  int index = cd.ChildIndex^1^( (dir&1)<<1 );
280  bool SameParent = ( (dir-cd.ChildIndex)&2 ) ? true : false;
281  if (SameParent) {
282  p = cd.Parent->Square;
283  } else {
284  p = cd.Parent->Square->GetFarNeighbor( dir, *cd.Parent );
285  if (p == 0) return 0;
286  }
287  quadsquare *n = p->Child[index];
288  return n;
289 }
290 
291 quadsquare* quadsquare::GetNeighbor( int dir, const quadcornerdata &cd ) const
292 {
293 //Traverses the tree in search of the quadsquare neighboring this square to the
294 //specified direction. 0-3 --> { E, N, W, S }.
295 //Returns NULL if the neighbor is outside the bounds of the tree.
296  //If we don't have a parent, then we don't have a neighbor.
297  //(Actually, we could have inter-tree connectivity at this level
298  //for connecting separate trees together.)
299  if (cd.Parent == 0) return NULL;
300  //Find the parent and the child-index of the square we want to locate or create.
301  quadsquare *p = 0;
302  int index = cd.ChildIndex^1^( (dir&1)<<1 );
303  bool SameParent = ( (dir-cd.ChildIndex)&2 ) ? true : false;
304  if (SameParent) {
305  p = cd.Parent->Square;
306  } else {
307  p = cd.Parent->Square->GetNeighbor( dir, *cd.Parent );
308  if (p == 0) return 0;
309  }
310  quadsquare *n = p->Child[index];
311  return n;
312 }
313 
314 void VertInfo::SetTex( float t )
315 {
316  Tex = (unsigned char) t;
317  Rem = (unsigned char) ( (t-Tex)*256 );
318  /*
319  * if (Rem==127||Rem==126||Rem==125)
320  * Rem = 128;
321  */
322  assert( t-Tex < 1 );
323 }
324 
325 void quadsquare::SetCurrentTerrain( unsigned int *VertexAllocated,
326  unsigned int *VertexCount,
327  GFXVertexList *vertices,
328  std::vector< unsigned int > *unvert,
329  IdentityTransform *nlt,
330  std::vector< TerrainTexture > *tex,
331  const Vector &NormScale,
332  quadsquare *neighbors[4] )
333 {
334  normalscale = NormScale;
335  neighbor[0] = neighbors[0];
336  neighbor[1] = neighbors[1];
337  neighbor[2] = neighbors[2];
338  neighbor[3] = neighbors[3];
339  if (quadsquare::blendVertices == NULL) {
340  GFXColorVertex tmp[3];
341  blendVertices = new GFXVertexList( GFXTRI, 3, tmp, 3, true );
342  }
343  quadsquare::VertexAllocated = VertexAllocated;
344  quadsquare::VertexCount = VertexCount;
345  quadsquare::vertices = vertices;
346  quadsquare::unusedvertices = unvert;
347  nonlinear_trans = nlt;
348  textures = tex;
349  if ( indices.size() < tex->size() )
350  while ( indices.size() < tex->size() )
351  indices.push_back( TextureIndex() );
352 }
353 
354 static unsigned char texturelookup[256];
355 
357 {
358  unsigned int i;
359  memset( texturelookup, 0, sizeof (unsigned char)*256 );
360  for (i = 0; i < textures->size(); i++)
361  texturelookup[(*textures)[i].color] = i;
362  AddHeightMapAux( cd, hm );
363 }
364 
366 {
367 //Sets the height of all samples within the specified rectangular
368 //region using the given array of floats. Extends the tree to the
369 //level of detail defined by (1 << hm.Scale) as necessary.
370  //If block is outside rectangle, then don't bother.
371  int BlockSize = 2<<cd.Level;
372  if ( cd.xorg > hm.XOrigin+( (int) (hm.XSize+2)<<hm.Scale )
373  || cd.xorg+BlockSize < hm.XOrigin-(1<<hm.Scale)
374  || cd.zorg > hm.ZOrigin+( (int) (hm.ZSize+2)<<hm.Scale )
375  || cd.zorg+BlockSize < hm.ZOrigin-(1<<hm.Scale) )
376  //This square does not touch the given height array area; no need to modify this square or descendants.
377  return;
378  if (cd.Parent && cd.Parent->Square)
379  cd.Parent->Square->EnableChild( cd.ChildIndex, *cd.Parent ); //causes parent edge verts to be enabled, possibly causing neighbor blocks to be created.
380  int i;
381  int half = 1<<cd.Level;
382  //Create and update child nodes.
383  for (i = 0; i < 4; i++) {
385  SetupCornerData( &q, cd, i );
386  if (Child[i] == NULL && cd.Level > hm.Scale)
387  //Create child node w/ current (unmodified) values for corner verts.
388  Child[i] = new quadsquare( &q );
389  //Recurse.
390  if (Child[i])
391  Child[i]->AddHeightMapAux( q, hm );
392  }
393  //don't want to bother changing things if the sample won't change things :-)
394  int s[5];
395  float texture[5];
396  s[0] = (int) hm.Sample( cd.xorg+half, cd.zorg+half, texture[0] );
397  s[1] = (int) hm.Sample( cd.xorg+half*2, cd.zorg+half, texture[1] );
398  s[2] = (int) hm.Sample( cd.xorg+half, cd.zorg, texture[2] );
399  s[3] = (int) hm.Sample( cd.xorg, cd.zorg+half, texture[3] );
400  s[4] = (int) hm.Sample( cd.xorg+half, cd.zorg+half*2, texture[4] );
401  //Modify the vertex heights if necessary, and set the dirty
402  //flag if any modifications occur, so that we know we need to
403  //recompute error data later.
404  /*
405  * float pos[5];
406  * pos[0] = (cd.xorg + half+ cd.zorg + half);
407  * pos[1] = (cd.xorg + half*2+ cd.zorg + half);
408  * pos[2] = (cd.xorg + half+ cd.zorg);
409  * pos[3] = (cd.xorg+ cd.zorg + half);
410  * pos[4] = (cd.xorg + half+ cd.zorg + half*2);
411  *
412  */
413  for (i = 0; i < 5; i++) {
414  //Vertex[i].SetTex(((int)((pos[i])/5000))%10);
415  Vertex[i].SetTex( texture[i] );
416  if (s[i] != 0) {
417  Dirty = true;
418  if (Vertex[i].Y+s[i] > 0)
419  Vertex[i].Y += s[i];
420  else
421  Vertex[i].Y = 0;
422  //vertices[Vertex[i].vertindex].x = v[i].i;//FIXME are we necessary?
423  //vertices[Vertex[i].vertindex].z = v[i].k;
424  }
425  }
426  if (Dirty) {
427  GFXVertex *vertexs = vertices->BeginMutate( 0 )->vertices;
428  SetVertices( vertexs, cd );
429  vertices->EndMutate();
430  } else {
431  //Check to see if any child nodes are dirty, and set the dirty flag if so.
432  for (i = 0; i < 4; i++)
433  if (Child[i] && Child[i]->Dirty) {
434  Dirty = true;
435  break;
436  }
437  }
438  if (Dirty) SetStatic( cd );
439 }
440 
441 //
442 //HeightMapInfo
443 //
444 
445 float HeightMapInfo::Sample( int x, int z, float &texture ) const
446 //Returns the height (y-value) of a point in this heightmap. The given (x,z) are in
447 //world coordinates. Heights outside this heightmap are considered to be 0. Heights
448 //between sample points are bilinearly interpolated from surrounding points.
449 //xxx deal with edges: either force to 0 or over-size the query region....
450 {
451  //Break coordinates into grid-relative coords (ix,iz) and remainder (rx,rz)
452  int ix = (x-XOrigin)>>Scale;
453  int iz = (z-ZOrigin)>>Scale;
454  int mask = (1<<Scale)-1;
455  int rx = (x-XOrigin)&mask;
456  int rz = (z-ZOrigin)&mask;
457  int ixpp = ix+1;
458  int izpp = iz+1;
459  if (ix < 0) {
460  ix = 0;
461  ixpp = 0;
462  }
463  if ( ix >= (int) (XSize-1) ) {
464  ix = XSize-1;
465  ixpp = XSize-1;
466  }
467  if (iz < 0) {
468  iz = 0;
469  izpp = 0;
470  }
471  if ( iz >= (int) (ZSize-1) ) {
472  iz = ZSize-1;
473  izpp = ZSize-1;
474  }
475  float fx = float(rx)/(mask+1);
476  float fz = float(rz)/(mask+1);
477  float s00 = Data[ix+iz*RowWidth];
478  float s01 = Data[(ixpp)+iz*RowWidth];
479  float s10 = Data[ix+(izpp)*RowWidth];
480  float s11 = Data[(ixpp)+(izpp)*RowWidth];
481  float t00 = texturelookup[terrainmap[ix+iz*RowWidth]];
482  float t01 = texturelookup[terrainmap[(ixpp)+iz*RowWidth]];
483  float t10 = texturelookup[terrainmap[ix+(izpp)*RowWidth]];
484  float t11 = texturelookup[terrainmap[(ixpp)+(izpp)*RowWidth]];
485  texture = (t00*(1-fx)+t01*fx)*(1-fz)
486  +(t10*(1-fx)+t11*fx)*fz;
487  return (s00*(1-fx)+s01*fx)*(1-fz)
488  +(s10*(1-fx)+s11*fx)*fz;
489 }
490