]> git.mxchange.org Git - simgear.git/blob - simgear/scene/sky/clouds3d/SkyRenderableInstanceCloud.cpp
A first attempt at making the clouds3d endian aware. Almost there.
[simgear.git] / simgear / scene / sky / clouds3d / SkyRenderableInstanceCloud.cpp
1 //------------------------------------------------------------------------------
2 // File : SkyRenderableInstanceCloud.cpp
3 //------------------------------------------------------------------------------
4 // SkyWorks : Copyright 2002 Mark J. Harris and
5 //                                              The University of North Carolina at Chapel Hill
6 //------------------------------------------------------------------------------
7 // Permission to use, copy, modify, distribute and sell this software and its 
8 // documentation for any purpose is hereby granted without fee, provided that 
9 // the above copyright notice appear in all copies and that both that copyright 
10 // notice and this permission notice appear in supporting documentation. 
11 // Binaries may be compiled with this software without any royalties or 
12 // restrictions. 
13 //
14 // The author(s) and The University of North Carolina at Chapel Hill make no 
15 // representations about the suitability of this software for any purpose. 
16 // It is provided "as is" without express or implied warranty.
17 /**
18  * @file SkyRenderableInstanceCloud.cpp
19  * 
20  * Implementation of class SkyRenderableInstanceCloud.
21  */
22 #include "SkyUtil.hpp"
23 #include "SkyCloud.hpp"
24 #include "SkyMaterial.hpp"
25 #include "SkyBoundingVolume.hpp"
26 #include "SkyRenderableInstanceCloud.hpp"
27 #include "SkyDynamicTextureManager.hpp"
28
29 //! Set this to 1 to see verbose messages about impostor updates.
30 #define SKYCLOUD_VERBOSE 0
31
32 //! Set this to control the number of frames a cloud has to be culled before its textures are released.
33 #define SKYCLOUD_CULL_RELEASE_COUNT 100
34
35 //------------------------------------------------------------------------------
36 // Static declarations.
37 //------------------------------------------------------------------------------
38 unsigned int        SkyRenderableInstanceCloud::s_iCount               = 0;
39 float               SkyRenderableInstanceCloud::s_rErrorToleranceAngle = SKYDEGREESTORADS * 0.125f;
40 SkyMaterial*        SkyRenderableInstanceCloud::s_pMaterial            = NULL;
41
42 //------------------------------------------------------------------------------
43 // Function               : SkyRenderableInstanceCloud::SkyRenderableInstanceCloud
44 // Description      : 
45 //------------------------------------------------------------------------------
46 /**
47  * @fn SkyRenderableInstanceCloud::SkyRenderableInstanceCloud(SkyCloud *pCloud, bool bUseOffScreenBuffer)
48  * @brief Constructor.
49  */ 
50 SkyRenderableInstanceCloud::SkyRenderableInstanceCloud(SkyCloud *pCloud, 
51                                                        bool bUseOffScreenBuffer /* = true */)
52 : SkyRenderableInstance(),
53   _iCloudID(-1),
54   _pCloud(pCloud),
55   _pWorldSpaceBV(NULL),
56   _rRadius(0),
57   _bScreenImpostor(false),
58   _bImageExists(false),
59   _bEnabled(true),
60   _bUseOffScreenBuffer(bUseOffScreenBuffer),
61   _bSplit(false),
62   _vecSplit(0, 0, 0),
63   _vecNearPoint(0, 0, 0),
64   _vecFarPoint(0, 0, 0), 
65   _iLogResolution(0),
66   _pBackTexture(NULL),
67   _pFrontTexture(NULL),
68   _iCulledCount(0)
69 {
70   _Initialize();
71 //   cout << "Cloud Instance created" << endl;
72 }
73
74 //------------------------------------------------------------------------------
75 // Function               : SkyRenderableInstanceCloud::SkyRenderableInstanceCloud
76 // Description      : 
77 //------------------------------------------------------------------------------
78 /**
79  * @fn SkyRenderableInstanceCloud::SkyRenderableInstanceCloud(SkyCloud *pCloud, const Vec3f &position, const Mat33f &rotation, const float scale, bool bUseOffScreenBuffer)
80  * @brief Constructor.
81  */ 
82 SkyRenderableInstanceCloud::SkyRenderableInstanceCloud(SkyCloud     *pCloud, 
83                                                        const Vec3f  &position, 
84                                                        const Mat33f &rotation, 
85                                                        const float  scale,
86                                                        bool         bUseOffScreenBuffer /* = true */)
87 : SkyRenderableInstance(position, rotation, scale),
88   _iCloudID(-1),
89   _pCloud(pCloud),
90   _pWorldSpaceBV(NULL),
91   _rRadius(0),
92   _bScreenImpostor(false),
93   _bImageExists(false),
94   _bEnabled(true),
95   _bUseOffScreenBuffer(false),
96   _bSplit(false),
97   _vecSplit(0, 0, 0),
98   _vecNearPoint(0, 0, 0),
99   _vecFarPoint(0, 0, 0), 
100   _iLogResolution(0),
101   _pBackTexture(NULL),
102   _pFrontTexture(NULL)
103 {
104   _Initialize();
105 }
106
107 //------------------------------------------------------------------------------
108 // Function               : SkyRenderableInstanceCloud::~SkyRenderableInstanceCloud
109 // Description      : 
110 //------------------------------------------------------------------------------
111 /**
112  * @fn SkyRenderableInstanceCloud::~SkyRenderableInstanceCloud()
113  * @brief Destructor
114  */ 
115 SkyRenderableInstanceCloud::~SkyRenderableInstanceCloud()
116 {
117   _pCloud = NULL;
118   SAFE_DELETE(_pWorldSpaceBV);
119
120   s_iCount--;
121   // delete the offscreen buffer when no one else is using it.
122   if (0 == s_iCount)
123   {
124 //JW??    SAFE_DELETE(s_pRenderBuffer);
125     SAFE_DELETE(s_pMaterial);
126   }
127 }
128
129
130 //------------------------------------------------------------------------------
131 // Function               : SkyRenderableInstanceCloud::SetPosition
132 // Description      : 
133 //------------------------------------------------------------------------------
134 /**
135  * @fn SkyRenderableInstanceCloud::SetPosition(const Vec3f  &position)
136  * @brief Set the world space position of the instance.
137  * 
138  * @todo <WRITE EXTENDED SkyRenderableInstanceCloud::SetPosition FUNCTION DOCUMENTATION>
139  */ 
140 void SkyRenderableInstanceCloud::SetPosition(const Vec3f  &position)
141
142   if (_pCloud)
143   {
144     _pCloud->Translate(position - _vecPosition);
145   }
146   _vecPosition = position; 
147    
148   _UpdateWorldSpaceBounds(); 
149 }
150
151
152 //------------------------------------------------------------------------------
153 // Function               : SkyRenderableInstanceCloud::SetRotation
154 // Description      : 
155 //------------------------------------------------------------------------------
156 /**
157  * @fn SkyRenderableInstanceCloud::SetRotation(const Mat33f &rotation)
158  * @brief Set the world space rotation of the instance.
159  * 
160  * @todo <WRITE EXTENDED SkyRenderableInstanceCloud::SetRotation FUNCTION DOCUMENTATION>
161  */ 
162 void SkyRenderableInstanceCloud::SetRotation(const Mat33f &rotation)
163
164   if (_pCloud)
165   {
166     _pCloud->Translate(-_vecPosition);
167     _pCloud->Rotate(_matInvRotation * rotation);
168     _pCloud->Translate(_vecPosition);
169   }
170   _matRotation    = rotation;
171   _matInvRotation = rotation; 
172   _matInvRotation.Transpose();  
173   _UpdateWorldSpaceBounds(); 
174 }
175
176
177 //------------------------------------------------------------------------------
178 // Function               : SkyRenderableInstanceCloud::SetScale
179 // Description      : 
180 //------------------------------------------------------------------------------
181 /**
182  * @fn SkyRenderableInstanceCloud::SetScale(const float  &scale)
183  * @brief Set the world space scale of the instance. 
184  */ 
185 void SkyRenderableInstanceCloud::SetScale(const float  &scale)
186
187   if (_pCloud)
188   {
189     _pCloud->Translate(-_vecPosition);
190     _pCloud->Scale(scale);
191     _pCloud->Translate(_vecPosition);
192   }
193   _rScale = scale; 
194   _UpdateWorldSpaceBounds(); 
195 }
196
197
198 //------------------------------------------------------------------------------
199 // Function               : DrawQuad
200 // Description      : 
201 //------------------------------------------------------------------------------
202 /**
203  * DrawQuad(Vec3f pos, Vec3f x, Vec3f y, Vec4f color)
204  * @brief Simply draws an OpenGL quad at @a pos.
205  *
206  * The quad's size and orientation are determined by the (non-unit) vectors @a x
207  * and @a y.  Its color is given by @a color.
208  */ 
209 inline void DrawQuad(Vec3f pos, Vec3f x, Vec3f y, Vec4f color)
210 {
211   glColor4fv(&(color.x));
212   Vec3f left  = pos;  left   -= y; 
213   Vec3f right = left; right  += x; 
214   left  -= x;
215   glTexCoord2f(0, 0); glVertex3fv(&(left.x));
216   glTexCoord2f(1, 0); glVertex3fv(&(right.x));
217   left  += y;  left  += y;
218   right += y;  right += y;
219   glTexCoord2f(1, 1); glVertex3fv(&(right.x));
220   glTexCoord2f(0, 1); glVertex3fv(&(left.x));
221 }
222
223
224 //------------------------------------------------------------------------------
225 // Function               : SkyRenderableInstanceCloud::Display
226 // Description      : 
227 //------------------------------------------------------------------------------
228 /**
229  * @fn SkyRenderableInstanceCloud::Display(bool bDisplayFrontOfSplit)
230  * @brief Display the instance of the cloud using the impostor image.
231  */ 
232 SKYRESULT SkyRenderableInstanceCloud::Display(bool bDisplayFrontOfSplit /* = false */)
233 {
234         
235   if (!_bImageExists || !_bEnabled)
236   {
237     //FAIL_RETURN(DisplayWithoutImpostor(*(GLVU::GetCurrent()->GetCurrentCam())));
238     FAIL_RETURN(DisplayWithoutImpostor(Camera()));
239   }
240   else
241   {//cout << "Using impostor image\n";
242       if (!_pBackTexture || (bDisplayFrontOfSplit && !_pFrontTexture)) {
243           // cout << "texture id failure" << endl;
244           FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyRenderableInstanceCloud::Display(): missing texture!");
245       }
246
247     s_pMaterial->SetTexture(0, GL_TEXTURE_2D, bDisplayFrontOfSplit ? *_pFrontTexture : *_pBackTexture);     
248     if (_bScreenImpostor)
249     {
250       s_pMaterial->EnableDepthTest(false);
251     }
252     else if (_bSplit)
253     {
254       if (!bDisplayFrontOfSplit)
255       {
256         s_pMaterial->EnableDepthTest(true);
257         s_pMaterial->SetDepthMask(false);
258       }
259       else
260         s_pMaterial->EnableDepthTest(false);
261     }
262     else
263     {
264       s_pMaterial->EnableDepthTest(true);
265       s_pMaterial->SetDepthMask(true); 
266     }
267      
268     s_pMaterial->Activate();
269     // s_pMaterial->Force();
270
271     Vec3f x, y, z;
272     
273     if (!_bScreenImpostor)
274     {//cout << "Outside the cloud\n";
275       z  =    _vecPosition; 
276       z -=    _impostorCam.Orig;
277       z.Normalize();
278       x  =    (z ^ _impostorCam.Y);
279       x.Normalize();
280       x *=    _rRadius;
281       y  =    (x ^ z);
282       y.Normalize();
283       y *=    _rRadius;      
284
285       glBegin(GL_QUADS);
286       DrawQuad(_vecPosition, x, y, Vec4f(1, 1, 1, 1));
287       glEnd();  
288     }
289     else
290     { //cout <<  "Drawing a polygon - must be inside a cloud\n";
291       x  =  _impostorCam.X;
292       x *=  0.5f * (_impostorCam.wR - _impostorCam.wL);
293       y  =  _impostorCam.Y;
294       y *=  0.5f * (_impostorCam.wT - _impostorCam.wB);
295       z  =  -_impostorCam.Z;
296       z *=  _impostorCam.Near;
297
298       // draw a polygon with this texture...
299       glMatrixMode(GL_MODELVIEW);
300       glPushMatrix();
301       glLoadIdentity();
302       glMatrixMode(GL_PROJECTION);
303       glPushMatrix();
304       glLoadIdentity();
305       gluOrtho2D(-1, 1, -1, 1);
306       
307       glColor4f(1, 1, 1, 1);
308       glBegin(GL_QUADS);
309       glTexCoord2f(0, 0); glVertex2f(-1, -1);
310       glTexCoord2f(1, 0); glVertex2f(1, -1);
311       glTexCoord2f(1, 1); glVertex2f(1, 1);
312       glTexCoord2f(0, 1); glVertex2f(-1, 1);
313       glEnd();
314       
315       glPopMatrix();
316       glMatrixMode(GL_MODELVIEW);
317       glPopMatrix();
318     }
319   }
320   return SKYRESULT_OK;
321 }
322
323
324
325 //------------------------------------------------------------------------------
326 // Function               : SkyRenderableInstanceCloud::DisplayWithoutImpostor
327 // Description      : 
328 //------------------------------------------------------------------------------
329 /**
330  * @fn SkyRenderableInstanceCloud::DisplayWithoutImpostor(const Camera &cam)
331  * @brief Displays the cloud directly -- without an impotor.
332  * 
333  * This is used both when the impostor is disabled and to create the impostor image
334  * when it needs to be updated.
335  */ 
336 SKYRESULT SkyRenderableInstanceCloud::DisplayWithoutImpostor(const Camera &cam)
337 {
338   // Get and set the world space transformation
339   /*Mat44f mat;
340   GetModelToWorldTransform(mat);
341
342   glMatrixMode(GL_MODELVIEW);
343   glPushMatrix();
344   glMultMatrixf(mat.M);*/
345  
346   FAIL_RETURN_MSG(_pCloud->Display(cam, this), "SkyRenderableInstanceCloud:Display(): Cloud's display failed.");
347
348   //glMatrixMode(GL_MODELVIEW);
349   //glPopMatrix();
350
351   return SKYRESULT_OK;
352 }
353
354
355 //------------------------------------------------------------------------------
356 // Function               : SkyRenderableInstanceCloud::ViewFrustumCull
357 // Description      : 
358 //------------------------------------------------------------------------------
359 /**
360  * @fn SkyRenderableInstanceCloud::ViewFrustumCull(const Camera &cam)
361  * @brief View frustum cull the object given its world position
362  */ 
363 bool SkyRenderableInstanceCloud::ViewFrustumCull(const Camera &cam)
364 {
365   Mat44f xform;
366   //GetModelToWorldTransform(xform);
367   xform.Identity();
368   _bCulled = (_pWorldSpaceBV == NULL) ? false : _pWorldSpaceBV->ViewFrustumCull(cam, xform);
369   return _bCulled;
370 }
371
372
373 //------------------------------------------------------------------------------
374 // Function               : SkyRenderableInstanceCloud::ReleaseImpostorTextures
375 // Description      : 
376 //------------------------------------------------------------------------------
377 /**
378  * @fn SkyRenderableInstanceCloud::ReleaseImpostorTextures()
379  * @brief Causes the instance to release its impostor textures for use by other impostors.
380  * 
381  * This method is called when the cloud is view frustum culled.
382  */ 
383 void SkyRenderableInstanceCloud::ReleaseImpostorTextures()
384 {
385   _iCulledCount++;
386
387   if (_iCulledCount > SKYCLOUD_CULL_RELEASE_COUNT)
388   {
389     _iCulledCount = 0;
390   
391     if (_pBackTexture)
392     {
393       DynamicTextureManager::InstancePtr()->CheckInTexture(_pBackTexture);
394       _pBackTexture = NULL;
395     }
396    
397     if (_pFrontTexture)
398     {
399       DynamicTextureManager::InstancePtr()->CheckInTexture(_pFrontTexture);
400       _pFrontTexture = NULL;
401     }
402     _bImageExists = false;
403   }
404 }
405
406
407 //------------------------------------------------------------------------------
408 // Function               : SkyRenderableInstanceCloud::Update
409 // Description      : 
410 //------------------------------------------------------------------------------
411 /**
412  * @fn SkyRenderableInstanceCloud::Update(const Camera &cam)
413  * @brief Updates the impostor image to be valid for the current viewpoint.
414  * 
415  * If the image is already valid, exits early.
416  *
417  * @see SetErrorToleranceAngle, IsValid
418  */ 
419 SKYRESULT SkyRenderableInstanceCloud::Update(const Camera &cam)
420 {
421   if (!_bEnabled || IsImpostorValid(cam)) 
422     return SKYRESULT_OK;
423
424   // since we are going to update it anyway, let's make sure we don't try to use it if something
425   // goes wrong.  This will be set to true on the successful completion of this Update() method.
426   _bImageExists = false;
427 //cout << "updating impostor\n";
428   Mat44f M;
429   
430   _impostorCam = cam;
431   float rDistance  = (_vecPosition - cam.Orig).Length();
432   
433   float rRadius    = _pWorldSpaceBV->GetRadius();
434   float rCamRadius = sqrt(cam.wR*cam.wR + cam.Near*cam.Near);
435   
436   float rWidth     = cam.wR - cam.wL;
437   float rHeight    = cam.wT - cam.wB;
438   float rMaxdim    = (rWidth > rHeight) ? rWidth : rHeight;
439   
440   if (rRadius * cam.Near / rDistance < 0.5 * rMaxdim && (rDistance - rRadius > rCamRadius)) 
441   { // outside cloud
442     _impostorCam.TightlyFitToSphere(cam.Orig, cam.Y, _vecPosition, rRadius);
443     _rRadius = 0.5f * (_impostorCam.wR - _impostorCam.wL) * rDistance / _impostorCam.Near;
444     _rRadius *= GetScale();
445     _bScreenImpostor = false;   
446     // store points used in later error estimation 
447     _vecNearPoint   =   -_impostorCam.Z;
448     _vecNearPoint   *=  _impostorCam.Near;
449     _vecNearPoint   +=  _impostorCam.Orig;
450     _vecFarPoint    =   -_impostorCam.Z;
451     _vecFarPoint    *=  _impostorCam.Far;
452     _vecFarPoint    +=  _impostorCam.Orig;
453   }
454   else // inside cloud
455   {
456     _impostorCam.Far  =  _impostorCam.Near + 3 * rRadius;
457     _bScreenImpostor =  true;
458   }
459   
460   // resolution based on screensize, distance, and object size.
461   // Cam radius is used to heuristically reduce resolution for clouds very close to the camera.
462   _iLogResolution = _GetRequiredLogResolution(rDistance, rRadius, rCamRadius);
463
464   int iRes = 1 << _iLogResolution;
465
466   int iOldVP[4];
467
468   glGetIntegerv(GL_VIEWPORT, iOldVP);
469   
470   _impostorCam.GetProjectionMatrix(M);
471   glMatrixMode(GL_PROJECTION);
472   glPushMatrix();
473   glLoadMatrixf(M);
474   
475   _impostorCam.GetModelviewMatrix(M);
476   glMatrixMode(GL_MODELVIEW);
477   glPushMatrix();
478   glLoadMatrixf(M);
479   
480   glViewport(0, 0, iRes, iRes);
481   
482   s_pMaterial->SetDepthMask(true);  // so that the depth buffer gets cleared!
483   s_pMaterial->Activate();
484   glClearColor(0, 0, 0, 0);
485   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
486   
487   if (!_bSplit)
488   {
489     FAIL_RETURN(DisplayWithoutImpostor(_impostorCam));
490     
491     if (_pBackTexture && _pBackTexture->GetWidth() != iRes)
492     {
493       DynamicTextureManager::InstancePtr()->CheckInTexture(_pBackTexture);
494       _pBackTexture = NULL;
495     }
496     
497     if (!_pBackTexture)
498     {
499       _pBackTexture = DynamicTextureManager::InstancePtr()->CheckOutTexture(iRes, iRes);
500     }
501     
502     s_pMaterial->SetTexture(0, GL_TEXTURE_2D, *_pBackTexture);     // shared material for clouds. 
503     s_pMaterial->Activate();
504     
505     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, iRes, iRes);
506   }
507   else
508   {  
509     FAIL_RETURN_MSG(_pCloud->DisplaySplit(cam, _vecSplit, true, this), 
510                     "SkyRenderableInstanceCloud:Display(): Cloud's display failed.");
511
512     if (_pBackTexture && _pBackTexture->GetWidth() != iRes)
513     {
514       DynamicTextureManager::InstancePtr()->CheckInTexture(_pBackTexture);
515       _pBackTexture = NULL;
516     }
517     if (_pFrontTexture && _pFrontTexture->GetWidth() != iRes)
518     {
519       DynamicTextureManager::InstancePtr()->CheckInTexture(_pFrontTexture);
520       _pFrontTexture = NULL;
521     }
522
523     if (!_pBackTexture)
524     {
525       _pBackTexture = DynamicTextureManager::InstancePtr()->CheckOutTexture(iRes, iRes);
526     }
527
528     s_pMaterial->SetTexture(0, GL_TEXTURE_2D, *_pBackTexture);     // shared material for clouds. 
529     FAIL_RETURN(s_pMaterial->Activate());
530    
531     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, iRes, iRes);
532
533     // now clear and draw the front.
534     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
535
536     FAIL_RETURN_MSG(_pCloud->DisplaySplit(cam, _vecSplit, false, this), 
537                     "SkyRenderableInstanceCloud:Display(): Cloud's display failed.");
538
539     if (!_pFrontTexture)
540     {
541       _pFrontTexture = DynamicTextureManager::InstancePtr()->CheckOutTexture(iRes, iRes);
542     }
543
544     s_pMaterial->GetTextureState().SetTexture(0, GL_TEXTURE_2D, *_pFrontTexture);
545     FAIL_RETURN(s_pMaterial->GetTextureState().Activate());
546
547     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, iRes, iRes);
548   }
549   
550   glMatrixMode(GL_MODELVIEW);
551   glPopMatrix();
552   glMatrixMode(GL_PROJECTION);
553   glPopMatrix();
554   
555   //GLVU::CheckForGLError("Cloud Impostor Update");
556
557     glViewport(iOldVP[0], iOldVP[1], iOldVP[2], iOldVP[3]);
558
559   _bImageExists = true;
560
561   // the textures should now exist.
562   assert(_pBackTexture);
563   assert(!_bSplit || (_bSplit && _pFrontTexture));
564
565   return SKYRESULT_OK;
566 }
567
568
569 //------------------------------------------------------------------------------
570 // Function               : SkyRenderableInstanceCloud::IsImpostorValid
571 // Description      : 
572 //------------------------------------------------------------------------------
573 /**
574  * @fn SkyRenderableInstanceCloud::IsImpostorValid(const Camera& cam)
575  * @brief Returns true if the impostor image is valid for the given camera.
576  * 
577  * Will return false if this is a screen impostor, or if there is error in either
578  * the translation of the camera from the capture point or the impostor image resolution.
579  *
580  * @see SetErrorToleranceAngle
581  */ 
582 bool SkyRenderableInstanceCloud::IsImpostorValid(const Camera& cam)
583
584   // first make sure there is a current image.
585   if (!_bImageExists) 
586     return false;
587
588   // screen impostors should always be updated
589   if (_bScreenImpostor)
590   {
591     _vecFarPoint = Vec3f::ZERO;
592     _vecNearPoint = Vec3f::ZERO;
593 #if SKYCLOUD_VERBOSE
594     SkyTrace("Screen Impostor Update");
595 #endif
596     return false;
597   }
598   // impostors are valid from the viewpoint from which they were captured
599   if (cam.Orig == _impostorCam.Orig) 
600     return true;
601   
602   if (_bSplit) 
603   {
604   #if SKYCLOUD_VERBOSE
605     SkyTrace("Split Impostor Update");
606   #endif
607     return false;
608   }
609   
610   Vec3f vecX = _vecNearPoint - cam.Orig;
611   Vec3f vecY = _vecFarPoint - cam.Orig;
612   float rXLength = vecX.Length();
613   float rYLength = vecY.Length();
614   if (rXLength > rYLength) 
615   {
616 #if SKYCLOUD_VERBOSE
617     SkyTrace("Backwards Impostor Update");
618 #endif
619     return false;
620   }
621   
622   vecX /= rXLength; 
623   vecY /= rYLength; 
624   float rCosAlpha = vecX * vecY; // dot product of normalized vectors = cosine
625   
626   if (fabs(rCosAlpha) < 1.0) 
627   {
628     float rAlpha = acos(rCosAlpha);
629     if (rAlpha >= s_rErrorToleranceAngle) 
630     {
631 #if SKYCLOUD_VERBOSE
632       SkyTrace("Angle Error Update %f", SKYRADSTODEGREES * rAlpha);
633 #endif
634       return false;
635     }
636   }
637  
638   float rDistance = (_vecPosition - cam.Orig).Length();
639   float rCamRadius = sqrt(cam.wR*cam.wR + cam.Near*cam.Near);
640   
641   int iRes = _GetRequiredLogResolution(rDistance, _pWorldSpaceBV->GetRadius(), rCamRadius);
642
643   if (iRes > _iLogResolution)
644   {
645 #if SKYCLOUD_VERBOSE
646     SkyTrace("Resolution Error Update: Required: %d Actual: %d", iRes, _iLogResolution);
647 #endif
648     return false;
649   }
650  
651   return true;
652 }
653
654
655 //------------------------------------------------------------------------------
656   // Function             : SetErrorToleranceAngle
657   // Description            : 
658   //------------------------------------------------------------------------------
659   /**
660   * @fn SkyRenderableInstanceCloud::SetErrorToleranceAngle(float rDegrees)
661   * @brief Set the global error tolerance angle for all impostors.
662   */ 
663 void SkyRenderableInstanceCloud::SetErrorToleranceAngle(float rDegrees)
664
665   s_rErrorToleranceAngle = SKYDEGREESTORADS * rDegrees; 
666 }
667
668
669
670 //------------------------------------------------------------------------------
671 // Function               : SkyRenderableInstanceCloud::_Initialize
672 // Description      : 
673 //------------------------------------------------------------------------------
674 /**
675  * @fn SkyRenderableInstanceCloud::_Initialize()
676  * @brief Initializer used by the constructors.
677  */ 
678 void SkyRenderableInstanceCloud::_Initialize()
679 {
680   _UpdateWorldSpaceBounds();
681
682 //  if (!s_pRenderBuffer && _bUseOffScreenBuffer)
683 //  {
684 //JW??    s_pRenderBuffer = new SkyOffScreenBuffer(GLUT_SINGLE | GLUT_DEPTH | GLUT_STENCIL);
685 //JW??    s_pRenderBuffer->Initialize(true);
686     
687 //JW??    s_pRenderBuffer->MakeCurrent();
688     // set some GL state:
689 //    glClearColor(0, 0, 0, 0);
690 //JW??    GLVU::GetCurrent()->MakeCurrent();
691 //  }
692   if (!s_pMaterial)
693   {
694     s_pMaterial = new SkyMaterial;
695     s_pMaterial->EnableBlending(true);
696     s_pMaterial->SetBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
697     s_pMaterial->SetAlphaFunc(GL_GREATER);
698     s_pMaterial->EnableDepthTest(false);
699     s_pMaterial->SetDepthMask(true);
700     s_pMaterial->EnableAlphaTest(true);
701     s_pMaterial->EnableLighting(false);
702     s_pMaterial->SetTextureParameter(0, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
703     s_pMaterial->SetTextureParameter(0, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
704     s_pMaterial->SetTextureParameter(0, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
705     s_pMaterial->EnableTexture(0, true);    
706   }
707   s_iCount++;
708 }