Files
2025-09-18 17:55:52 -04:00

235 lines
5.7 KiB
C++

#include "stdafx.h"
#include "EnvMap.h"
#include "VisualEngine.h"
#include "GfxCore/Device.h"
#include "GfxCore/Texture.h"
#include "GfxCore/FrameBuffer.h"
#include "GlobalShaderData.h"
#include "SceneManager.h"
#include "ShaderManager.h"
#include "Sky.h"
#include "TextureManager.h"
#include "GfxCore/pix.h"
static const float MATH_PI = 3.14159265359f;
static const int kCubemapSize = 256;
namespace RBX { namespace Graphics {
EnvMap::EnvMap(VisualEngine* ve): Resource(ve->getDevice())
{
dirtyState = VeryDirty;
updateStep = 0;
visualEngine = ve;
Device* dev = ve->getDevice();
envmapLastRealTime = 0;
envmapLastTimeOfDay = 0;
setDebugName("Global envmap");
texture = dev->createTexture(Texture::Type_Cube, Texture::Format_RGBA8, kCubemapSize, kCubemapSize, 1, Texture::getMaxMipCount(kCubemapSize,kCubemapSize,1), Texture::Usage_Renderbuffer);
for (int j=0; j<6; ++j)
{
shared_ptr<Renderbuffer> rb = texture.getTexture()->getRenderbuffer(j, 0);
fbFaces[j] = dev->createFramebuffer(rb); // no depth
}
}
EnvMap::~EnvMap()
{
}
static Matrix4 lookat( Vector3 dir, Vector3 up, float rh = 1.0f )
{
Matrix4 result = Matrix4::identity();
Vector3 rt = cross(up,rh*dir);
result.setRow( 0, Vector4(rt,0) );
result.setRow( 1, Vector4(up,0) );
result.setRow( 2, Vector4(dir,0) );
return result;
}
static const double kEnvmapGameTimePeriod = 120;
static const double kEnvmapRealtimePeriod = 30;
void EnvMap::update(DeviceContext* context, double gameTime)
{
// prepare the envmap
if (texture.getTexture())
{
double realTime = RBX::Time::nowFastSec();
if( visualEngine->getSettings()->getEagerBulkExecution() )
{
markDirty(true);
}
else if (fabs(envmapLastTimeOfDay - gameTime ) > kEnvmapGameTimePeriod || fabs(envmapLastRealTime - realTime) > kEnvmapRealtimePeriod) // extra refresh at midnight - who cares
{
envmapLastTimeOfDay = gameTime;
envmapLastRealTime = realTime;
markDirty();
}
switch (dirtyState)
{
case VeryDirty:
fullUpdate(context);
break;
case DirtyWait:
if (visualEngine->getSceneManager()->getSky()->isReady())
{
fullUpdate(context);
}
break;
case Dirty:
case BusyDirty:
incrementalUpdate(context);
break;
default:
break;
}
}
}
void EnvMap::markDirty(bool veryDirty)
{
if( veryDirty )
{
dirtyState = DirtyWait;
}
else switch (dirtyState)
{
case VeryDirty: case DirtyWait: break;
case Dirty: dirtyState = BusyDirty; break;
case BusyDirty: break;
default: dirtyState = Dirty; break;
}
}
void EnvMap::clearDirty()
{
switch (dirtyState)
{
case Dirty:
dirtyState = Ready;
break;
case BusyDirty:
dirtyState = Dirty;
break;
case VeryDirty:
case DirtyWait:
if (visualEngine->getSceneManager()->getSky()->isReady())
dirtyState = Ready;
else
dirtyState = DirtyWait;
break;
default:
break;
}
}
void EnvMap::incrementalUpdate(DeviceContext* context)
{
if (!texture.getTexture())
return;
if (dirtyState == Ready)
return;
if (updateStep>=7)
{
updateStep = 0;
clearDirty();
return;
}
if (updateStep<6)
renderFace(context,updateStep);
else if (updateStep == 6)
texture.getTexture()->generateMipmaps();
updateStep++;
}
// full re-render in a single frame
void EnvMap::fullUpdate(DeviceContext* context)
{
/*
while( !visualEngine->getSceneManager()->getSky()->isReady() )
{
visualEngine->getSceneManager()->getSky()->setSkyBoxDefault();
visualEngine->getSceneManager()->getSky()->prerender(context);
Sleep(100);
}
*/
if (!texture.getTexture())
return;
for (int j=0; j<6; ++j)
renderFace(context,j);
texture.getTexture()->generateMipmaps();
updateStep = 0;
clearDirty();
}
void EnvMap::renderFace(DeviceContext* context, int face)
{
PIX_SCOPE(context, "EnvMap/update", 0);
SceneManager* sman = visualEngine->getSceneManager();
static int isOgl = 6*visualEngine->getDevice()->getCaps().requiresRenderTargetFlipping;
// THIS IS A HACK!
static Matrix4 view[6*2] = {
lookat(Vector3(-1,0,0), Vector3(0,1,0), -1),
lookat(Vector3(1,0,0), Vector3(0,1,0), -1),
lookat(Vector3(0,-1,0), Vector3(0,0,-1), -1),
lookat(Vector3(0,1,0), Vector3(0,0,1), -1),
lookat(Vector3(0,0,-1), Vector3(0,1,0), -1),
lookat(Vector3(0,0,1), Vector3(0,1,0), -1),
lookat(Vector3(-1,0,0), Vector3(0,-1,0)),
lookat(Vector3(1,0,0), Vector3(0,-1,0)),
lookat(Vector3(0,-1,0), Vector3(0,0,1)),
lookat(Vector3(0,1,0), Vector3(0,0,-1)),
lookat(Vector3(0,0,-1), Vector3(0,-1,0)),
lookat(Vector3(0,0,1), Vector3(0,-1,0)),
};
if (1)
{
PIX_SCOPE(context, "EnvMap face %d", face);
RenderCamera cam;
cam.setViewMatrix(view[isOgl + face]);
cam.setProjectionPerspective(MATH_PI/2, 1, 0.5, 3000);
GlobalShaderData globsd = sman->readGlobalShaderData();
globsd.setCamera(cam);
context->updateGlobalConstants(&globsd,sizeof(globsd));
context->bindFramebuffer(fbFaces[face].get());
visualEngine->getSceneManager()->getSky()->render(context, cam, false);
// add more stuff to render to envmap
}
}
void EnvMap::onDeviceRestored()
{
markDirty(true);
}
}}