709 lines
22 KiB
C++
709 lines
22 KiB
C++
//------------------------------------------------------------------------------
|
|
// File : SkyRenderableInstanceCloud.cpp
|
|
//------------------------------------------------------------------------------
|
|
// SkyWorks : Copyright 2002 Mark J. Harris and
|
|
// The University of North Carolina at Chapel Hill
|
|
//------------------------------------------------------------------------------
|
|
// Permission to use, copy, modify, distribute and sell this software and its
|
|
// documentation for any purpose is hereby granted without fee, provided that
|
|
// the above copyright notice appear in all copies and that both that copyright
|
|
// notice and this permission notice appear in supporting documentation.
|
|
// Binaries may be compiled with this software without any royalties or
|
|
// restrictions.
|
|
//
|
|
// The author(s) and The University of North Carolina at Chapel Hill make no
|
|
// representations about the suitability of this software for any purpose.
|
|
// It is provided "as is" without express or implied warranty.
|
|
/**
|
|
* @file SkyRenderableInstanceCloud.cpp
|
|
*
|
|
* Implementation of class SkyRenderableInstanceCloud.
|
|
*/
|
|
#include "SkyUtil.hpp"
|
|
#include "SkyCloud.hpp"
|
|
#include "SkyMaterial.hpp"
|
|
#include "SkyBoundingVolume.hpp"
|
|
#include "SkyRenderableInstanceCloud.hpp"
|
|
#include "SkyDynamicTextureManager.hpp"
|
|
|
|
//! Set this to 1 to see verbose messages about impostor updates.
|
|
#define SKYCLOUD_VERBOSE 0
|
|
|
|
//! Set this to control the number of frames a cloud has to be culled before its textures are released.
|
|
#define SKYCLOUD_CULL_RELEASE_COUNT 100
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Static declarations.
|
|
//------------------------------------------------------------------------------
|
|
unsigned int SkyRenderableInstanceCloud::s_iCount = 0;
|
|
float SkyRenderableInstanceCloud::s_rErrorToleranceAngle = SKYDEGREESTORADS * 0.125f;
|
|
SkyMaterial* SkyRenderableInstanceCloud::s_pMaterial = NULL;
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Function : SkyRenderableInstanceCloud::SkyRenderableInstanceCloud
|
|
// Description :
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* @fn SkyRenderableInstanceCloud::SkyRenderableInstanceCloud(SkyCloud *pCloud, bool bUseOffScreenBuffer)
|
|
* @brief Constructor.
|
|
*/
|
|
SkyRenderableInstanceCloud::SkyRenderableInstanceCloud(SkyCloud *pCloud,
|
|
bool bUseOffScreenBuffer /* = true */)
|
|
: SkyRenderableInstance(),
|
|
_iCloudID(-1),
|
|
_pCloud(pCloud),
|
|
_pWorldSpaceBV(NULL),
|
|
_rRadius(0),
|
|
_bScreenImpostor(false),
|
|
_bImageExists(false),
|
|
_bEnabled(true),
|
|
_bUseOffScreenBuffer(bUseOffScreenBuffer),
|
|
_bSplit(false),
|
|
_vecSplit(0, 0, 0),
|
|
_vecNearPoint(0, 0, 0),
|
|
_vecFarPoint(0, 0, 0),
|
|
_iLogResolution(0),
|
|
_pBackTexture(NULL),
|
|
_pFrontTexture(NULL),
|
|
_iCulledCount(0)
|
|
{
|
|
_Initialize();
|
|
// cout << "Cloud Instance created" << endl;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Function : SkyRenderableInstanceCloud::SkyRenderableInstanceCloud
|
|
// Description :
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* @fn SkyRenderableInstanceCloud::SkyRenderableInstanceCloud(SkyCloud *pCloud, const Vec3f &position, const Mat33f &rotation, const float scale, bool bUseOffScreenBuffer)
|
|
* @brief Constructor.
|
|
*/
|
|
SkyRenderableInstanceCloud::SkyRenderableInstanceCloud(SkyCloud *pCloud,
|
|
const Vec3f &position,
|
|
const Mat33f &rotation,
|
|
const float scale,
|
|
bool bUseOffScreenBuffer /* = true */)
|
|
: SkyRenderableInstance(position, rotation, scale),
|
|
_iCloudID(-1),
|
|
_pCloud(pCloud),
|
|
_pWorldSpaceBV(NULL),
|
|
_rRadius(0),
|
|
_bScreenImpostor(false),
|
|
_bImageExists(false),
|
|
_bEnabled(true),
|
|
_bUseOffScreenBuffer(false),
|
|
_bSplit(false),
|
|
_vecSplit(0, 0, 0),
|
|
_vecNearPoint(0, 0, 0),
|
|
_vecFarPoint(0, 0, 0),
|
|
_iLogResolution(0),
|
|
_pBackTexture(NULL),
|
|
_pFrontTexture(NULL)
|
|
{
|
|
_Initialize();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Function : SkyRenderableInstanceCloud::~SkyRenderableInstanceCloud
|
|
// Description :
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* @fn SkyRenderableInstanceCloud::~SkyRenderableInstanceCloud()
|
|
* @brief Destructor
|
|
*/
|
|
SkyRenderableInstanceCloud::~SkyRenderableInstanceCloud()
|
|
{
|
|
_pCloud = NULL;
|
|
SAFE_DELETE(_pWorldSpaceBV);
|
|
|
|
s_iCount--;
|
|
// delete the offscreen buffer when no one else is using it.
|
|
if (0 == s_iCount)
|
|
{
|
|
//JW?? SAFE_DELETE(s_pRenderBuffer);
|
|
SAFE_DELETE(s_pMaterial);
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Function : SkyRenderableInstanceCloud::SetPosition
|
|
// Description :
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* @fn SkyRenderableInstanceCloud::SetPosition(const Vec3f &position)
|
|
* @brief Set the world space position of the instance.
|
|
*
|
|
* @todo <WRITE EXTENDED SkyRenderableInstanceCloud::SetPosition FUNCTION DOCUMENTATION>
|
|
*/
|
|
void SkyRenderableInstanceCloud::SetPosition(const Vec3f &position)
|
|
{
|
|
if (_pCloud)
|
|
{
|
|
_pCloud->Translate(position - _vecPosition);
|
|
}
|
|
_vecPosition = position;
|
|
|
|
_UpdateWorldSpaceBounds();
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Function : SkyRenderableInstanceCloud::SetRotation
|
|
// Description :
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* @fn SkyRenderableInstanceCloud::SetRotation(const Mat33f &rotation)
|
|
* @brief Set the world space rotation of the instance.
|
|
*
|
|
* @todo <WRITE EXTENDED SkyRenderableInstanceCloud::SetRotation FUNCTION DOCUMENTATION>
|
|
*/
|
|
void SkyRenderableInstanceCloud::SetRotation(const Mat33f &rotation)
|
|
{
|
|
if (_pCloud)
|
|
{
|
|
_pCloud->Translate(-_vecPosition);
|
|
_pCloud->Rotate(_matInvRotation * rotation);
|
|
_pCloud->Translate(_vecPosition);
|
|
}
|
|
_matRotation = rotation;
|
|
_matInvRotation = rotation;
|
|
_matInvRotation.Transpose();
|
|
_UpdateWorldSpaceBounds();
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Function : SkyRenderableInstanceCloud::SetScale
|
|
// Description :
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* @fn SkyRenderableInstanceCloud::SetScale(const float &scale)
|
|
* @brief Set the world space scale of the instance.
|
|
*/
|
|
void SkyRenderableInstanceCloud::SetScale(const float &scale)
|
|
{
|
|
if (_pCloud)
|
|
{
|
|
_pCloud->Translate(-_vecPosition);
|
|
_pCloud->Scale(scale);
|
|
_pCloud->Translate(_vecPosition);
|
|
}
|
|
_rScale = scale;
|
|
_UpdateWorldSpaceBounds();
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Function : DrawQuad
|
|
// Description :
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* DrawQuad(Vec3f pos, Vec3f x, Vec3f y, Vec4f color)
|
|
* @brief Simply draws an OpenGL quad at @a pos.
|
|
*
|
|
* The quad's size and orientation are determined by the (non-unit) vectors @a x
|
|
* and @a y. Its color is given by @a color.
|
|
*/
|
|
inline void DrawQuad(Vec3f pos, Vec3f x, Vec3f y, Vec4f color)
|
|
{
|
|
glColor4fv(&(color.x));
|
|
Vec3f left = pos; left -= y;
|
|
Vec3f right = left; right += x;
|
|
left -= x;
|
|
glTexCoord2f(0, 0); glVertex3fv(&(left.x));
|
|
glTexCoord2f(1, 0); glVertex3fv(&(right.x));
|
|
left += y; left += y;
|
|
right += y; right += y;
|
|
glTexCoord2f(1, 1); glVertex3fv(&(right.x));
|
|
glTexCoord2f(0, 1); glVertex3fv(&(left.x));
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Function : SkyRenderableInstanceCloud::Display
|
|
// Description :
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* @fn SkyRenderableInstanceCloud::Display(bool bDisplayFrontOfSplit)
|
|
* @brief Display the instance of the cloud using the impostor image.
|
|
*/
|
|
SKYRESULT SkyRenderableInstanceCloud::Display(bool bDisplayFrontOfSplit /* = false */)
|
|
{
|
|
|
|
if (!_bImageExists || !_bEnabled)
|
|
{
|
|
//FAIL_RETURN(DisplayWithoutImpostor(*(GLVU::GetCurrent()->GetCurrentCam())));
|
|
FAIL_RETURN(DisplayWithoutImpostor(Camera()));
|
|
}
|
|
else
|
|
{//cout << "Using impostor image\n";
|
|
if (!_pBackTexture || (bDisplayFrontOfSplit && !_pFrontTexture)) {
|
|
// cout << "texture id failure" << endl;
|
|
FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyRenderableInstanceCloud::Display(): missing texture!");
|
|
}
|
|
|
|
s_pMaterial->SetTexture(0, GL_TEXTURE_2D, bDisplayFrontOfSplit ? *_pFrontTexture : *_pBackTexture);
|
|
if (_bScreenImpostor)
|
|
{
|
|
s_pMaterial->EnableDepthTest(false);
|
|
}
|
|
else if (_bSplit)
|
|
{
|
|
if (!bDisplayFrontOfSplit)
|
|
{
|
|
s_pMaterial->EnableDepthTest(true);
|
|
s_pMaterial->SetDepthMask(false);
|
|
}
|
|
else
|
|
s_pMaterial->EnableDepthTest(false);
|
|
}
|
|
else
|
|
{
|
|
s_pMaterial->EnableDepthTest(true);
|
|
s_pMaterial->SetDepthMask(true);
|
|
}
|
|
|
|
s_pMaterial->Activate();
|
|
// s_pMaterial->Force();
|
|
|
|
Vec3f x, y, z;
|
|
|
|
if (!_bScreenImpostor)
|
|
{//cout << "Outside the cloud\n";
|
|
z = _vecPosition;
|
|
z -= _impostorCam.Orig;
|
|
z.Normalize();
|
|
x = (z ^ _impostorCam.Y);
|
|
x.Normalize();
|
|
x *= _rRadius;
|
|
y = (x ^ z);
|
|
y.Normalize();
|
|
y *= _rRadius;
|
|
|
|
glBegin(GL_QUADS);
|
|
DrawQuad(_vecPosition, x, y, Vec4f(1, 1, 1, 1));
|
|
glEnd();
|
|
}
|
|
else
|
|
{ //cout << "Drawing a polygon - must be inside a cloud\n";
|
|
x = _impostorCam.X;
|
|
x *= 0.5f * (_impostorCam.wR - _impostorCam.wL);
|
|
y = _impostorCam.Y;
|
|
y *= 0.5f * (_impostorCam.wT - _impostorCam.wB);
|
|
z = -_impostorCam.Z;
|
|
z *= _impostorCam.Near;
|
|
|
|
// draw a polygon with this texture...
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
gluOrtho2D(-1, 1, -1, 1);
|
|
|
|
glColor4f(1, 1, 1, 1);
|
|
glBegin(GL_QUADS);
|
|
glTexCoord2f(0, 0); glVertex2f(-1, -1);
|
|
glTexCoord2f(1, 0); glVertex2f(1, -1);
|
|
glTexCoord2f(1, 1); glVertex2f(1, 1);
|
|
glTexCoord2f(0, 1); glVertex2f(-1, 1);
|
|
glEnd();
|
|
|
|
glPopMatrix();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPopMatrix();
|
|
}
|
|
}
|
|
return SKYRESULT_OK;
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Function : SkyRenderableInstanceCloud::DisplayWithoutImpostor
|
|
// Description :
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* @fn SkyRenderableInstanceCloud::DisplayWithoutImpostor(const Camera &cam)
|
|
* @brief Displays the cloud directly -- without an impotor.
|
|
*
|
|
* This is used both when the impostor is disabled and to create the impostor image
|
|
* when it needs to be updated.
|
|
*/
|
|
SKYRESULT SkyRenderableInstanceCloud::DisplayWithoutImpostor(const Camera &cam)
|
|
{
|
|
// Get and set the world space transformation
|
|
/*Mat44f mat;
|
|
GetModelToWorldTransform(mat);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glMultMatrixf(mat.M);*/
|
|
|
|
FAIL_RETURN_MSG(_pCloud->Display(cam, this), "SkyRenderableInstanceCloud:Display(): Cloud's display failed.");
|
|
|
|
//glMatrixMode(GL_MODELVIEW);
|
|
//glPopMatrix();
|
|
|
|
return SKYRESULT_OK;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Function : SkyRenderableInstanceCloud::ViewFrustumCull
|
|
// Description :
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* @fn SkyRenderableInstanceCloud::ViewFrustumCull(const Camera &cam)
|
|
* @brief View frustum cull the object given its world position
|
|
*/
|
|
bool SkyRenderableInstanceCloud::ViewFrustumCull(const Camera &cam)
|
|
{
|
|
Mat44f xform;
|
|
//GetModelToWorldTransform(xform);
|
|
xform.Identity();
|
|
_bCulled = (_pWorldSpaceBV == NULL) ? false : _pWorldSpaceBV->ViewFrustumCull(cam, xform);
|
|
return _bCulled;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Function : SkyRenderableInstanceCloud::ReleaseImpostorTextures
|
|
// Description :
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* @fn SkyRenderableInstanceCloud::ReleaseImpostorTextures()
|
|
* @brief Causes the instance to release its impostor textures for use by other impostors.
|
|
*
|
|
* This method is called when the cloud is view frustum culled.
|
|
*/
|
|
void SkyRenderableInstanceCloud::ReleaseImpostorTextures()
|
|
{
|
|
_iCulledCount++;
|
|
|
|
if (_iCulledCount > SKYCLOUD_CULL_RELEASE_COUNT)
|
|
{
|
|
_iCulledCount = 0;
|
|
|
|
if (_pBackTexture)
|
|
{
|
|
DynamicTextureManager::InstancePtr()->CheckInTexture(_pBackTexture);
|
|
_pBackTexture = NULL;
|
|
}
|
|
|
|
if (_pFrontTexture)
|
|
{
|
|
DynamicTextureManager::InstancePtr()->CheckInTexture(_pFrontTexture);
|
|
_pFrontTexture = NULL;
|
|
}
|
|
_bImageExists = false;
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Function : SkyRenderableInstanceCloud::Update
|
|
// Description :
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* @fn SkyRenderableInstanceCloud::Update(const Camera &cam)
|
|
* @brief Updates the impostor image to be valid for the current viewpoint.
|
|
*
|
|
* If the image is already valid, exits early.
|
|
*
|
|
* @see SetErrorToleranceAngle, IsValid
|
|
*/
|
|
SKYRESULT SkyRenderableInstanceCloud::Update(const Camera &cam)
|
|
{
|
|
if (!_bEnabled || IsImpostorValid(cam))
|
|
return SKYRESULT_OK;
|
|
|
|
// since we are going to update it anyway, let's make sure we don't try to use it if something
|
|
// goes wrong. This will be set to true on the successful completion of this Update() method.
|
|
_bImageExists = false;
|
|
//cout << "updating impostor\n";
|
|
Mat44f M;
|
|
|
|
_impostorCam = cam;
|
|
float rDistance = (_vecPosition - cam.Orig).Length();
|
|
|
|
float rRadius = _pWorldSpaceBV->GetRadius();
|
|
float rCamRadius = sqrt(cam.wR*cam.wR + cam.Near*cam.Near);
|
|
|
|
float rWidth = cam.wR - cam.wL;
|
|
float rHeight = cam.wT - cam.wB;
|
|
float rMaxdim = (rWidth > rHeight) ? rWidth : rHeight;
|
|
|
|
if (rRadius * cam.Near / rDistance < 0.5 * rMaxdim && (rDistance - rRadius > rCamRadius))
|
|
{ // outside cloud
|
|
_impostorCam.TightlyFitToSphere(cam.Orig, cam.Y, _vecPosition, rRadius);
|
|
_rRadius = 0.5f * (_impostorCam.wR - _impostorCam.wL) * rDistance / _impostorCam.Near;
|
|
_rRadius *= GetScale();
|
|
_bScreenImpostor = false;
|
|
// store points used in later error estimation
|
|
_vecNearPoint = -_impostorCam.Z;
|
|
_vecNearPoint *= _impostorCam.Near;
|
|
_vecNearPoint += _impostorCam.Orig;
|
|
_vecFarPoint = -_impostorCam.Z;
|
|
_vecFarPoint *= _impostorCam.Far;
|
|
_vecFarPoint += _impostorCam.Orig;
|
|
}
|
|
else // inside cloud
|
|
{
|
|
_impostorCam.Far = _impostorCam.Near + 3 * rRadius;
|
|
_bScreenImpostor = true;
|
|
}
|
|
|
|
// resolution based on screensize, distance, and object size.
|
|
// Cam radius is used to heuristically reduce resolution for clouds very close to the camera.
|
|
_iLogResolution = _GetRequiredLogResolution(rDistance, rRadius, rCamRadius);
|
|
|
|
int iRes = 1 << _iLogResolution;
|
|
|
|
int iOldVP[4];
|
|
|
|
glGetIntegerv(GL_VIEWPORT, iOldVP);
|
|
|
|
_impostorCam.GetProjectionMatrix(M);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glLoadMatrixf(M);
|
|
|
|
_impostorCam.GetModelviewMatrix(M);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadMatrixf(M);
|
|
|
|
glViewport(0, 0, iRes, iRes);
|
|
|
|
s_pMaterial->SetDepthMask(true); // so that the depth buffer gets cleared!
|
|
s_pMaterial->Activate();
|
|
glClearColor(0, 0, 0, 0);
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
if (!_bSplit)
|
|
{
|
|
FAIL_RETURN(DisplayWithoutImpostor(_impostorCam));
|
|
|
|
if (_pBackTexture && _pBackTexture->GetWidth() != iRes)
|
|
{
|
|
DynamicTextureManager::InstancePtr()->CheckInTexture(_pBackTexture);
|
|
_pBackTexture = NULL;
|
|
}
|
|
|
|
if (!_pBackTexture)
|
|
{
|
|
_pBackTexture = DynamicTextureManager::InstancePtr()->CheckOutTexture(iRes, iRes);
|
|
}
|
|
|
|
s_pMaterial->SetTexture(0, GL_TEXTURE_2D, *_pBackTexture); // shared material for clouds.
|
|
s_pMaterial->Activate();
|
|
|
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, iRes, iRes);
|
|
}
|
|
else
|
|
{
|
|
FAIL_RETURN_MSG(_pCloud->DisplaySplit(cam, _vecSplit, true, this),
|
|
"SkyRenderableInstanceCloud:Display(): Cloud's display failed.");
|
|
|
|
if (_pBackTexture && _pBackTexture->GetWidth() != iRes)
|
|
{
|
|
DynamicTextureManager::InstancePtr()->CheckInTexture(_pBackTexture);
|
|
_pBackTexture = NULL;
|
|
}
|
|
if (_pFrontTexture && _pFrontTexture->GetWidth() != iRes)
|
|
{
|
|
DynamicTextureManager::InstancePtr()->CheckInTexture(_pFrontTexture);
|
|
_pFrontTexture = NULL;
|
|
}
|
|
|
|
if (!_pBackTexture)
|
|
{
|
|
_pBackTexture = DynamicTextureManager::InstancePtr()->CheckOutTexture(iRes, iRes);
|
|
}
|
|
|
|
s_pMaterial->SetTexture(0, GL_TEXTURE_2D, *_pBackTexture); // shared material for clouds.
|
|
FAIL_RETURN(s_pMaterial->Activate());
|
|
|
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, iRes, iRes);
|
|
|
|
// now clear and draw the front.
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
FAIL_RETURN_MSG(_pCloud->DisplaySplit(cam, _vecSplit, false, this),
|
|
"SkyRenderableInstanceCloud:Display(): Cloud's display failed.");
|
|
|
|
if (!_pFrontTexture)
|
|
{
|
|
_pFrontTexture = DynamicTextureManager::InstancePtr()->CheckOutTexture(iRes, iRes);
|
|
}
|
|
|
|
s_pMaterial->GetTextureState().SetTexture(0, GL_TEXTURE_2D, *_pFrontTexture);
|
|
FAIL_RETURN(s_pMaterial->GetTextureState().Activate());
|
|
|
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, iRes, iRes);
|
|
}
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
|
|
//GLVU::CheckForGLError("Cloud Impostor Update");
|
|
|
|
glViewport(iOldVP[0], iOldVP[1], iOldVP[2], iOldVP[3]);
|
|
|
|
_bImageExists = true;
|
|
|
|
// the textures should now exist.
|
|
assert(_pBackTexture);
|
|
assert(!_bSplit || (_bSplit && _pFrontTexture));
|
|
|
|
return SKYRESULT_OK;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Function : SkyRenderableInstanceCloud::IsImpostorValid
|
|
// Description :
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* @fn SkyRenderableInstanceCloud::IsImpostorValid(const Camera& cam)
|
|
* @brief Returns true if the impostor image is valid for the given camera.
|
|
*
|
|
* Will return false if this is a screen impostor, or if there is error in either
|
|
* the translation of the camera from the capture point or the impostor image resolution.
|
|
*
|
|
* @see SetErrorToleranceAngle
|
|
*/
|
|
bool SkyRenderableInstanceCloud::IsImpostorValid(const Camera& cam)
|
|
{
|
|
// first make sure there is a current image.
|
|
if (!_bImageExists)
|
|
return false;
|
|
|
|
// screen impostors should always be updated
|
|
if (_bScreenImpostor)
|
|
{
|
|
_vecFarPoint = Vec3f::ZERO;
|
|
_vecNearPoint = Vec3f::ZERO;
|
|
#if SKYCLOUD_VERBOSE
|
|
SkyTrace("Screen Impostor Update");
|
|
#endif
|
|
return false;
|
|
}
|
|
// impostors are valid from the viewpoint from which they were captured
|
|
if (cam.Orig == _impostorCam.Orig)
|
|
return true;
|
|
|
|
if (_bSplit)
|
|
{
|
|
#if SKYCLOUD_VERBOSE
|
|
SkyTrace("Split Impostor Update");
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
Vec3f vecX = _vecNearPoint - cam.Orig;
|
|
Vec3f vecY = _vecFarPoint - cam.Orig;
|
|
float rXLength = vecX.Length();
|
|
float rYLength = vecY.Length();
|
|
if (rXLength > rYLength)
|
|
{
|
|
#if SKYCLOUD_VERBOSE
|
|
SkyTrace("Backwards Impostor Update");
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
vecX /= rXLength;
|
|
vecY /= rYLength;
|
|
float rCosAlpha = vecX * vecY; // dot product of normalized vectors = cosine
|
|
|
|
if (fabs(rCosAlpha) < 1.0)
|
|
{
|
|
float rAlpha = acos(rCosAlpha);
|
|
if (rAlpha >= s_rErrorToleranceAngle)
|
|
{
|
|
#if SKYCLOUD_VERBOSE
|
|
SkyTrace("Angle Error Update %f", SKYRADSTODEGREES * rAlpha);
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
|
|
float rDistance = (_vecPosition - cam.Orig).Length();
|
|
float rCamRadius = sqrt(cam.wR*cam.wR + cam.Near*cam.Near);
|
|
|
|
int iRes = _GetRequiredLogResolution(rDistance, _pWorldSpaceBV->GetRadius(), rCamRadius);
|
|
|
|
if (iRes > _iLogResolution)
|
|
{
|
|
#if SKYCLOUD_VERBOSE
|
|
SkyTrace("Resolution Error Update: Required: %d Actual: %d", iRes, _iLogResolution);
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Function : SetErrorToleranceAngle
|
|
// Description :
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* @fn SkyRenderableInstanceCloud::SetErrorToleranceAngle(float rDegrees)
|
|
* @brief Set the global error tolerance angle for all impostors.
|
|
*/
|
|
void SkyRenderableInstanceCloud::SetErrorToleranceAngle(float rDegrees)
|
|
{
|
|
s_rErrorToleranceAngle = SKYDEGREESTORADS * rDegrees;
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Function : SkyRenderableInstanceCloud::_Initialize
|
|
// Description :
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* @fn SkyRenderableInstanceCloud::_Initialize()
|
|
* @brief Initializer used by the constructors.
|
|
*/
|
|
void SkyRenderableInstanceCloud::_Initialize()
|
|
{
|
|
_UpdateWorldSpaceBounds();
|
|
|
|
// if (!s_pRenderBuffer && _bUseOffScreenBuffer)
|
|
// {
|
|
//JW?? s_pRenderBuffer = new SkyOffScreenBuffer(GLUT_SINGLE | GLUT_DEPTH | GLUT_STENCIL);
|
|
//JW?? s_pRenderBuffer->Initialize(true);
|
|
|
|
//JW?? s_pRenderBuffer->MakeCurrent();
|
|
// set some GL state:
|
|
// glClearColor(0, 0, 0, 0);
|
|
//JW?? GLVU::GetCurrent()->MakeCurrent();
|
|
// }
|
|
if (!s_pMaterial)
|
|
{
|
|
s_pMaterial = new SkyMaterial;
|
|
s_pMaterial->EnableBlending(true);
|
|
s_pMaterial->SetBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
|
s_pMaterial->SetAlphaFunc(GL_GREATER);
|
|
s_pMaterial->EnableDepthTest(false);
|
|
s_pMaterial->SetDepthMask(true);
|
|
s_pMaterial->EnableAlphaTest(true);
|
|
s_pMaterial->EnableLighting(false);
|
|
s_pMaterial->SetTextureParameter(0, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
s_pMaterial->SetTextureParameter(0, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
s_pMaterial->SetTextureParameter(0, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
s_pMaterial->EnableTexture(0, true);
|
|
}
|
|
s_iCount++;
|
|
}
|