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_update.cpp
Go to the documentation of this file.
1 #include "quadsquare.h"
2 int MaxCreateDepth = 0;
3 
4 void quadsquare::EnableEdgeVertex( int index, bool IncrementCount, const quadcornerdata &cd )
5 {
6 //Enable the specified edge vertex. Indices go { e, n, w, s }.
7 //Increments the appropriate reference-count if IncrementCount is true.
8  if ( ( EnabledFlags&(1<<index) ) && IncrementCount == false ) return;
9  //static const int Inc[4] = { 1, 0, 0, 8 };
10  //Turn on flag and deal with reference count.
11  EnabledFlags |= 1<<index;
12  if ( IncrementCount == true && (index == 0 || index == 3) )
13  SubEnabledCount[index&1]++;
14  //Now we need to enable the opposite edge vertex of the adjacent square (i.e. the alias vertex).
15  //This is a little tricky, since the desired neighbor node may not exist, in which
16  //case we have to create it, in order to prevent cracks. Creating it may in turn cause
17  //further edge vertices to be enabled, propagating updates through the tree.
18  //The sticking point is the quadcornerdata list, which
19  //conceptually is just a linked list of activation structures.
20  //In this function, however, we will introduce branching into
21  //the "list", making it in actuality a tree. This is all kind
22  //of obscure and hard to explain in words, but basically what
23  //it means is that our implementation has to be properly
24  //recursive.
25  //Travel upwards through the tree, looking for the parent in common with our desired neighbor.
26  //Remember the path through the tree, so we can travel down the complementary path to get to the neighbor.
27  quadsquare *p = this;
28  const quadcornerdata *pcd = &cd;
29  int ct = 0;
30  int stack[32];
31  for (;;) {
32  int ci = pcd->ChildIndex;
33  if (pcd->Parent == NULL || pcd->Parent->Square == NULL)
34  //Neighbor doesn't exist (it's outside the tree), so there's no alias vertex to enable.
35  return;
36  p = pcd->Parent->Square;
37  pcd = pcd->Parent;
38 
39  bool SameParent = ( (index-ci)&2 ) ? true : false;
40 
41  ci = ci^1^( (index&1)<<1 ); //Child index of neighbor node.
42 
43  stack[ct] = ci;
44  ct++;
45  if (SameParent) break;
46  }
47  //Get a pointer to our neighbor (create if necessary), by walking down
48  //the quadtree from our shared ancestor.
49  p = p->EnableDescendant( ct, stack, *pcd );
50  //Finally: enable the vertex on the opposite edge of our neighbor, the alias of the original vertex.
51  index ^= 2;
52  p->EnabledFlags |= (1<<index);
53  if ( IncrementCount == true && (index == 0 || index == 3) )
54  p->SubEnabledCount[index&1]++;
55 }
56 
57 quadsquare* quadsquare::EnableDescendant( int count, int path[], const quadcornerdata &cd )
58 {
59 //This function enables the descendant node 'count' generations below
60 //us, located by following the list of child indices in path[].
61 //Creates the node if necessary, and returns a pointer to it.
62  count--;
63  int ChildIndex = path[count];
64  if ( ( EnabledFlags&(16<<ChildIndex) ) == 0 )
65  EnableChild( ChildIndex, cd );
66  if (count > 0) {
68  SetupCornerData( &q, cd, ChildIndex );
69  return Child[ChildIndex]->EnableDescendant( count, path, q );
70  } else {
71  return Child[ChildIndex];
72  }
73 }
74 
75 void quadsquare::CreateChild( int index, const quadcornerdata &cd )
76 {
77 //Creates a child square at the specified index.
78  if (Child[index] == 0) {
80  SetupCornerData( &q, cd, index );
81  Child[index] = new quadsquare( &q );
82  }
83 }
84 
85 void quadsquare::EnableChild( int index, const quadcornerdata &cd )
86 {
87 //Enable the indexed child node. { ne, nw, sw, se }
88 //Causes dependent edge vertices to be enabled.
89 //if (Enabled[index + 4] == false) {
90  if ( ( EnabledFlags&(16<<index) ) == 0 ) {
91 //Enabled[index + 4] = true;
92  EnabledFlags |= (16<<index);
93  EnableEdgeVertex( index, true, cd );
94  EnableEdgeVertex( (index+1)&3, true, cd );
95  if (Child[index] == 0)
96  CreateChild( index, cd );
97  }
98 }
99 
100 void quadsquare::NotifyChildDisable( const quadcornerdata &cd, int index )
101 {
102 //Marks the indexed child quadrant as disabled. Deletes the child node
103 //if it isn't static.
104  //Clear enabled flag for the child.
105  EnabledFlags &= ~(16<<index);
106  //Update child enabled counts for the affected edge verts.
107  quadsquare *s;
108  if (index&2) s = this;
109  else s = GetFarNeighbor( 1, cd );
110  if (s)
111  s->SubEnabledCount[1]--;
112  if (index == 1 || index == 2) s = GetFarNeighbor( 2, cd );
113  else s = this;
114  if (s)
115  s->SubEnabledCount[0]--;
116  if (Child[index]->Static == false) {
117  delete Child[index];
118  Child[index] = 0;
119  }
120 }
121 
122 static float DetailThreshold = 100;
123 
124 bool VertexTest( float x, float y, float z, float error, const Vector &Viewer )
125 {
126 //Returns true if the vertex at (x,z) with the given world-space error between
127 //its interpolated location and its true location, should be enabled, given that
128 //the viewpoint is located at Viewer[].
129  float dx = fabs( x-Viewer.i );
130  float dy = fabs( y-Viewer.j );
131  float dz = fabs( z-Viewer.k );
132  float d = dx;
133  if (dy > d) d = dy;
134  if (dz > d) d = dz;
135  return (error*DetailThreshold) > d;
136 }
137 
138 bool BoxTest( float x, float z, float size, float miny, float maxy, float error, const Vector &Viewer )
139 {
140 //Returns true if any vertex within the specified box (origin at x,z,
141 //edges of length size) with the given error value could be enabled
142 //based on the given viewer location.
143  //Find the minimum distance to the box.
144  float half = size*0.5;
145  float dx = fabs( x+half-Viewer.i )-half;
146  float dy = fabs( (miny+maxy)*0.5-Viewer.j )-(maxy-miny)*0.5;
147  float dz = fabs( z+half-Viewer.k )-half;
148  float d = dx;
149  if (dy > d) d = dy;
150  if (dz > d) d = dz;
151  return (error*DetailThreshold) > d;
152 }
153 
174 static unsigned int calculatestage( unsigned int numstages, unsigned int whichstage )
175 {
176  unsigned int stage = 0;
177  int count = 0;
178  numstages -= 1;
179  while (numstages) {
180  int tmp = 1<<(whichstage%4);
181  stage += ( tmp<<( (count++)*4 ) );
182  whichstage /= 4;
183  numstages /= 4;
184  }
185  return stage;
186 }
187 
189 static unsigned int transformstage( unsigned int stage, updateparity *updateorder )
190 {
191  int tmp;
192  unsigned int transformedstage = 0;
193  while ( ( tmp = ( stage&(1|2|4|8) ) ) != 0 ) {
194  stage >>= 4;
195  transformedstage <<= 4;
196  transformedstage |= ( (*updateorder)(tmp) );
197  }
198  return transformedstage;
199 }
200 
201 int identityparity( int i )
202 {
203  return i;
204 }
205 
206 int sideparityodd( int i )
207 {
208  switch (i)
209  {
210  case 1:
211  return 2;
212 
213  case 2:
214  return 1;
215 
216  case 4:
217  return 8;
218 
219  case 8:
220  return 4;
221  }
222  return 0;
223 }
224 
225 int upparityodd( int i )
226 {
227  switch (i)
228  {
229  case 1:
230  return 4;
231 
232  case 2:
233  return 8;
234 
235  case 4:
236  return 1;
237 
238  case 8:
239  return 2;
240  }
241  return 0;
242 }
243 
244 int sideupparityodd( int i )
245 {
246  switch (i)
247  {
248  case 8:
249  return 1;
250 
251  case 4:
252  return 2;
253 
254  case 2:
255  return 4;
256 
257  case 1:
258  return 8;
259  }
260  return 0;
261 }
262 
267  const Vector &ViewerLocation,
268  float Detail,
269  unsigned short numstages,
270  unsigned short whichstage,
271  updateparity *par )
272 {
273  DetailThreshold = Detail;
274  UpdateAux( cd, ViewerLocation, 0, transformstage( calculatestage( numstages, whichstage ), par ) );
275 }
276 
277 void quadsquare::UpdateAux( const quadcornerdata &cd,
278  const Vector &ViewerLocation,
279  float CenterError,
280  unsigned int whichChildren )
281 {
282 //Does the actual work of updating enabled states and tree growing/shrinking.
283  //Make sure error values are current.
284  if (Dirty)
286  int half = 1<<cd.Level;
287  //See about enabling child verts.
288  if ( (EnabledFlags&1) == 0
289  && VertexTest( cd.xorg+(half<<1), Vertex[1].Y, cd.zorg+half, Error[0], ViewerLocation ) == true ) {
290  EnableEdgeVertex(
291  0,
292  false, cd ); //East vert.
293  }
294  if ( (EnabledFlags&8) == 0
295  && VertexTest( cd.xorg+half, Vertex[4].Y, cd.zorg+(half<<1), Error[1], ViewerLocation ) == true ) {
296  EnableEdgeVertex(
297  3,
298  false,
299  cd ); //South vert.
300  }
301  if (cd.Level > 0) {
302  if ( (EnabledFlags&32) == 0 )
303  if (BoxTest( cd.xorg, cd.zorg, half, MinY, MaxY, Error[3], ViewerLocation ) == true) EnableChild( 1, cd );
304  //nw child.er
305  if ( (EnabledFlags&16) == 0 )
306  if (BoxTest( cd.xorg+half, cd.zorg, half, MinY, MaxY, Error[2], ViewerLocation ) == true) EnableChild( 0, cd );
307  //ne child.
308  if ( (EnabledFlags&64) == 0 )
309  if (BoxTest( cd.xorg, cd.zorg+half, half, MinY, MaxY, Error[4], ViewerLocation ) == true) EnableChild( 2, cd );
310  //sw child.
311  if ( (EnabledFlags&128) == 0 )
312  if (BoxTest( cd.xorg+half, cd.zorg+half, half, MinY, MaxY, Error[5], ViewerLocation ) == true) EnableChild( 3, cd );
313  //se child.
314  //Recurse into child quadrants as necessary.
316  if (whichChildren) {
317  //if we want to mask out certain vertices for pipelined execution
318  if ( (EnabledFlags&32) && (whichChildren&0x1) ) {
319  SetupCornerData( &q, cd, 1 );
320  Child[1]->UpdateAux( q, ViewerLocation, Error[3], whichChildren>>4 );
321  }
322  if ( (EnabledFlags&16) && (whichChildren&0x2) ) {
323  SetupCornerData( &q, cd, 0 );
324  Child[0]->UpdateAux( q, ViewerLocation, Error[2], whichChildren>>4 );
325  }
326  if ( (EnabledFlags&64) && (whichChildren&0x4) ) {
327  SetupCornerData( &q, cd, 2 );
328  Child[2]->UpdateAux( q, ViewerLocation, Error[4], whichChildren>>4 );
329  }
330  if ( (EnabledFlags&128) && (whichChildren&0x8) ) {
331  SetupCornerData( &q, cd, 3 );
332  Child[3]->UpdateAux( q, ViewerLocation, Error[5], whichChildren>>4 );
333  }
334  } else {
335  //if we want to do all
336  if ( (EnabledFlags&32) ) {
337  SetupCornerData( &q, cd, 1 );
338  Child[1]->UpdateAux( q, ViewerLocation, Error[3], 0 );
339  }
340  if ( (EnabledFlags&16) ) {
341  SetupCornerData( &q, cd, 0 );
342  Child[0]->UpdateAux( q, ViewerLocation, Error[2], 0 );
343  }
344  if ( (EnabledFlags&64) ) {
345  SetupCornerData( &q, cd, 2 );
346  Child[2]->UpdateAux( q, ViewerLocation, Error[4], 0 );
347  }
348  if ( (EnabledFlags&128) ) {
349  SetupCornerData( &q, cd, 3 );
350  Child[3]->UpdateAux( q, ViewerLocation, Error[5], 0 );
351  }
352  }
353  }
354  //Test for disabling. East, South, and center.
355  if ( (EnabledFlags&1) && SubEnabledCount[0] == 0
356  && VertexTest( cd.xorg+(half<<1), Vertex[1].Y, cd.zorg+half, Error[0], ViewerLocation ) == false ) {
357  EnabledFlags &= ~1;
358  quadsquare *s = GetFarNeighbor( 0, cd );
359  if (s) s->EnabledFlags &= ~4;
360  }
361  if ( (EnabledFlags&8) && SubEnabledCount[1] == 0
362  && VertexTest( cd.xorg+half, Vertex[4].Y, cd.zorg+(half<<1), Error[1], ViewerLocation ) == false ) {
363  EnabledFlags &= ~8;
364  quadsquare *s = GetFarNeighbor( 3, cd );
365  if (s) s->EnabledFlags &= ~2;
366  }
367  if (EnabledFlags == 0
368  && cd.Parent != NULL
369  && BoxTest( cd.xorg, cd.zorg, (half<<1), MinY, MaxY, CenterError, ViewerLocation ) == false)
370  //Disable ourself.
371  cd.Parent->Square->NotifyChildDisable( *cd.Parent, cd.ChildIndex ); //nb: possibly deletes 'this'.
372 }
373 
374 inline Vector Normalise( const Vector &vec, const float scale )
375 {
376  return vec*( scale/vec.Magnitude() );
377 }
378 
379 Vector quadsquare::MakeLightness( float xslope, float zslope, const Vector &loc )
380 {
381  Vector tmp( nonlinear_trans->TransformNormal( loc.Cast(), QVector( -xslope, 1, -zslope ) ).Cast() );
382  tmp.Normalize();
383  return Vector( tmp.i*normalscale.i, tmp.j*normalscale.j, tmp.k*normalscale.k );
384 }
385 
393 {
394  int i;
395  //Measure error of center and edge vertices.
396  float maxerror = 0;
397  //Compute error of center vert.
398  float e;
399  if (cd.ChildIndex&1)
400  e = fabs( Vertex[0].Y-(cd.Verts[1].Y+cd.Verts[3].Y)*0.5 );
401  else
402  e = fabs( Vertex[0].Y-(cd.Verts[0].Y+cd.Verts[2].Y)*0.5 );
403  if (e > maxerror) maxerror = e;
404  //Initial min/max.
405  MaxY = (unsigned short) Vertex[0].Y;
406  MinY = (unsigned short) Vertex[0].Y;
407  //Check min/max of corners.
408  for (i = 0; i < 4; i++) {
409  float y = cd.Verts[i].Y;
410  if (y < MinY) MinY = (unsigned short) y;
411  if (y > MaxY) MaxY = (unsigned short) y;
412  }
413  //Edge verts.
414  e = fabs( Vertex[1].Y-(cd.Verts[0].Y+cd.Verts[3].Y)*0.5 );
415  if (e > maxerror) maxerror = e;
416  Error[0] = (unsigned short) e;
417  e = fabs( Vertex[4].Y-(cd.Verts[2].Y+cd.Verts[3].Y)*0.5 );
418  if (e > maxerror) maxerror = e;
419  Error[1] = (unsigned short) e;
420  //Min/max of edge verts.
421  for (i = 0; i < 4; i++) {
422  float y = Vertex[1+i].Y;
423  if (y < MinY) MinY = (unsigned short) y;
424  if (y > MaxY) MaxY = (unsigned short) y;
425  }
426  //Check child squares.
427  for (i = 0; i < 4; i++) {
429  if (Child[i]) {
430  SetupCornerData( &q, cd, i );
431  Error[i+2] = (unsigned short) Child[i]->RecomputeErrorAndLighting( q );
432  if (Child[i]->MinY < MinY) MinY = Child[i]->MinY;
433  if (Child[i]->MaxY > MaxY) MaxY = Child[i]->MaxY;
434  } else {
435  //Compute difference between bilinear average at child center, and diagonal edge approximation.
436  Error[i
437  +2] =
438  (unsigned short) (fabs( (double) ( (Vertex[0].Y
439  +cd.Verts[i].Y)-(Vertex[i+1].Y+Vertex[( (i+1)&3 )+1].Y) ) )*0.25);
440  }
441  if (Error[i+2] > maxerror) maxerror = Error[i+2];
442  }
443  //
444  //Compute quickie demo lighting.
445  //
446  float OneOverSize = 1.0/(2<<cd.Level);
447  GFXVertex *vertexs = vertices->BeginMutate( 0 )->vertices;
448  GFXVertex *V = &vertexs[Vertex[0].vertindex];
449  V->SetNormal( MakeLightness( (Vertex[1].Y-Vertex[3].Y)*OneOverSize,
450  (Vertex[4].Y-Vertex[2].Y)*OneOverSize,
451  V->GetConstVertex() ) );
452  float v;
453  quadsquare *s = GetFarNeighbor( 0, cd );
454  if (s)
455  v = s->Vertex[0].Y;
456  else
457  v = Vertex[1].Y;
458  V = &vertexs[Vertex[1].vertindex];
459  V->SetNormal( MakeLightness( (v-Vertex[0].Y)*OneOverSize,
460  (cd.Verts[3].Y-cd.Verts[0].Y)*OneOverSize,
461  V->GetConstVertex() ) );
462  s = GetFarNeighbor( 1, cd );
463  if (s)
464  v = s->Vertex[0].Y;
465  else
466  v = Vertex[2].Y;
467  V = &vertexs[Vertex[2].vertindex];
468  V->SetNormal( MakeLightness( (cd.Verts[0].Y-cd.Verts[1].Y)*OneOverSize,
469  (Vertex[0].Y-v)*OneOverSize,
470  V->GetConstVertex() ) );
471  s = GetFarNeighbor( 2, cd );
472  if (s)
473  v = s->Vertex[0].Y;
474  else
475  v = Vertex[3].Y;
476  V = &vertexs[Vertex[3].vertindex];
477  V->SetNormal( MakeLightness( (Vertex[0].Y-v)*OneOverSize,
478  (cd.Verts[2].Y-cd.Verts[1].Y)*OneOverSize,
479  V->GetConstVertex() ) );
480  s = GetFarNeighbor( 3, cd );
481  if (s)
482  v = s->Vertex[0].Y;
483  else
484  v = Vertex[4].Y;
485  V = &vertexs[Vertex[4].vertindex];
486  V->SetNormal( MakeLightness( (cd.Verts[3].Y-cd.Verts[2].Y)*OneOverSize,
487  (v-Vertex[0].Y)*OneOverSize,
488  V->GetConstVertex() ) );
489  vertices->EndMutate();
490  //The error, MinY/MaxY, and lighting values for this node and descendants are correct now.
491  Dirty = false;
492  return maxerror;
493 }
494