Some Linux compile fixes over the place.
Create TerrainRenderer, ShadowMap and WaterManager classes to divide CRenderer's functions into more logical units. This was SVN commit r3332.
This commit is contained in:
parent
1c43192f2d
commit
b889826a3d
@ -15,6 +15,8 @@
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include "CStr.h"
|
||||
#include "NUSpline.h"
|
||||
|
||||
/*
|
||||
@ -32,7 +34,6 @@
|
||||
class CVector3D;
|
||||
class CVector4D;
|
||||
class CCamera;
|
||||
class CStr;
|
||||
|
||||
//For loading data
|
||||
class CCinemaData
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "Profile.h"
|
||||
#include "ps/LoaderThunks.h"
|
||||
#include "ps/Globals.h"
|
||||
#include "renderer/WaterManager.h"
|
||||
|
||||
#include "Quaternion.h"
|
||||
#include "Unit.h"
|
||||
@ -80,7 +81,7 @@ CGameView::CGameView(CGame *pGame):
|
||||
|
||||
m_UnitView=NULL;
|
||||
m_UnitAttach=NULL;
|
||||
|
||||
|
||||
|
||||
ONCE( ScriptingInit(); );
|
||||
}
|
||||
@ -135,7 +136,7 @@ void CGameView::RegisterInit(CGameAttributes *pAttribs)
|
||||
RegMemFun(g_TexMan.GetSingletonPtr(), &CTextureManager::LoadTerrainTextures, L"LoadTerrainTextures", 15);
|
||||
RegMemFun(g_ObjMan.GetSingletonPtr(), &CObjectManager::LoadObjects, L"LoadObjects", 1);
|
||||
RegMemFun(g_Renderer.GetSingletonPtr(), &CRenderer::LoadAlphaMaps, L"LoadAlphaMaps", 45);
|
||||
RegMemFun(g_Renderer.GetSingletonPtr(), &CRenderer::LoadWaterTextures, L"LoadWaterTextures", 600);
|
||||
RegMemFun(g_Renderer.GetSingletonPtr()->GetWaterManager(), &WaterManager::LoadWaterTextures, L"LoadWaterTextures", 600);
|
||||
}
|
||||
|
||||
|
||||
@ -173,15 +174,15 @@ void CGameView::RenderModels(CUnitManager *pUnitMan, CProjectileManager *pProjec
|
||||
CLOSManager* losMgr = m_pWorld->GetLOSManager();
|
||||
|
||||
const std::vector<CUnit*>& units=pUnitMan->GetUnits();
|
||||
for (uint i=0;i<units.size();++i)
|
||||
for (uint i=0;i<units.size();++i)
|
||||
{
|
||||
int status = losMgr->GetUnitStatus(units[i], g_Game->GetLocalPlayer());
|
||||
CModel* model = units[i]->GetModel();
|
||||
|
||||
|
||||
model->ValidatePosition();
|
||||
|
||||
|
||||
if (frustum.IsBoxVisible(CVector3D(0,0,0), model->GetBounds())
|
||||
&& status != UNIT_HIDDEN)
|
||||
&& status != UNIT_HIDDEN)
|
||||
{
|
||||
if(units[i] != g_BuildingPlacer.m_actor)
|
||||
{
|
||||
@ -203,18 +204,18 @@ void CGameView::RenderModels(CUnitManager *pUnitMan, CProjectileManager *pProjec
|
||||
}
|
||||
|
||||
const std::vector<CProjectile*>& projectiles=pProjectileMan->GetProjectiles();
|
||||
for (uint i=0;i<projectiles.size();++i)
|
||||
for (uint i=0;i<projectiles.size();++i)
|
||||
{
|
||||
CModel* model = projectiles[i]->GetModel();
|
||||
|
||||
|
||||
model->ValidatePosition();
|
||||
|
||||
|
||||
const CBound& bound = model->GetBounds();
|
||||
CVector3D centre;
|
||||
bound.GetCentre(centre);
|
||||
|
||||
|
||||
if (frustum.IsBoxVisible(CVector3D(0,0,0), bound)
|
||||
&& losMgr->GetStatus(centre.X, centre.Z, g_Game->GetLocalPlayer()) & LOS_VISIBLE)
|
||||
&& losMgr->GetStatus(centre.X, centre.Z, g_Game->GetLocalPlayer()) & LOS_VISIBLE)
|
||||
{
|
||||
PROFILE( "submit projectiles" );
|
||||
SubmitModelRecursive(projectiles[i]->GetModel());
|
||||
@ -222,13 +223,13 @@ void CGameView::RenderModels(CUnitManager *pUnitMan, CProjectileManager *pProjec
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//locks the camera in place
|
||||
void CGameView::CameraLock(CVector3D Trans, bool smooth)
|
||||
{
|
||||
m_Terrain=g_Game->GetWorld()->GetTerrain();
|
||||
float height=m_Terrain->getExactGroundLevel(
|
||||
m_Camera.m_Orientation._14 + Trans.X, m_Camera.m_Orientation._34 + Trans.Z) +
|
||||
m_Camera.m_Orientation._14 + Trans.X, m_Camera.m_Orientation._34 + Trans.Z) +
|
||||
g_YMinOffset;
|
||||
//is requested position within limits?
|
||||
if (m_Camera.m_Orientation._24 + Trans.Y <= g_MaxZoomHeight)
|
||||
@ -244,14 +245,14 @@ void CGameView::CameraLock(CVector3D Trans, bool smooth)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGameView::CameraLock(float x, float y, float z, bool smooth)
|
||||
{
|
||||
m_Terrain=g_Game->GetWorld()->GetTerrain();
|
||||
float height=m_Terrain->getExactGroundLevel(
|
||||
m_Camera.m_Orientation._14 + x, m_Camera.m_Orientation._34 + z) +
|
||||
m_Camera.m_Orientation._14 + x, m_Camera.m_Orientation._34 + z) +
|
||||
g_YMinOffset;
|
||||
//is requested position within limits?
|
||||
if (m_Camera.m_Orientation._24 + y <= g_MaxZoomHeight)
|
||||
@ -269,8 +270,8 @@ void CGameView::CameraLock(float x, float y, float z, bool smooth)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void CGameView::SubmitModelRecursive(CModel* model)
|
||||
{
|
||||
g_Renderer.Submit(model);
|
||||
@ -309,7 +310,7 @@ void CGameView::UnloadResources()
|
||||
g_ObjMan.UnloadObjects();
|
||||
g_TexMan.UnloadTerrainTextures();
|
||||
g_Renderer.UnloadAlphaMaps();
|
||||
g_Renderer.UnloadWaterTextures();
|
||||
g_Renderer.GetWaterManager()->UnloadWaterTextures();
|
||||
}
|
||||
|
||||
|
||||
@ -335,7 +336,7 @@ void CGameView::ResetCameraOrientation()
|
||||
m_Camera.SetProjection (1, 5000, DEGTORAD(20));
|
||||
m_Camera.m_Orientation.SetXRotation(DEGTORAD(30));
|
||||
m_Camera.m_Orientation.RotateY(DEGTORAD(-45));
|
||||
|
||||
|
||||
target += CVector3D( 100.0f, 150.0f, -100.0f );
|
||||
|
||||
m_Camera.m_Orientation.Translate( target );
|
||||
@ -350,7 +351,7 @@ void CGameView::Update(float DeltaTime)
|
||||
{
|
||||
if (!g_app_has_focus)
|
||||
return;
|
||||
|
||||
|
||||
if (m_UnitView)
|
||||
{
|
||||
// CQuaternion ToRotate = m_UnitViewProp->m_Rotation - m_Camera.m_Orientation.GetRotation();
|
||||
@ -367,20 +368,20 @@ void CGameView::Update(float DeltaTime)
|
||||
/*if( !m_UnitView->m_orderQueue.empty())
|
||||
{
|
||||
CEntityOrder Order = m_UnitView->m_orderQueue.front();
|
||||
|
||||
if (Order.m_type == CEntityOrder::ORDER_ATTACK_MELEE_NOPATHING ||
|
||||
|
||||
if (Order.m_type == CEntityOrder::ORDER_ATTACK_MELEE_NOPATHING ||
|
||||
Order.m_type == CEntityOrder::ORDER_GATHER_NOPATHING)
|
||||
{
|
||||
CVector3D Focus = m_Camera.GetFocus();
|
||||
CVector3D Target;
|
||||
Target.X = (float) Order.m_data[0].location.x;
|
||||
Target.Y = (float) m_Terrain->getExactGroundLevel(
|
||||
Target.Y = (float) m_Terrain->getExactGroundLevel(
|
||||
Order.m_data[0].location.x, Order.m_data[0].location.y );
|
||||
Target.Z = (float) Order.m_data[0].location.y;
|
||||
|
||||
|
||||
CVector3D Distance = Target - Focus;
|
||||
float length = Distance.GetLength();
|
||||
|
||||
|
||||
//We're looking too far out. Correct by moving up or down toward the true position.
|
||||
if (length > 1.0f)
|
||||
{
|
||||
@ -388,9 +389,9 @@ void CGameView::Update(float DeltaTime)
|
||||
CVector3D Down(0.0f, -1.0f, 0.0f);
|
||||
//Find opposite side's length
|
||||
float Angle = tan( acosf(Distance.Dot(Down)) );
|
||||
float opp = length * Angle;
|
||||
float hyp = 1 / sinf(Angle) * opp;
|
||||
|
||||
float opp = length * Angle;
|
||||
float hyp = 1 / sinf(Angle) * opp;
|
||||
|
||||
CVector3D CamFace = m_Camera.m_Orientation.GetIn();
|
||||
CVector3D ToFace = Target - m_Camera.m_Orientation.GetTranslation();
|
||||
ToFace.Normalize();
|
||||
@ -405,11 +406,11 @@ void CGameView::Update(float DeltaTime)
|
||||
} //Check order type
|
||||
} //Is order queue empty?
|
||||
*/
|
||||
|
||||
|
||||
m_Camera.UpdateFrustum();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (m_UnitAttach)
|
||||
{
|
||||
CVector3D ToMove = m_UnitAttach->m_position - m_Camera.GetFocus();
|
||||
@ -418,7 +419,7 @@ void CGameView::Update(float DeltaTime)
|
||||
m_Camera.UpdateFrustum();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!m_TrackManager.m_TrackQueue.empty())
|
||||
{
|
||||
if(!m_TrackManager.Update(DeltaTime))
|
||||
@ -428,7 +429,7 @@ void CGameView::Update(float DeltaTime)
|
||||
m_Camera.UpdateFrustum();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
float delta = powf( m_ViewSnapSmoothness, DeltaTime );
|
||||
m_Camera.m_Orientation.Translate( m_CameraDelta * ( 1.0f - delta ) );
|
||||
m_CameraDelta *= delta;
|
||||
@ -451,7 +452,7 @@ void CGameView::Update(float DeltaTime)
|
||||
CVector3D rightwards = m_Camera.m_Orientation.GetLeft() * -1.0f; // upwards.Cross(forwards);
|
||||
CVector3D upwards( 0.0f, 1.0f, 0.0f );
|
||||
// rightwards.Normalize();
|
||||
|
||||
|
||||
CVector3D forwards_horizontal = forwards;
|
||||
forwards_horizontal.Y = 0.0f;
|
||||
forwards_horizontal.Normalize();
|
||||
@ -465,7 +466,7 @@ void CGameView::Update(float DeltaTime)
|
||||
m_Camera.m_Orientation.Translate(position*-1);
|
||||
|
||||
// Sideways rotation
|
||||
|
||||
|
||||
float rightways = 0.0f;
|
||||
if( hotkeys[HOTKEY_CAMERA_ROTATE] )
|
||||
rightways = (float)mouse_dx * m_ViewRotateSensitivity;
|
||||
@ -494,7 +495,7 @@ void CGameView::Update(float DeltaTime)
|
||||
|
||||
CQuaternion temp;
|
||||
temp.FromAxisAngle(rightwards, upways);
|
||||
|
||||
|
||||
m_Camera.m_Orientation.Rotate(temp);
|
||||
|
||||
// Retranslate back to the right position
|
||||
@ -505,13 +506,13 @@ void CGameView::Update(float DeltaTime)
|
||||
{
|
||||
CVector3D origin = m_Camera.m_Orientation.GetTranslation();
|
||||
CVector3D delta = origin - m_CameraPivot;
|
||||
|
||||
|
||||
CQuaternion rotateH, rotateV; CMatrix3D rotateM;
|
||||
|
||||
// Sideways rotation
|
||||
|
||||
|
||||
float rightways = (float)mouse_dx * m_ViewRotateAboutTargetSensitivity;
|
||||
|
||||
|
||||
rotateH.FromAxisAngle( upwards, rightways );
|
||||
|
||||
// Up/down rotation
|
||||
@ -527,7 +528,7 @@ void CGameView::Update(float DeltaTime)
|
||||
// Lock the inclination to a rather arbitrary values (for the sake of graphical decency)
|
||||
|
||||
float scan = sqrt( delta.X * delta.X + delta.Z * delta.Z ) / delta.Y;
|
||||
if( ( scan >= 0.5f ) )
|
||||
if( ( scan >= 0.5f ) )
|
||||
{
|
||||
// Move the camera to the origin (in preparation for rotation )
|
||||
m_Camera.m_Orientation.Translate( origin * -1.0f );
|
||||
@ -537,7 +538,7 @@ void CGameView::Update(float DeltaTime)
|
||||
// Move the camera back to where it belongs
|
||||
m_Camera.m_Orientation.Translate( m_CameraPivot + delta );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if( hotkeys[HOTKEY_CAMERA_ROTATE_ABOUT_TARGET_KEYBOARD] )
|
||||
{
|
||||
@ -545,17 +546,17 @@ void CGameView::Update(float DeltaTime)
|
||||
CVector3D origin = m_Camera.m_Orientation.GetTranslation();
|
||||
CVector3D pivot = m_Camera.GetFocus();
|
||||
CVector3D delta = origin - pivot;
|
||||
|
||||
|
||||
CQuaternion rotateH, rotateV; CMatrix3D rotateM;
|
||||
|
||||
// Sideways rotation
|
||||
|
||||
|
||||
float rightways = 0.0f;
|
||||
if( hotkeys[HOTKEY_CAMERA_LEFT] )
|
||||
rightways -= m_ViewRotateAboutTargetSensitivityKeyboard * DeltaTime;
|
||||
if( hotkeys[HOTKEY_CAMERA_RIGHT] )
|
||||
rightways += m_ViewRotateAboutTargetSensitivityKeyboard * DeltaTime;
|
||||
|
||||
|
||||
rotateH.FromAxisAngle( upwards, rightways );
|
||||
|
||||
// Up/down rotation
|
||||
@ -565,7 +566,7 @@ void CGameView::Update(float DeltaTime)
|
||||
upways -= m_ViewRotateAboutTargetSensitivityKeyboard * DeltaTime;
|
||||
if( hotkeys[HOTKEY_CAMERA_DOWN] )
|
||||
upways += m_ViewRotateAboutTargetSensitivityKeyboard * DeltaTime;
|
||||
|
||||
|
||||
rotateV.FromAxisAngle( rightwards, upways );
|
||||
|
||||
rotateH *= rotateV;
|
||||
@ -576,7 +577,7 @@ void CGameView::Update(float DeltaTime)
|
||||
// Lock the inclination to a rather arbitrary values (for the sake of graphical decency)
|
||||
|
||||
float scan = sqrt( delta.X * delta.X + delta.Z * delta.Z ) / delta.Y;
|
||||
if( ( scan >= 0.5f ) )
|
||||
if( ( scan >= 0.5f ) )
|
||||
{
|
||||
// Move the camera to the origin (in preparation for rotation )
|
||||
m_Camera.m_Orientation.Translate( origin * -1.0f );
|
||||
@ -586,7 +587,7 @@ void CGameView::Update(float DeltaTime)
|
||||
// Move the camera back to where it belongs
|
||||
m_Camera.m_Orientation.Translate( pivot + delta );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if( hotkeys[HOTKEY_CAMERA_PAN] )
|
||||
{
|
||||
@ -595,15 +596,15 @@ void CGameView::Update(float DeltaTime)
|
||||
CameraLock(rightwards * (m_ViewDragSensitivity * mouse_dx));
|
||||
CameraLock(forwards_horizontal * (-m_ViewDragSensitivity * mouse_dy));
|
||||
}
|
||||
|
||||
|
||||
// Mouse movement
|
||||
if( !hotkeys[HOTKEY_CAMERA_ROTATE] && !hotkeys[HOTKEY_CAMERA_ROTATE_ABOUT_TARGET] )
|
||||
{
|
||||
if (g_mouse_x >= g_xres-2 && g_mouse_x < g_xres)
|
||||
CameraLock(rightwards * (m_ViewScrollSpeed * DeltaTime));
|
||||
CameraLock(rightwards * (m_ViewScrollSpeed * DeltaTime));
|
||||
else if (g_mouse_x <= 3 && g_mouse_x >= 0)
|
||||
CameraLock(-rightwards * (m_ViewScrollSpeed * DeltaTime));
|
||||
|
||||
|
||||
if (g_mouse_y >= g_yres-2 && g_mouse_y < g_yres)
|
||||
CameraLock(-forwards_horizontal * (m_ViewScrollSpeed * DeltaTime));
|
||||
else if (g_mouse_y <= 3 && g_mouse_y >= 0)
|
||||
@ -619,7 +620,7 @@ void CGameView::Update(float DeltaTime)
|
||||
CameraLock(rightwards * (m_ViewScrollSpeed * DeltaTime));
|
||||
if( hotkeys[HOTKEY_CAMERA_LEFT] )
|
||||
CameraLock(-rightwards * (m_ViewScrollSpeed * DeltaTime));
|
||||
|
||||
|
||||
if( hotkeys[HOTKEY_CAMERA_DOWN] )
|
||||
CameraLock(-forwards_horizontal * (m_ViewScrollSpeed * DeltaTime));
|
||||
if( hotkeys[HOTKEY_CAMERA_UP] )
|
||||
@ -645,8 +646,8 @@ void CGameView::Update(float DeltaTime)
|
||||
m_Camera.UpdateFrustum ();
|
||||
}
|
||||
|
||||
void CGameView::ToUnitView(CEntity* target, CModel* prop)
|
||||
{
|
||||
void CGameView::ToUnitView(CEntity* target, CModel* prop)
|
||||
{
|
||||
if( !target )
|
||||
{
|
||||
//prevent previous zooming
|
||||
@ -654,7 +655,7 @@ void CGameView::ToUnitView(CEntity* target, CModel* prop)
|
||||
ResetCamera();
|
||||
SetCameraTarget( m_UnitView->m_position );
|
||||
}
|
||||
m_UnitView = target;
|
||||
m_UnitView = target;
|
||||
m_UnitViewProp = prop;
|
||||
|
||||
}
|
||||
@ -739,11 +740,11 @@ InReaction CGameView::HandleEvent(const SDL_Event* ev)
|
||||
case HOTKEY_CAMERA_ZOOM_WHEEL_IN:
|
||||
m_ZoomDelta += m_ViewZoomSensitivityWheel;
|
||||
return( IN_HANDLED );
|
||||
|
||||
|
||||
case HOTKEY_CAMERA_ZOOM_WHEEL_OUT:
|
||||
m_ZoomDelta -= m_ViewZoomSensitivityWheel;
|
||||
return( IN_HANDLED );
|
||||
|
||||
|
||||
default:
|
||||
|
||||
if( ( ev->user.code >= HOTKEY_CAMERA_BOOKMARK_0 ) && ( ev->user.code <= HOTKEY_CAMERA_BOOKMARK_9 ) )
|
||||
@ -793,7 +794,7 @@ InReaction CGameView::HandleEvent(const SDL_Event* ev)
|
||||
bool CGameView::JSI_StartCustomSelection(
|
||||
JSContext* UNUSED(context), uint UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
StartCustomSelection();
|
||||
StartCustomSelection();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include "Profile.h"
|
||||
#include "LOSManager.h"
|
||||
#include "graphics/GameView.h"
|
||||
|
||||
#include "renderer/WaterManager.h"
|
||||
|
||||
|
||||
bool g_TerrainModified = false;
|
||||
@ -81,11 +81,11 @@ void CMiniMap::HandleMessage(const SGUIMessage &Message)
|
||||
m_Camera->m_Orientation._14+=TransVector.X;
|
||||
m_Camera->m_Orientation._34+=TransVector.Z;
|
||||
|
||||
//Lock Y coord. No risk of zoom exceeding limit-Y does not increase
|
||||
//Lock Y coord. No risk of zoom exceeding limit-Y does not increase
|
||||
float Height=MMTerrain->getExactGroundLevel(
|
||||
m_Camera->m_Orientation._14, m_Camera->m_Orientation._34) + g_YMinOffset;
|
||||
|
||||
if (m_Camera->m_Orientation._24 < Height)
|
||||
if (m_Camera->m_Orientation._24 < Height)
|
||||
{
|
||||
m_Camera->m_Orientation._24=Height;
|
||||
}
|
||||
@ -103,7 +103,7 @@ void CMiniMap::HandleMessage(const SGUIMessage &Message)
|
||||
// which represents the view of the camera in the world.
|
||||
void CMiniMap::DrawViewRect()
|
||||
{
|
||||
// Get correct world coordinates based off corner of screen start
|
||||
// Get correct world coordinates based off corner of screen start
|
||||
// at Bottom Left and going CW
|
||||
CVector3D hitPt[4];
|
||||
hitPt[0]=m_Camera->GetWorldCoordinates(0,g_Renderer.GetHeight());
|
||||
@ -150,7 +150,7 @@ void CMiniMap::Draw()
|
||||
// happens when the game is started, so abort until then.
|
||||
if(!(GetGUI() && g_Game && g_Game->IsGameStarted()))
|
||||
return;
|
||||
|
||||
|
||||
// Set our globals in case they hadn't been set before
|
||||
m_Camera = g_Game->GetView()->GetCamera();
|
||||
m_Terrain = g_Game->GetWorld()->GetTerrain();
|
||||
@ -271,7 +271,7 @@ void CMiniMap::Draw()
|
||||
glEnd();
|
||||
|
||||
DrawViewRect();
|
||||
|
||||
|
||||
// Reset everything back to normal
|
||||
glPointSize(1.0f);
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
@ -315,6 +315,7 @@ void CMiniMap::RebuildTerrainTexture()
|
||||
u32 y = 0;
|
||||
u32 w = m_MapSize - 1;
|
||||
u32 h = m_MapSize - 1;
|
||||
float waterHeight = g_Renderer.GetWaterManager()->m_WaterHeight;
|
||||
|
||||
for(u32 j = 0; j < h; j++)
|
||||
{
|
||||
@ -327,7 +328,7 @@ void CMiniMap::RebuildTerrainTexture()
|
||||
+ m_Terrain->getVertexGroundLevel((int)i+1, (int)j+1)
|
||||
) / 4.0f;
|
||||
|
||||
if(avgHeight < g_Renderer.m_WaterHeight)
|
||||
if(avgHeight < waterHeight)
|
||||
{
|
||||
*dataPtr++ = 0xff304080; // TODO: perhaps use the renderer's water color?
|
||||
}
|
||||
|
@ -351,10 +351,6 @@ LibError ogl_get_gfx_info()
|
||||
}
|
||||
|
||||
|
||||
static void __stdcall emu_glDrawRangeElementsEXT(GLenum, GLuint, GLuint, GLsizei, GLenum, GLvoid*)
|
||||
{
|
||||
}
|
||||
|
||||
// call after each video mode change, since thereafter extension functions
|
||||
// may have changed [address].
|
||||
void oglInit()
|
||||
@ -372,9 +368,6 @@ void oglInit()
|
||||
|
||||
importExtensionFunctions();
|
||||
|
||||
if(!pglDrawRangeElementsEXT)
|
||||
pglDrawRangeElementsEXT = emu_glDrawRangeElementsEXT;
|
||||
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &ogl_max_tex_size);
|
||||
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &ogl_max_tex_units);
|
||||
}
|
||||
|
@ -25,6 +25,17 @@ inline T clamp(T value, T min, T max)
|
||||
else return value;
|
||||
}
|
||||
|
||||
static inline int RoundUpToPowerOf2(int x)
|
||||
{
|
||||
if ((x & (x-1))==0) return x;
|
||||
int d=x;
|
||||
while (d & (d-1)) {
|
||||
d&=(d-1);
|
||||
}
|
||||
return d<<1;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
/*
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include "Precompiled.h"
|
||||
#include "precompiled.h"
|
||||
#include "NUSpline.h"
|
||||
#include "Matrix3D.h"
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
//Desc: Contains classes for smooth splines
|
||||
//Borrowed from Game Programming Gems4. (Slightly changed to better suit our purposes
|
||||
//(and compatability). Any references to external material can be found there
|
||||
|
||||
#ifndef NUSPLINE_H
|
||||
#define NUSPLINE_H
|
||||
|
||||
#define MAX_SPLINE_NODES 30
|
||||
#include <stdlib.h>
|
||||
#include "Vector3D.h"
|
||||
@ -47,4 +51,6 @@ public:
|
||||
void BuildSpline(){ RNSpline::BuildSpline(); Smooth(); Smooth(); Smooth(); }
|
||||
void Smooth(){ SNSpline::Smooth(); Constrain(); }
|
||||
void Constrain();
|
||||
};
|
||||
};
|
||||
|
||||
#endif // NUSPLINE_H
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "graphics/MaterialManager.h"
|
||||
#include "graphics/MeshManager.h"
|
||||
#include "renderer/Renderer.h"
|
||||
#include "renderer/VertexBufferManager.h"
|
||||
#include "maths/MathUtil.h"
|
||||
|
||||
#include "simulation/BaseEntityCollection.h"
|
||||
|
@ -6,17 +6,13 @@
|
||||
#include "Pyrogenesis.h"
|
||||
#include "lib/res/graphics/ogl_tex.h"
|
||||
#include "Renderer.h"
|
||||
#include "PatchRData.h"
|
||||
#include "renderer/PatchRData.h"
|
||||
#include "AlphaMapCalculator.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Profile.h"
|
||||
#include "MathUtil.h"
|
||||
#include "LOSManager.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// shared list of all submitted patches this frame
|
||||
std::vector<CPatch*> CPatchRData::m_Patches;
|
||||
|
||||
|
||||
const int BlendOffsets[8][2] = {
|
||||
{ 0, -1 },
|
||||
@ -397,7 +393,7 @@ void CPatchRData::BuildVertices()
|
||||
// upload to vertex buffer
|
||||
if (!m_VBBase) {
|
||||
m_VBBase=g_VBMan.Allocate(sizeof(SBaseVertex),vsize*vsize,true);
|
||||
}
|
||||
}
|
||||
m_VBBase->m_Owner->UpdateChunkVertices(m_VBBase,m_Vertices);
|
||||
}
|
||||
|
||||
@ -557,22 +553,6 @@ void CPatchRData::RenderBlends()
|
||||
}
|
||||
}
|
||||
|
||||
void CPatchRData::RenderOutlines()
|
||||
{
|
||||
for (uint i=0;i<m_Patches.size();++i) {
|
||||
CPatchRData* patchdata=(CPatchRData*) m_Patches[i]->GetRenderData();
|
||||
patchdata->RenderOutline();
|
||||
}
|
||||
}
|
||||
|
||||
void CPatchRData::RenderStreamsAll(u32 streamflags)
|
||||
{
|
||||
for (uint i=0;i<m_Patches.size();++i) {
|
||||
CPatchRData* patchdata=(CPatchRData*) m_Patches[i]->GetRenderData();
|
||||
patchdata->RenderStreams(streamflags);
|
||||
}
|
||||
}
|
||||
|
||||
void CPatchRData::RenderOutline()
|
||||
{
|
||||
int i;
|
||||
@ -606,285 +586,4 @@ void CPatchRData::RenderOutline()
|
||||
glEnd();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SubmitBaseBatches: submit base batches for this patch to the vertex buffer
|
||||
void CPatchRData::SubmitBaseBatches()
|
||||
{
|
||||
debug_assert(m_VBBase);
|
||||
|
||||
for (uint i=0;i<m_Splats.size();i++) {
|
||||
const SSplat& splat=m_Splats[i];
|
||||
m_VBBase->m_Owner->AppendBatch(m_VBBase,splat.m_Texture,splat.m_IndexCount,&m_Indices[splat.m_IndexStart]);
|
||||
}
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SubmitBlendBatches: submit next set of blend batches for this patch to the vertex buffer;
|
||||
void CPatchRData::SubmitBlendBatches()
|
||||
{
|
||||
for (uint i=0;i<m_BlendSplats.size();i++) {
|
||||
const SSplat& splat=m_BlendSplats[i];
|
||||
m_VBBlends->m_Owner->AppendBatch(m_VBBlends, splat.m_Texture, splat.m_IndexCount, &m_BlendIndices[splat.m_IndexStart]);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RenderBaseSplats: render all base passes of all patches; assumes vertex, texture and color
|
||||
// client states are enabled
|
||||
void CPatchRData::RenderBaseSplats()
|
||||
{
|
||||
uint i;
|
||||
|
||||
// set up texture environment for base pass
|
||||
MICROLOG(L"base splat textures");
|
||||
pglActiveTextureARB(GL_TEXTURE0);
|
||||
pglClientActiveTextureARB(GL_TEXTURE0);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
|
||||
|
||||
// Set alpha to 1.0
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_CONSTANT);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
||||
float one[4] = { 1.f, 1.f, 1.f, 1.f };
|
||||
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, one);
|
||||
|
||||
#if 1
|
||||
// submit base batches for each patch to the vertex buffer
|
||||
for (i=0;i<m_Patches.size();++i) {
|
||||
CPatchRData* patchdata=(CPatchRData*) m_Patches[i]->GetRenderData();
|
||||
patchdata->SubmitBaseBatches();
|
||||
}
|
||||
|
||||
// render base passes for each patch
|
||||
const std::list<CVertexBuffer*>& buffers=g_VBMan.GetBufferList();
|
||||
std::list<CVertexBuffer*>::const_iterator iter;
|
||||
for (iter=buffers.begin();iter!=buffers.end();++iter) {
|
||||
CVertexBuffer* buffer=*iter;
|
||||
|
||||
// any batches in this VB?
|
||||
const std::vector<CVertexBuffer::Batch*>& batches=buffer->GetBatches();
|
||||
if (batches.size()>0) {
|
||||
u8* base=buffer->Bind();
|
||||
|
||||
// setup data pointers
|
||||
u32 stride=sizeof(SBaseVertex);
|
||||
|
||||
glVertexPointer(3,GL_FLOAT,stride,base+offsetof(SBaseVertex,m_Position));
|
||||
glColorPointer(4,GL_UNSIGNED_BYTE,stride,base+offsetof(SBaseVertex,m_Color));
|
||||
glTexCoordPointer(2,GL_FLOAT,stride,base+offsetof(SBaseVertex,m_UVs[0]));
|
||||
|
||||
// render each batch
|
||||
for (i=0;i<batches.size();++i) {
|
||||
const CVertexBuffer::Batch* batch=batches[i];
|
||||
if (batch->m_IndexData.size()>0) {
|
||||
ogl_tex_bind(batch->m_Texture);
|
||||
for (uint j=0;j<batch->m_IndexData.size();j++) {
|
||||
glDrawElements(GL_QUADS, (GLsizei)batch->m_IndexData[j].first, GL_UNSIGNED_SHORT, batch->m_IndexData[j].second);
|
||||
g_Renderer.m_Stats.m_DrawCalls++;
|
||||
g_Renderer.m_Stats.m_TerrainTris+=(u32)batch->m_IndexData[j].first/2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// everything rendered; empty out batch lists
|
||||
MICROLOG(L"clear");
|
||||
g_VBMan.ClearBatchIndices();
|
||||
#else
|
||||
for (i=0;i<m_Patches.size();++i) {
|
||||
CPatchRData* patchdata=(CPatchRData*) m_Patches[i]->GetRenderData();
|
||||
patchdata->RenderBase();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RenderBlendSplats: render all blend passes of all patches; assumes vertex, texture and color
|
||||
// client states are enabled
|
||||
void CPatchRData::RenderBlendSplats()
|
||||
{
|
||||
uint i;
|
||||
|
||||
// switch on the composite alpha map texture
|
||||
(void)ogl_tex_bind(g_Renderer.m_hCompositeAlphaMap, 1);
|
||||
|
||||
// switch on second uv set
|
||||
pglClientActiveTextureARB(GL_TEXTURE1);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
// setup additional texenv required by blend pass
|
||||
pglActiveTextureARB(GL_TEXTURE1);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// switch on blending
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// no need to write to the depth buffer a second time
|
||||
glDepthMask(0);
|
||||
|
||||
#if 1
|
||||
// submit blend batches for each patch to the vertex buffer
|
||||
for (i=0;i<m_Patches.size();++i) {
|
||||
CPatchRData* patchdata=(CPatchRData*) m_Patches[i]->GetRenderData();
|
||||
patchdata->SubmitBlendBatches();
|
||||
}
|
||||
|
||||
// render blend passes for each patch
|
||||
const std::list<CVertexBuffer*>& buffers=g_VBMan.GetBufferList();
|
||||
std::list<CVertexBuffer*>::const_iterator iter;
|
||||
for (iter=buffers.begin();iter!=buffers.end();++iter) {
|
||||
CVertexBuffer* buffer=*iter;
|
||||
|
||||
// any batches in this VB?
|
||||
const std::vector<CVertexBuffer::Batch*>& batches=buffer->GetBatches();
|
||||
if (batches.size()>0) {
|
||||
u8* base=buffer->Bind();
|
||||
|
||||
// setup data pointers
|
||||
u32 stride=sizeof(SBlendVertex);
|
||||
glVertexPointer(3,GL_FLOAT,stride,base+offsetof(SBlendVertex,m_Position));
|
||||
glColorPointer(4,GL_UNSIGNED_BYTE,stride,base+offsetof(SBlendVertex,m_Color));
|
||||
|
||||
pglClientActiveTextureARB(GL_TEXTURE1);
|
||||
glTexCoordPointer(2,GL_FLOAT,stride,base+offsetof(SBlendVertex,m_AlphaUVs[0]));
|
||||
|
||||
pglClientActiveTextureARB(GL_TEXTURE0);
|
||||
glTexCoordPointer(2,GL_FLOAT,stride,base+offsetof(SBlendVertex,m_UVs[0]));
|
||||
|
||||
// render each batch
|
||||
for (i=0;i<batches.size();++i) {
|
||||
const CVertexBuffer::Batch* batch=batches[i];
|
||||
if (batch->m_IndexData.size()>0) {
|
||||
ogl_tex_bind(batch->m_Texture);
|
||||
for (uint j = 0; j < batch->m_IndexData.size(); j++) {
|
||||
glDrawElements(GL_QUADS, (GLsizei)batch->m_IndexData[j].first, GL_UNSIGNED_SHORT, batch->m_IndexData[j].second);
|
||||
g_Renderer.m_Stats.m_DrawCalls++;
|
||||
g_Renderer.m_Stats.m_TerrainTris+=(u32)batch->m_IndexData[j].first/2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// everything rendered; empty out batch lists
|
||||
g_VBMan.ClearBatchIndices();
|
||||
#else
|
||||
// render blend passes for each patch
|
||||
for (i=0;i<m_Patches.size();++i) {
|
||||
CPatchRData* patchdata=(CPatchRData*) m_Patches[i]->GetRenderData();
|
||||
patchdata->RenderBlends();
|
||||
}
|
||||
#endif
|
||||
|
||||
// restore depth writes
|
||||
glDepthMask(1);
|
||||
|
||||
// restore default state: switch off blending
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
// switch off texture unit 1 and second uv set
|
||||
pglClientActiveTextureARB(GL_TEXTURE1);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
g_Renderer.BindTexture(1,0);
|
||||
|
||||
// switch back to texture unit 0
|
||||
pglClientActiveTextureARB(GL_TEXTURE0);
|
||||
pglActiveTextureARB(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Submit: submit a patch to render this frame
|
||||
void CPatchRData::Submit(CPatch* patch)
|
||||
{
|
||||
CPatchRData* data=(CPatchRData*) patch->GetRenderData();
|
||||
if (data==0) {
|
||||
// no renderdata for patch, create it now
|
||||
data=new CPatchRData(patch);
|
||||
patch->SetRenderData(data);
|
||||
}
|
||||
data->Update();
|
||||
|
||||
m_Patches.push_back(patch);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ApplyShadowMap: apply given shadow map to all terrain patches; assume the texture matrix
|
||||
// has been correctly setup on unit 1 to handle the projection
|
||||
void CPatchRData::ApplyShadowMap(GLuint shadowmaphandle)
|
||||
{
|
||||
uint i;
|
||||
|
||||
g_Renderer.BindTexture(0,shadowmaphandle);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
||||
|
||||
glColor3f(1,1,1);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_DST_COLOR,GL_ZERO);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
#if 1
|
||||
// submit base batches for each patch to the vertex buffer
|
||||
for (i=0;i<m_Patches.size();++i) {
|
||||
CPatchRData* patchdata=(CPatchRData*) m_Patches[i]->GetRenderData();
|
||||
patchdata->m_VBBase->m_Owner->AppendBatch(patchdata->m_VBBase,0,patchdata->m_ShadowMapIndices.size(),
|
||||
&patchdata->m_ShadowMapIndices[0]);
|
||||
}
|
||||
|
||||
// render base passes for each patch
|
||||
const std::list<CVertexBuffer*>& buffers=g_VBMan.GetBufferList();
|
||||
std::list<CVertexBuffer*>::const_iterator iter;
|
||||
for (iter=buffers.begin();iter!=buffers.end();++iter) {
|
||||
CVertexBuffer* buffer=*iter;
|
||||
|
||||
// any batches in this VB?
|
||||
const std::vector<CVertexBuffer::Batch*>& batches=buffer->GetBatches();
|
||||
if (batches.size()>0) {
|
||||
u8* base=buffer->Bind();
|
||||
|
||||
// setup data pointers
|
||||
u32 stride=sizeof(SBaseVertex);
|
||||
glVertexPointer(3,GL_FLOAT,stride,base+offsetof(SBaseVertex,m_Position));
|
||||
glColorPointer(4,GL_UNSIGNED_BYTE,stride,base+offsetof(SBaseVertex,m_Color));
|
||||
glTexCoordPointer(3,GL_FLOAT,sizeof(SBaseVertex),base+offsetof(SBaseVertex,m_Position));
|
||||
|
||||
// render batch (can only be one per buffer, since all batches are flagged as using a null texture)
|
||||
const CVertexBuffer::Batch* batch=batches[0];
|
||||
for (uint j=0;j<batch->m_IndexData.size();j++) {
|
||||
glDrawElements(GL_QUADS,(GLsizei)batch->m_IndexData[j].first,GL_UNSIGNED_SHORT,batch->m_IndexData[j].second);
|
||||
g_Renderer.m_Stats.m_DrawCalls++;
|
||||
g_Renderer.m_Stats.m_TerrainTris+=(u32)batch->m_IndexData[j].first/2;
|
||||
}
|
||||
}
|
||||
}
|
||||
// everything rendered; empty out batch lists
|
||||
g_VBMan.ClearBatchIndices();
|
||||
#else
|
||||
for (uint i=0;i<m_Patches.size();++i) {
|
||||
CPatchRData* patchdata=(CPatchRData*) m_Patches[i]->GetRenderData();;
|
||||
patchdata->RenderStreams(STREAM_POS|STREAM_POSTOUV0);
|
||||
}
|
||||
#endif
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
|
@ -15,8 +15,8 @@ class CPatch;
|
||||
class CPatchRData : public CRenderData
|
||||
{
|
||||
public:
|
||||
CPatchRData(CPatch* patch);
|
||||
~CPatchRData();
|
||||
CPatchRData(CPatch* patch);
|
||||
~CPatchRData();
|
||||
|
||||
void Update();
|
||||
void RenderBase();
|
||||
@ -24,27 +24,6 @@ public:
|
||||
void RenderOutline();
|
||||
void RenderStreams(u32 streamflags);
|
||||
|
||||
// submit a patch to render this frame
|
||||
static void Submit(CPatch* patch);
|
||||
// clear per frame patch list
|
||||
static void ClearSubmissions() { m_Patches.clear(); }
|
||||
|
||||
// render the base pass of all patches
|
||||
static void RenderBaseSplats();
|
||||
// render the blend pass of all patches
|
||||
static void RenderBlendSplats();
|
||||
// render the outlines of all patches
|
||||
static void RenderOutlines();
|
||||
// render given streams of all patches; don't fiddle with renderstate
|
||||
static void RenderStreamsAll(u32 streamflags);
|
||||
// apply given shadow map to all terrain patches
|
||||
static void ApplyShadowMap(GLuint handle);
|
||||
|
||||
// submit base batches for this patch to the vertex buffer
|
||||
void SubmitBaseBatches();
|
||||
// submit next set of blend batches for this patch to the vertex buffer;
|
||||
void SubmitBlendBatches();
|
||||
|
||||
private:
|
||||
struct SSplat {
|
||||
SSplat() : m_Texture(0), m_IndexCount(0) {}
|
||||
@ -129,9 +108,6 @@ private:
|
||||
|
||||
// splats used in blend pass
|
||||
std::vector<SSplat> m_BlendSplats;
|
||||
|
||||
// list of all submitted patches
|
||||
static std::vector<CPatch*> m_Patches;
|
||||
};
|
||||
|
||||
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "Matrix3D.h"
|
||||
#include "MathUtil.h"
|
||||
#include "Camera.h"
|
||||
#include "PatchRData.h"
|
||||
#include "Texture.h"
|
||||
#include "LightEnv.h"
|
||||
#include "Terrain.h"
|
||||
@ -52,7 +51,10 @@
|
||||
#include "renderer/PlayerRenderer.h"
|
||||
#include "renderer/RenderModifiers.h"
|
||||
#include "renderer/RenderPathVertexShader.h"
|
||||
#include "renderer/ShadowMap.h"
|
||||
#include "renderer/TerrainRenderer.h"
|
||||
#include "renderer/TransparencyRenderer.h"
|
||||
#include "renderer/WaterManager.h"
|
||||
|
||||
#define LOG_CATEGORY "graphics"
|
||||
|
||||
@ -71,7 +73,7 @@ class CRendererStatsTable : public AbstractProfileTable
|
||||
{
|
||||
public:
|
||||
CRendererStatsTable(const CRenderer::Stats& st);
|
||||
|
||||
|
||||
// Implementation of AbstractProfileTable interface
|
||||
CStr GetName();
|
||||
CStr GetTitle();
|
||||
@ -83,17 +85,17 @@ public:
|
||||
private:
|
||||
/// Reference to the renderer singleton's stats
|
||||
const CRenderer::Stats& Stats;
|
||||
|
||||
|
||||
/// Column descriptions
|
||||
std::vector<ProfileColumn> columnDescriptions;
|
||||
|
||||
|
||||
enum {
|
||||
Row_Counter = 0,
|
||||
Row_DrawCalls,
|
||||
Row_TerrainTris,
|
||||
Row_ModelTris,
|
||||
Row_BlendSplats,
|
||||
|
||||
|
||||
// Must be last to count number of rows
|
||||
NumberRows
|
||||
};
|
||||
@ -134,7 +136,7 @@ const std::vector<ProfileColumn>& CRendererStatsTable::GetColumns()
|
||||
CStr CRendererStatsTable::GetCellText(uint row, uint col)
|
||||
{
|
||||
char buf[256];
|
||||
|
||||
|
||||
switch(row)
|
||||
{
|
||||
case Row_Counter:
|
||||
@ -142,31 +144,31 @@ CStr CRendererStatsTable::GetCellText(uint row, uint col)
|
||||
return "counter";
|
||||
snprintf(buf, sizeof(buf), "%d", Stats.m_Counter);
|
||||
return buf;
|
||||
|
||||
|
||||
case Row_DrawCalls:
|
||||
if (col == 0)
|
||||
return "# draw calls";
|
||||
snprintf(buf, sizeof(buf), "%d", Stats.m_DrawCalls);
|
||||
return buf;
|
||||
|
||||
|
||||
case Row_TerrainTris:
|
||||
if (col == 0)
|
||||
return "# terrain tris";
|
||||
snprintf(buf, sizeof(buf), "%d", Stats.m_TerrainTris);
|
||||
return buf;
|
||||
|
||||
|
||||
case Row_ModelTris:
|
||||
if (col == 0)
|
||||
return "# model tris";
|
||||
snprintf(buf, sizeof(buf), "%d", Stats.m_ModelTris);
|
||||
return buf;
|
||||
|
||||
|
||||
case Row_BlendSplats:
|
||||
if (col == 0)
|
||||
return "# blend splats";
|
||||
snprintf(buf, sizeof(buf), "%d", Stats.m_BlendSplats);
|
||||
return buf;
|
||||
|
||||
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
@ -189,10 +191,27 @@ struct CRendererInternals
|
||||
{
|
||||
/// Table to display renderer stats in-game via profile system
|
||||
CRendererStatsTable profileTable;
|
||||
|
||||
/// Water manager
|
||||
WaterManager waterManager;
|
||||
|
||||
/// Terrain renderer
|
||||
TerrainRenderer* terrainRenderer;
|
||||
|
||||
/// Shadow map
|
||||
ShadowMap* shadow;
|
||||
|
||||
CRendererInternals()
|
||||
: profileTable(g_Renderer.m_Stats)
|
||||
{
|
||||
terrainRenderer = new TerrainRenderer();
|
||||
shadow = new ShadowMap();
|
||||
}
|
||||
|
||||
~CRendererInternals()
|
||||
{
|
||||
delete shadow;
|
||||
delete terrainRenderer;
|
||||
}
|
||||
};
|
||||
|
||||
@ -201,8 +220,10 @@ struct CRendererInternals
|
||||
CRenderer::CRenderer()
|
||||
{
|
||||
m = new CRendererInternals;
|
||||
m_WaterManager = &m->waterManager;
|
||||
|
||||
g_ProfileViewer.AddRootTable(&m->profileTable);
|
||||
|
||||
|
||||
m_Width=0;
|
||||
m_Height=0;
|
||||
m_Depth=0;
|
||||
@ -210,13 +231,12 @@ CRenderer::CRenderer()
|
||||
m_TerrainRenderMode=SOLID;
|
||||
m_ModelRenderMode=SOLID;
|
||||
m_ClearColor[0]=m_ClearColor[1]=m_ClearColor[2]=m_ClearColor[3]=0;
|
||||
m_ShadowMap=0;
|
||||
|
||||
m_SortAllTransparent = false;
|
||||
m_FastNormals = true;
|
||||
|
||||
|
||||
m_VertexShader = 0;
|
||||
|
||||
|
||||
m_Options.m_NoVBO=false;
|
||||
m_Options.m_Shadows=true;
|
||||
m_Options.m_ShadowColor=RGBAColor(0.4f,0.4f,0.4f,1.0f);
|
||||
@ -279,23 +299,6 @@ CRenderer::CRenderer()
|
||||
m_Models.ModTransparent = RenderModifierPtr(new TransparentRenderModifier);
|
||||
m_Models.ModTransparentShadow = RenderModifierPtr(new TransparentShadowRenderModifier);
|
||||
|
||||
// water
|
||||
m_RenderWater = true;
|
||||
m_WaterHeight = 5.0f;
|
||||
m_WaterColor = CColor(0.3f, 0.35f, 0.7f, 1.0f);
|
||||
m_WaterFullDepth = 4.0f;
|
||||
m_WaterMaxAlpha = 0.85f;
|
||||
m_WaterAlphaOffset = -0.05f;
|
||||
m_SWaterTrans=0;
|
||||
m_TWaterTrans=0;
|
||||
m_SWaterSpeed=0.0015f;
|
||||
m_TWaterSpeed=0.0015f;
|
||||
m_SWaterScrollCounter=0;
|
||||
m_TWaterScrollCounter=0;
|
||||
m_WaterCurrentTex=0;
|
||||
|
||||
cur_loading_water_tex = 0;
|
||||
|
||||
ONCE( ScriptingInit(); );
|
||||
}
|
||||
|
||||
@ -382,19 +385,19 @@ bool CRenderer::Open(int width, int height, int depth)
|
||||
|
||||
if (m_Options.m_RenderPath == RP_DEFAULT)
|
||||
SetRenderPath(m_Options.m_RenderPath);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// resize renderer view
|
||||
void CRenderer::Resize(int width,int height)
|
||||
{
|
||||
if (m_ShadowMap && (width>m_Width || height>m_Height)) {
|
||||
glDeleteTextures(1,(GLuint*) &m_ShadowMap);
|
||||
m_ShadowMap=0;
|
||||
}
|
||||
m_Width=width;
|
||||
m_Height=height;
|
||||
// need to recreate the shadow map object to resize the shadow texture
|
||||
delete m->shadow;
|
||||
m->shadow = new ShadowMap;
|
||||
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -492,7 +495,7 @@ void CRenderer::SetRenderPath(RenderPath rp)
|
||||
else
|
||||
rp = RP_FIXED;
|
||||
}
|
||||
|
||||
|
||||
if (rp == RP_VERTEXSHADER)
|
||||
{
|
||||
if (!m_Models.NormalHWLit || !m_Models.PlayerHWLit)
|
||||
@ -501,7 +504,7 @@ void CRenderer::SetRenderPath(RenderPath rp)
|
||||
rp = RP_FIXED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
m_Options.m_RenderPath = rp;
|
||||
}
|
||||
|
||||
@ -524,7 +527,7 @@ CRenderer::RenderPath CRenderer::GetRenderPathByName(CStr name)
|
||||
return RP_VERTEXSHADER;
|
||||
if (name == "default")
|
||||
return RP_DEFAULT;
|
||||
|
||||
|
||||
LOG(WARNING, LOG_CATEGORY, "Unknown render path name '%hs', assuming 'default'", name.c_str());
|
||||
return RP_DEFAULT;
|
||||
}
|
||||
@ -535,7 +538,7 @@ CRenderer::RenderPath CRenderer::GetRenderPathByName(CStr name)
|
||||
void CRenderer::SetFastPlayerColor(bool fast)
|
||||
{
|
||||
m_FastPlayerColor = fast;
|
||||
|
||||
|
||||
if (m_FastPlayerColor)
|
||||
{
|
||||
if (!FastPlayerColorRender::IsAvailable())
|
||||
@ -544,7 +547,7 @@ void CRenderer::SetFastPlayerColor(bool fast)
|
||||
m_FastPlayerColor = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (m_FastPlayerColor)
|
||||
m_Models.ModPlayer = RenderModifierPtr(new FastPlayerColorRender);
|
||||
else
|
||||
@ -565,10 +568,10 @@ void CRenderer::BeginFrame()
|
||||
|
||||
if (m_VertexShader)
|
||||
m_VertexShader->BeginFrame();
|
||||
|
||||
|
||||
// zero out all the per-frame stats
|
||||
m_Stats.Reset();
|
||||
|
||||
|
||||
// calculate coefficients for terrain and unit lighting
|
||||
m_SHCoeffsUnits.Clear();
|
||||
m_SHCoeffsTerrain.Clear();
|
||||
@ -596,354 +599,14 @@ void CRenderer::SetClearColor(u32 color)
|
||||
m_ClearColor[3]=float((color>>24) & 0xff)/255.0f;
|
||||
}
|
||||
|
||||
static int RoundUpToPowerOf2(int x)
|
||||
{
|
||||
if ((x & (x-1))==0) return x;
|
||||
int d=x;
|
||||
while (d & (d-1)) {
|
||||
d&=(d-1);
|
||||
}
|
||||
return d<<1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// BuildTransformation: build transformation matrix from a position and standard basis vectors
|
||||
void CRenderer::BuildTransformation(const CVector3D& pos,const CVector3D& right,const CVector3D& up,
|
||||
const CVector3D& dir,CMatrix3D& result)
|
||||
{
|
||||
// build basis
|
||||
result._11=right.X;
|
||||
result._12=right.Y;
|
||||
result._13=right.Z;
|
||||
result._14=0;
|
||||
|
||||
result._21=up.X;
|
||||
result._22=up.Y;
|
||||
result._23=up.Z;
|
||||
result._24=0;
|
||||
|
||||
result._31=dir.X;
|
||||
result._32=dir.Y;
|
||||
result._33=dir.Z;
|
||||
result._34=0;
|
||||
|
||||
result._41=0;
|
||||
result._42=0;
|
||||
result._43=0;
|
||||
result._44=1;
|
||||
|
||||
CMatrix3D trans;
|
||||
trans.SetTranslation(-pos.X,-pos.Y,-pos.Z);
|
||||
result=result*trans;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ConstructLightTransform: build transformation matrix for light at given position casting in
|
||||
// given direction
|
||||
void CRenderer::ConstructLightTransform(const CVector3D& pos,const CVector3D& dir,CMatrix3D& result)
|
||||
{
|
||||
CVector3D right,up;
|
||||
|
||||
CVector3D viewdir=m_Camera.m_Orientation.GetIn();
|
||||
if (fabs(dir.Y)>0.01f) {
|
||||
up=CVector3D(viewdir.X,(-dir.Z*viewdir.Z-dir.X*dir.X)/dir.Y,viewdir.Z);
|
||||
} else {
|
||||
up=CVector3D(0,0,1);
|
||||
}
|
||||
|
||||
up.Normalize();
|
||||
right=dir.Cross(up);
|
||||
right.Normalize();
|
||||
BuildTransformation(pos,right,up,dir,result);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CalcShadowMatrices: calculate required matrices for shadow map generation - the light's
|
||||
// projection and transformation matrices
|
||||
void CRenderer::CalcShadowMatrices()
|
||||
{
|
||||
int i;
|
||||
|
||||
// get bounds of shadow casting objects
|
||||
const CBound& bounds=m_ShadowBound;
|
||||
|
||||
// get centre of bounds
|
||||
CVector3D centre;
|
||||
bounds.GetCentre(centre);
|
||||
|
||||
// get sunlight direction
|
||||
// ??? RC more optimal light placement?
|
||||
CVector3D lightpos=centre-(m_LightEnv->m_SunDir * 1000);
|
||||
|
||||
// make light transformation matrix
|
||||
ConstructLightTransform(lightpos,m_LightEnv->m_SunDir,m_LightTransform);
|
||||
|
||||
// transform shadow bounds to light space, calculate near and far bounds
|
||||
CVector3D vp[8];
|
||||
m_LightTransform.Transform(CVector3D(bounds[0].X,bounds[0].Y,bounds[0].Z),vp[0]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[1].X,bounds[0].Y,bounds[0].Z),vp[1]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[0].X,bounds[1].Y,bounds[0].Z),vp[2]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[1].X,bounds[1].Y,bounds[0].Z),vp[3]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[0].X,bounds[0].Y,bounds[1].Z),vp[4]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[1].X,bounds[0].Y,bounds[1].Z),vp[5]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[0].X,bounds[1].Y,bounds[1].Z),vp[6]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[1].X,bounds[1].Y,bounds[1].Z),vp[7]);
|
||||
|
||||
float left=vp[0].X;
|
||||
float right=vp[0].X;
|
||||
float top=vp[0].Y;
|
||||
float bottom=vp[0].Y;
|
||||
float znear=vp[0].Z;
|
||||
float zfar=vp[0].Z;
|
||||
|
||||
for (i=1;i<8;i++) {
|
||||
if (vp[i].X<left) left=vp[i].X;
|
||||
else if (vp[i].X>right) right=vp[i].X;
|
||||
|
||||
if (vp[i].Y<bottom) bottom=vp[i].Y;
|
||||
else if (vp[i].Y>top) top=vp[i].Y;
|
||||
|
||||
if (vp[i].Z<znear) znear=vp[i].Z;
|
||||
else if (vp[i].Z>zfar) zfar=vp[i].Z;
|
||||
}
|
||||
|
||||
// shift near and far clip planes slightly to avoid artifacts with points
|
||||
// exactly on the clip planes
|
||||
znear=(znear<m_Camera.GetNearPlane()+0.01f) ? m_Camera.GetNearPlane() : znear-0.01f;
|
||||
zfar+=0.01f;
|
||||
|
||||
m_LightProjection.SetZero();
|
||||
m_LightProjection._11=2/(right-left);
|
||||
m_LightProjection._22=2/(top-bottom);
|
||||
m_LightProjection._33=2/(zfar-znear);
|
||||
m_LightProjection._14=-(right+left)/(right-left);
|
||||
m_LightProjection._24=-(top+bottom)/(top-bottom);
|
||||
m_LightProjection._34=-(zfar+znear)/(zfar-znear);
|
||||
m_LightProjection._44=1;
|
||||
|
||||
#if 0
|
||||
|
||||
#if 0
|
||||
// TODO, RC - trim against frustum?
|
||||
// get points of view frustum in world space
|
||||
CVector3D frustumPts[8];
|
||||
m_Camera.GetFrustumPoints(frustumPts);
|
||||
|
||||
// transform to light space
|
||||
for (i=0;i<8;i++) {
|
||||
m_LightTransform.Transform(frustumPts[i],vp[i]);
|
||||
}
|
||||
|
||||
float left1=vp[0].X;
|
||||
float right1=vp[0].X;
|
||||
float top1=vp[0].Y;
|
||||
float bottom1=vp[0].Y;
|
||||
float znear1=vp[0].Z;
|
||||
float zfar1=vp[0].Z;
|
||||
|
||||
for (int i=1;i<8;i++) {
|
||||
if (vp[i].X<left1) left1=vp[i].X;
|
||||
else if (vp[i].X>right1) right1=vp[i].X;
|
||||
|
||||
if (vp[i].Y<bottom1) bottom1=vp[i].Y;
|
||||
else if (vp[i].Y>top1) top1=vp[i].Y;
|
||||
|
||||
if (vp[i].Z<znear1) znear1=vp[i].Z;
|
||||
else if (vp[i].Z>zfar1) zfar1=vp[i].Z;
|
||||
}
|
||||
|
||||
left=max(left,left1);
|
||||
right=min(right,right1);
|
||||
top=min(top,top1);
|
||||
bottom=max(bottom,bottom1);
|
||||
znear=max(znear,znear1);
|
||||
zfar=min(zfar,zfar1);
|
||||
#endif
|
||||
|
||||
// experimental stuff, do not use ..
|
||||
// TODO, RC - desperately need to improve resolution here if we're using shadow maps; investigate
|
||||
// feasibility of PSMs
|
||||
|
||||
// transform light space bounds to image space - TODO, RC: safe to just use 3d transform here?
|
||||
CVector4D vph[8];
|
||||
for (i=0;i<8;i++) {
|
||||
CVector4D tmp(vp[i].X,vp[i].Y,vp[i].Z,1.0f);
|
||||
m_LightProjection.Transform(tmp,vph[i]);
|
||||
vph[i][0]/=vph[i][2];
|
||||
vph[i][1]/=vph[i][2];
|
||||
}
|
||||
|
||||
// find the two points furthest apart
|
||||
int p0,p1;
|
||||
float maxdistsqrd=-1;
|
||||
for (i=0;i<8;i++) {
|
||||
for (int j=i+1;j<8;j++) {
|
||||
float dx=vph[i][0]-vph[j][0];
|
||||
float dy=vph[i][1]-vph[j][1];
|
||||
float distsqrd=dx*dx+dy*dy;
|
||||
if (distsqrd>maxdistsqrd) {
|
||||
p0=i;
|
||||
p1=j;
|
||||
maxdistsqrd=distsqrd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now we want to rotate the camera such that the longest axis lies the diagonal at 45 degrees -
|
||||
// get angle between points
|
||||
float angle=atan2(vph[p0][1]-vph[p1][1],vph[p0][0]-vph[p1][0]);
|
||||
float rotation=-angle;
|
||||
|
||||
// build rotation matrix
|
||||
CQuaternion quat;
|
||||
quat.FromAxisAngle(lightdir,rotation);
|
||||
CMatrix3D m;
|
||||
quat.ToMatrix(m);
|
||||
|
||||
// rotate up vector by given rotation
|
||||
CVector3D up(m_LightTransform._21,m_LightTransform._22,m_LightTransform._23);
|
||||
up=m.Rotate(up);
|
||||
up.Normalize(); // TODO, RC - required??
|
||||
|
||||
// rebuild right vector
|
||||
CVector3D rightvec;
|
||||
rightvec=lightdir.Cross(up);
|
||||
rightvec.Normalize();
|
||||
BuildTransformation(lightpos,rightvec,up,lightdir,m_LightTransform);
|
||||
|
||||
// retransform points
|
||||
m_LightTransform.Transform(CVector3D(bounds[0].X,bounds[0].Y,bounds[0].Z),vp[0]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[1].X,bounds[0].Y,bounds[0].Z),vp[1]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[0].X,bounds[1].Y,bounds[0].Z),vp[2]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[1].X,bounds[1].Y,bounds[0].Z),vp[3]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[0].X,bounds[0].Y,bounds[1].Z),vp[4]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[1].X,bounds[0].Y,bounds[1].Z),vp[5]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[0].X,bounds[1].Y,bounds[1].Z),vp[6]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[1].X,bounds[1].Y,bounds[1].Z),vp[7]);
|
||||
|
||||
// recalculate projection
|
||||
left=vp[0].X;
|
||||
right=vp[0].X;
|
||||
top=vp[0].Y;
|
||||
bottom=vp[0].Y;
|
||||
znear=vp[0].Z;
|
||||
zfar=vp[0].Z;
|
||||
|
||||
for (i=1;i<8;i++) {
|
||||
if (vp[i].X<left) left=vp[i].X;
|
||||
else if (vp[i].X>right) right=vp[i].X;
|
||||
|
||||
if (vp[i].Y<bottom) bottom=vp[i].Y;
|
||||
else if (vp[i].Y>top) top=vp[i].Y;
|
||||
|
||||
if (vp[i].Z<znear) znear=vp[i].Z;
|
||||
else if (vp[i].Z>zfar) zfar=vp[i].Z;
|
||||
}
|
||||
|
||||
// shift near and far clip planes slightly to avoid artifacts with points
|
||||
// exactly on the clip planes
|
||||
znear-=0.01f;
|
||||
zfar+=0.01f;
|
||||
|
||||
m_LightProjection.SetZero();
|
||||
m_LightProjection._11=2/(right-left);
|
||||
m_LightProjection._22=2/(top-bottom);
|
||||
m_LightProjection._33=2/(zfar-znear);
|
||||
m_LightProjection._14=-(right+left)/(right-left);
|
||||
m_LightProjection._24=-(top+bottom)/(top-bottom);
|
||||
m_LightProjection._34=-(zfar+znear)/(zfar-znear);
|
||||
m_LightProjection._44=1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CRenderer::CreateShadowMap()
|
||||
{
|
||||
// get shadow map size as next power of two up from view width and height
|
||||
m_ShadowMapWidth=m_Width;
|
||||
m_ShadowMapWidth=RoundUpToPowerOf2(m_ShadowMapWidth);
|
||||
m_ShadowMapHeight=m_Height;
|
||||
m_ShadowMapHeight=RoundUpToPowerOf2(m_ShadowMapHeight);
|
||||
|
||||
// create texture object - initially filled with white, so clamp to edge clamps to correct color
|
||||
glGenTextures(1,(GLuint*) &m_ShadowMap);
|
||||
BindTexture(0,(GLuint) m_ShadowMap);
|
||||
|
||||
u32 size=m_ShadowMapWidth*m_ShadowMapHeight;
|
||||
u32* buf=new u32[size];
|
||||
for (uint i=0;i<size;i++) buf[i]=0x00ffffff;
|
||||
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,m_ShadowMapWidth,m_ShadowMapHeight,0,GL_RGBA,GL_UNSIGNED_BYTE,buf);
|
||||
delete[] buf;
|
||||
|
||||
// set texture parameters
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
|
||||
}
|
||||
|
||||
void CRenderer::RenderShadowMap()
|
||||
{
|
||||
PROFILE( "render shadow map" );
|
||||
|
||||
// create shadow map if we haven't already got one
|
||||
if (!m_ShadowMap) CreateShadowMap();
|
||||
|
||||
// clear buffers
|
||||
glClearColor(1,1,1,0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
// build required matrices
|
||||
CalcShadowMatrices();
|
||||
|
||||
// setup viewport
|
||||
glViewport(0,0,m_Width,m_Height);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadMatrixf(&m_LightProjection._11);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadMatrixf(&m_LightTransform._11);
|
||||
|
||||
#if 0
|
||||
// debug aid - render actual bounds of shadow casting objects; helps see where
|
||||
// the lights projection/transform can be optimised
|
||||
glColor3f(1.0,0.0,0.0);
|
||||
const CBound& bounds=m_ShadowBound;
|
||||
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex3f(bounds[0].X,bounds[0].Y,bounds[0].Z);
|
||||
glVertex3f(bounds[0].X,bounds[0].Y,bounds[1].Z);
|
||||
glVertex3f(bounds[0].X,bounds[1].Y,bounds[1].Z);
|
||||
glVertex3f(bounds[0].X,bounds[1].Y,bounds[0].Z);
|
||||
glEnd();
|
||||
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex3f(bounds[1].X,bounds[0].Y,bounds[0].Z);
|
||||
glVertex3f(bounds[1].X,bounds[0].Y,bounds[1].Z);
|
||||
glVertex3f(bounds[1].X,bounds[1].Y,bounds[1].Z);
|
||||
glVertex3f(bounds[1].X,bounds[1].Y,bounds[0].Z);
|
||||
glEnd();
|
||||
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex3f(bounds[0].X,bounds[0].Y,bounds[0].Z);
|
||||
glVertex3f(bounds[0].X,bounds[0].Y,bounds[1].Z);
|
||||
glVertex3f(bounds[1].X,bounds[0].Y,bounds[1].Z);
|
||||
glVertex3f(bounds[1].X,bounds[0].Y,bounds[0].Z);
|
||||
glEnd();
|
||||
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex3f(bounds[0].X,bounds[1].Y,bounds[0].Z);
|
||||
glVertex3f(bounds[0].X,bounds[1].Y,bounds[1].Z);
|
||||
glVertex3f(bounds[1].X,bounds[1].Y,bounds[1].Z);
|
||||
glVertex3f(bounds[1].X,bounds[1].Y,bounds[0].Z);
|
||||
glEnd();
|
||||
#endif // 0
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(1,1,m_Width-2,m_Height-2);
|
||||
|
||||
m->shadow->SetupFrame(m_ShadowBound);
|
||||
m->shadow->BeginRender();
|
||||
|
||||
// TODO HACK fold this into ShadowMap
|
||||
glColor4fv(m_Options.m_ShadowColor);
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
@ -967,56 +630,22 @@ void CRenderer::RenderShadowMap()
|
||||
|
||||
glColor3f(1.0f,1.0f,1.0f);
|
||||
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
// copy result into shadow map texture
|
||||
BindTexture(0,m_ShadowMap);
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D,0,0,0,0,0,m_Width,m_Height);
|
||||
|
||||
// restore matrix stack
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
#if 0
|
||||
// debug aid - dump generated shadow map to file; helps verify shadow map
|
||||
// space being well used (not that it is at the minute .. (TODO, RC))
|
||||
unsigned char* data=new unsigned char[m_ShadowMapWidth*m_ShadowMapHeight*3];
|
||||
glGetTexImage(GL_TEXTURE_2D,0,GL_BGR_EXT,GL_UNSIGNED_BYTE,data);
|
||||
saveTGA("d:\\test4.tga",m_ShadowMapWidth,m_ShadowMapHeight,24,data);
|
||||
delete[] data;
|
||||
#endif // 0
|
||||
#if 0
|
||||
unsigned char* data=new unsigned char[m_Width*m_Height*4];
|
||||
glReadBuffer(GL_BACK);
|
||||
glReadPixels(0,0,m_Width,m_Height,GL_BGRA_EXT,GL_UNSIGNED_BYTE,data);
|
||||
saveTGA("d:\\test3.tga",m_Width,m_Height,32,data);
|
||||
delete[] data;
|
||||
#endif // 0
|
||||
m->shadow->EndRender();
|
||||
}
|
||||
|
||||
//TODO: Fold into TerrainRenderer
|
||||
void CRenderer::ApplyShadowMap()
|
||||
{
|
||||
PROFILE( "applying shadows" );
|
||||
|
||||
CMatrix3D tmp2;
|
||||
CMatrix3D texturematrix;
|
||||
|
||||
float dx=0.5f*float(m_Width)/float(m_ShadowMapWidth);
|
||||
float dy=0.5f*float(m_Height)/float(m_ShadowMapHeight);
|
||||
texturematrix.SetTranslation(dx,dy,0); // transform (-0.5, 0.5) to (0,1) - texture space
|
||||
tmp2.SetScaling(dx,dy,0); // scale (-1,1) to (-0.5,0.5)
|
||||
texturematrix=texturematrix*tmp2;
|
||||
|
||||
texturematrix=texturematrix*m_LightProjection; // transform light -> projected light space (-1 to 1)
|
||||
texturematrix=texturematrix*m_LightTransform; // transform world -> light space
|
||||
const CMatrix3D& texturematrix = m->shadow->GetTextureMatrix();
|
||||
GLuint shadowmap = m->shadow->GetTexture();
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadMatrixf(&texturematrix._11);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
CPatchRData::ApplyShadowMap(m_ShadowMap);
|
||||
m->terrainRenderer->ApplyShadowMap(shadowmap);
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
@ -1035,7 +664,7 @@ void CRenderer::RenderPatches()
|
||||
|
||||
// render all the patches, including blend pass
|
||||
MICROLOG(L"render patch submissions");
|
||||
RenderPatchSubmissions();
|
||||
m->terrainRenderer->RenderTerrain();
|
||||
|
||||
if (m_TerrainRenderMode==WIREFRAME) {
|
||||
// switch wireframe off again
|
||||
@ -1055,19 +684,15 @@ void CRenderer::RenderPatches()
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// .. and some client states
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
CPatchRData::RenderStreamsAll(STREAM_POS);
|
||||
// render tiles edges
|
||||
m->terrainRenderer->RenderPatches();
|
||||
|
||||
// set color for outline
|
||||
glColor3f(0,0,1);
|
||||
glLineWidth(4.0f);
|
||||
|
||||
// render outline of each patch
|
||||
CPatchRData::RenderOutlines();
|
||||
|
||||
// .. and switch off the client states
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
m->terrainRenderer->RenderOutlines();
|
||||
|
||||
// .. and restore the renderstates
|
||||
glDisable(GL_BLEND);
|
||||
@ -1078,135 +703,6 @@ void CRenderer::RenderPatches()
|
||||
}
|
||||
}
|
||||
|
||||
void CRenderer::RenderWater()
|
||||
{
|
||||
PROFILE(" render water ");
|
||||
|
||||
if(!m_RenderWater)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Fresnel effect
|
||||
CCamera* Camera=g_Game->GetView()->GetCamera();
|
||||
CVector3D CamFace=Camera->m_Orientation.GetIn();
|
||||
CamFace.Normalize();
|
||||
float FresnelScalar = CamFace.Dot( CVector3D(0.0f, -1.0f, 0.0f) );
|
||||
//Invert and set boundaries
|
||||
FresnelScalar = (1 - FresnelScalar) * 0.4f + 0.6f;
|
||||
|
||||
const int DX[] = {1,1,0,0};
|
||||
const int DZ[] = {0,1,1,0};
|
||||
|
||||
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
|
||||
int mapSize = terrain->GetVerticesPerSide();
|
||||
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
double time = get_time();
|
||||
|
||||
double period = 1.6;
|
||||
int curTex = (int)(time*60/period) % 60;
|
||||
ogl_tex_bind(m_WaterTexture[curTex], 0);
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
float tx = -fmod(time, 20.0)/20.0;
|
||||
float ty = fmod(time, 35.0)/35.0;
|
||||
glTranslatef(tx, ty, 0);
|
||||
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
||||
|
||||
// Set the proper LOD bias
|
||||
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, m_Options.m_LodBias);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
for(size_t i=0; i<m_VisiblePatches.size(); i++)
|
||||
{
|
||||
CPatch* patch = m_VisiblePatches[i];
|
||||
|
||||
for(int dx=0; dx<PATCH_SIZE; dx++)
|
||||
{
|
||||
for(int dz=0; dz<PATCH_SIZE; dz++)
|
||||
{
|
||||
int x = (patch->m_X*PATCH_SIZE + dx);
|
||||
int z = (patch->m_Z*PATCH_SIZE + dz);
|
||||
|
||||
// is any corner of the tile below the water height? if not, no point rendering it
|
||||
bool shouldRender = false;
|
||||
for(int j=0; j<4; j++)
|
||||
{
|
||||
float terrainHeight = terrain->getVertexGroundLevel(x + DX[j], z + DZ[j]);
|
||||
if(terrainHeight < m_WaterHeight)
|
||||
{
|
||||
shouldRender = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!shouldRender)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for(int j=0; j<4; j++)
|
||||
{
|
||||
int ix = x + DX[j];
|
||||
int iz = z + DZ[j];
|
||||
|
||||
float vertX = ix * CELL_SIZE;
|
||||
float vertZ = iz * CELL_SIZE;
|
||||
|
||||
float terrainHeight = terrain->getVertexGroundLevel(ix, iz);
|
||||
|
||||
float alpha = clamp((m_WaterHeight - terrainHeight) / m_WaterFullDepth + m_WaterAlphaOffset,
|
||||
-100.0f, m_WaterMaxAlpha);
|
||||
|
||||
float losMod = 1.0f;
|
||||
for(int k=0; k<4; k++)
|
||||
{
|
||||
int tx = ix - DX[k];
|
||||
int tz = iz - DZ[k];
|
||||
|
||||
if(tx >= 0 && tz >= 0 && tx <= mapSize-2 && tz <= mapSize-2)
|
||||
{
|
||||
ELOSStatus s = losMgr->GetStatus(tx, tz, g_Game->GetLocalPlayer());
|
||||
if(s == LOS_EXPLORED && losMod > 0.7f)
|
||||
losMod = 0.7f;
|
||||
else if(s==LOS_UNEXPLORED && losMod > 0.0f)
|
||||
losMod = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
glColor4f(m_WaterColor.r*losMod, m_WaterColor.g*losMod, m_WaterColor.b*losMod, alpha * FresnelScalar);
|
||||
pglMultiTexCoord2fARB(GL_TEXTURE0, vertX/16.0f, vertZ/16.0f);
|
||||
glVertex3f(vertX, m_WaterHeight, vertZ);
|
||||
}
|
||||
} //end of x loop
|
||||
} //end of z loop
|
||||
}
|
||||
|
||||
glEnd();
|
||||
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
glDepthMask(GL_TRUE);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void CRenderer::RenderModels()
|
||||
{
|
||||
PROFILE( "render models ");
|
||||
@ -1298,6 +794,10 @@ void CRenderer::FlushFrame()
|
||||
m_Models.TranspSortAll->PrepareModels();
|
||||
PROFILE_END("prepare models");
|
||||
|
||||
PROFILE_START("prepare terrain");
|
||||
m->terrainRenderer->PrepareForRendering();
|
||||
PROFILE_END("prepare terrain");
|
||||
|
||||
if (!m_ShadowRendered) {
|
||||
if (m_Options.m_Shadows) {
|
||||
MICROLOG(L"render shadows");
|
||||
@ -1334,15 +834,17 @@ void CRenderer::FlushFrame()
|
||||
// render water (note: we're assuming there's no transparent stuff over water...
|
||||
// we could also do this above render transparent if we assume there's no transparent
|
||||
// stuff underwater)
|
||||
MICROLOG(L"render water");
|
||||
RenderWater();
|
||||
oglCheck();
|
||||
if (m_WaterManager->m_RenderWater)
|
||||
{
|
||||
MICROLOG(L"render water");
|
||||
m->terrainRenderer->RenderWater();
|
||||
oglCheck();
|
||||
}
|
||||
|
||||
// empty lists
|
||||
MICROLOG(L"empty lists");
|
||||
CPatchRData::ClearSubmissions();
|
||||
m_VisiblePatches.clear();
|
||||
|
||||
m->terrainRenderer->EndFrame();
|
||||
|
||||
// Finish model renderers
|
||||
m_Models.NormalFF->EndFrame();
|
||||
m_Models.PlayerFF->EndFrame();
|
||||
@ -1405,8 +907,7 @@ void CRenderer::SetViewport(const SViewPort &vp)
|
||||
|
||||
void CRenderer::Submit(CPatch* patch)
|
||||
{
|
||||
CPatchRData::Submit(patch);
|
||||
m_VisiblePatches.push_back(patch);
|
||||
m->terrainRenderer->Submit(patch);
|
||||
}
|
||||
|
||||
void CRenderer::Submit(CModel* model)
|
||||
@ -1418,9 +919,9 @@ void CRenderer::Submit(CModel* model)
|
||||
|
||||
// Tricky: The call to GetBounds() above can invalidate the position
|
||||
model->ValidatePosition();
|
||||
|
||||
|
||||
bool canUseInstancing = false;
|
||||
|
||||
|
||||
if (model->GetModelDef()->GetNumBones() == 0)
|
||||
canUseInstancing = true;
|
||||
|
||||
@ -1471,24 +972,6 @@ void CRenderer::Submit(COverlay* UNUSED(overlay))
|
||||
{
|
||||
}
|
||||
|
||||
void CRenderer::RenderPatchSubmissions()
|
||||
{
|
||||
// switch on required client states
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
// render everything
|
||||
CPatchRData::RenderBaseSplats();
|
||||
CPatchRData::RenderBlendSplats();
|
||||
|
||||
// switch off all client states
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// LoadTexture: try and load the given texture; set clamp/repeat flags on texture object if necessary
|
||||
@ -1723,58 +1206,6 @@ void CRenderer::UnloadAlphaMaps()
|
||||
|
||||
|
||||
|
||||
|
||||
int CRenderer::LoadWaterTextures()
|
||||
{
|
||||
const uint num_textures = ARRAY_SIZE(m_WaterTexture);
|
||||
|
||||
// yield after this time is reached. balances increased progress bar
|
||||
// smoothness vs. slowing down loading.
|
||||
const double end_time = get_time() + 100e-3;
|
||||
|
||||
// initialize to 0 in case something fails below
|
||||
// (we then abort the loop, but don't want undefined values in here)
|
||||
if (cur_loading_water_tex == 0)
|
||||
{
|
||||
for (uint i = 0; i < num_textures; i++)
|
||||
m_WaterTexture[i] = 0;
|
||||
}
|
||||
|
||||
while (cur_loading_water_tex < num_textures)
|
||||
{
|
||||
char waterName[VFS_MAX_PATH];
|
||||
// TODO: add a member variable and setter for this. (can't make this
|
||||
// a parameter because this function is called via delay-load code)
|
||||
const char* water_type = "animation2";
|
||||
snprintf(waterName, ARRAY_SIZE(waterName), "art/textures/terrain/types/water/%s/water%02d.dds", water_type, cur_loading_water_tex+1);
|
||||
Handle ht = ogl_tex_load(waterName);
|
||||
if (ht <= 0)
|
||||
{
|
||||
LOG(ERROR, LOG_CATEGORY, "LoadWaterTextures failed on \"%s\"", waterName);
|
||||
return ht;
|
||||
}
|
||||
m_WaterTexture[cur_loading_water_tex]=ht;
|
||||
RETURN_ERR(ogl_tex_upload(ht));
|
||||
|
||||
cur_loading_water_tex++;
|
||||
LDR_CHECK_TIMEOUT(cur_loading_water_tex, num_textures);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CRenderer::UnloadWaterTextures()
|
||||
{
|
||||
for (uint i = 0; i < ARRAY_SIZE(m_WaterTexture); i++)
|
||||
{
|
||||
ogl_tex_free(m_WaterTexture[i]);
|
||||
m_WaterTexture[i] = 0;
|
||||
}
|
||||
cur_loading_water_tex = 0; // so they will be reloaded if LoadWaterTextures is called again
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Scripting Interface
|
||||
|
||||
@ -1786,10 +1217,10 @@ jsval CRenderer::JSI_GetFastPlayerColor(JSContext*)
|
||||
void CRenderer::JSI_SetFastPlayerColor(JSContext* ctx, jsval newval)
|
||||
{
|
||||
bool fast;
|
||||
|
||||
|
||||
if (!ToPrimitive(ctx, newval, fast))
|
||||
return;
|
||||
|
||||
|
||||
SetFastPlayerColor(fast);
|
||||
}
|
||||
|
||||
@ -1801,10 +1232,10 @@ jsval CRenderer::JSI_GetRenderPath(JSContext*)
|
||||
void CRenderer::JSI_SetRenderPath(JSContext* ctx, jsval newval)
|
||||
{
|
||||
CStr name;
|
||||
|
||||
|
||||
if (!ToPrimitive(ctx, newval, name))
|
||||
return;
|
||||
|
||||
|
||||
SetRenderPath(GetRenderPathByName(name));
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
// Description: OpenGL renderer class; a higher level interface
|
||||
// on top of OpenGL to handle rendering the basic visual games
|
||||
// on top of OpenGL to handle rendering the basic visual games
|
||||
// types - terrain, models, sprites, particles etc
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -17,7 +17,6 @@
|
||||
#include "ogl.h"
|
||||
#include "Camera.h"
|
||||
#include "Frustum.h"
|
||||
#include "PatchRData.h"
|
||||
#include "SHCoeffs.h"
|
||||
#include "Terrain.h"
|
||||
#include "Singleton.h"
|
||||
@ -40,6 +39,7 @@ class CTexture;
|
||||
class CTerrain;
|
||||
|
||||
class RenderPathVertexShader;
|
||||
class WaterManager;
|
||||
|
||||
|
||||
// rendering modes
|
||||
@ -82,28 +82,6 @@ struct CRendererInternals;
|
||||
|
||||
class CRenderer : public Singleton<CRenderer>, public CJSObject<CRenderer>
|
||||
{
|
||||
private:
|
||||
std::vector<CPatch*> m_VisiblePatches;
|
||||
|
||||
public:
|
||||
Handle m_WaterTexture[60];
|
||||
int m_WaterCurrentTex;
|
||||
CColor m_WaterColor;
|
||||
bool m_RenderWater;
|
||||
bool m_WaterScroll;
|
||||
float m_WaterHeight;
|
||||
float m_WaterMaxAlpha;
|
||||
float m_WaterFullDepth;
|
||||
float m_WaterAlphaOffset;
|
||||
|
||||
float m_SWaterSpeed;
|
||||
float m_TWaterSpeed;
|
||||
float m_SWaterTrans;
|
||||
float m_TWaterTrans;
|
||||
float m_SWaterScrollCounter;
|
||||
float m_TWaterScrollCounter;
|
||||
float m_WaterTexTimer;
|
||||
|
||||
public:
|
||||
// various enumerations and renderer related constants
|
||||
enum { NumAlphaMaps=14 };
|
||||
@ -115,19 +93,19 @@ public:
|
||||
OPT_SHADOWCOLOR,
|
||||
OPT_LODBIAS
|
||||
};
|
||||
|
||||
|
||||
enum RenderPath {
|
||||
// If no rendering path is configured explicitly, the renderer
|
||||
// will choose the path when Open() is called.
|
||||
RP_DEFAULT,
|
||||
|
||||
|
||||
// Classic fixed function.
|
||||
RP_FIXED,
|
||||
|
||||
|
||||
// Use (GL 2.0) vertex shaders for T&L when possible.
|
||||
RP_VERTEXSHADER
|
||||
};
|
||||
|
||||
|
||||
// stats class - per frame counts of number of draw calls, poly counts etc
|
||||
struct Stats {
|
||||
// set all stats to zero
|
||||
@ -141,7 +119,7 @@ public:
|
||||
m_BlendSplats+=rhs.m_BlendSplats;
|
||||
return *this;
|
||||
}
|
||||
// count of the number of stats added together
|
||||
// count of the number of stats added together
|
||||
size_t m_Counter;
|
||||
// number of draw calls per frame - total DrawElements + Begin/End immediate mode loops
|
||||
size_t m_DrawCalls;
|
||||
@ -153,7 +131,7 @@ public:
|
||||
size_t m_BlendSplats;
|
||||
};
|
||||
|
||||
// renderer options
|
||||
// renderer options
|
||||
struct Options {
|
||||
bool m_NoVBO;
|
||||
bool m_Shadows;
|
||||
@ -172,11 +150,11 @@ public:
|
||||
|
||||
// resize renderer view
|
||||
void Resize(int width,int height);
|
||||
|
||||
// set/get boolean renderer option
|
||||
|
||||
// set/get boolean renderer option
|
||||
void SetOptionBool(enum Option opt,bool value);
|
||||
bool GetOptionBool(enum Option opt) const;
|
||||
// set/get RGBA color renderer option
|
||||
// set/get RGBA color renderer option
|
||||
void SetOptionColor(enum Option opt,const RGBAColor& value);
|
||||
void SetOptionFloat(enum Option opt, float val);
|
||||
const RGBAColor& GetOptionColor(enum Option opt) const;
|
||||
@ -184,7 +162,7 @@ public:
|
||||
RenderPath GetRenderPath() const { return m_Options.m_RenderPath; }
|
||||
static CStr GetRenderPathName(RenderPath rp);
|
||||
static RenderPath GetRenderPathByName(CStr name);
|
||||
|
||||
|
||||
// return view width
|
||||
int GetWidth() const { return m_Width; }
|
||||
// return view height
|
||||
@ -196,7 +174,7 @@ public:
|
||||
void BeginFrame();
|
||||
// force rendering of any batched objects
|
||||
void FlushFrame();
|
||||
// signal frame end : implicitly flushes batched objects
|
||||
// signal frame end : implicitly flushes batched objects
|
||||
void EndFrame();
|
||||
|
||||
// set color used to clear screen in BeginFrame()
|
||||
@ -219,9 +197,9 @@ public:
|
||||
void Submit(CParticleSys* psys);
|
||||
void Submit(COverlay* overlay);
|
||||
|
||||
// basic primitive rendering operations in 2 and 3D; handy for debugging stuff, but also useful in
|
||||
// editor tools (eg for highlighting specific terrain patches)
|
||||
// note:
|
||||
// basic primitive rendering operations in 2 and 3D; handy for debugging stuff, but also useful in
|
||||
// editor tools (eg for highlighting specific terrain patches)
|
||||
// note:
|
||||
// * all 3D vertices specified in world space
|
||||
// * primitive operations rendered immediatedly, never batched
|
||||
// * primitives rendered in current material (set via SetMaterial)
|
||||
@ -266,21 +244,22 @@ public:
|
||||
int LoadAlphaMaps();
|
||||
void UnloadAlphaMaps();
|
||||
|
||||
// load textures for the active water type.
|
||||
// return a negative error code if anything along the way fails.
|
||||
// called via delay-load mechanism.
|
||||
int LoadWaterTextures();
|
||||
void UnloadWaterTextures();
|
||||
|
||||
// return stats accumulated for current frame
|
||||
const Stats& GetStats() { return m_Stats; }
|
||||
|
||||
// return the current light environment
|
||||
const CLightEnv &GetLightEnv() { return *m_LightEnv; }
|
||||
|
||||
|
||||
// return the current camera
|
||||
const CCamera& GetCamera() const { return m_Camera; }
|
||||
|
||||
|
||||
/**
|
||||
* GetWaterManager: Return the renderer's water manager.
|
||||
*
|
||||
* @return the WaterManager object used by the renderer
|
||||
*/
|
||||
WaterManager* GetWaterManager() { return m_WaterManager; }
|
||||
|
||||
/**
|
||||
* SetFastPlayerColor: Tell the renderer which path to take for
|
||||
* player colored models. Both paths should provide the same visual
|
||||
@ -291,7 +270,7 @@ public:
|
||||
* is printed and the slow path is used instead.
|
||||
*/
|
||||
void SetFastPlayerColor(bool fast);
|
||||
|
||||
|
||||
protected:
|
||||
friend struct CRendererInternals;
|
||||
friend class CVertexBuffer;
|
||||
@ -303,6 +282,7 @@ protected:
|
||||
friend class RenderPathVertexShader;
|
||||
friend class HWLightingModelRenderer;
|
||||
friend class InstancingModelRenderer;
|
||||
friend class TerrainRenderer;
|
||||
|
||||
// scripting
|
||||
jsval JSI_GetFastPlayerColor(JSContext*);
|
||||
@ -310,25 +290,17 @@ protected:
|
||||
jsval JSI_GetRenderPath(JSContext*);
|
||||
void JSI_SetRenderPath(JSContext* ctx, jsval newval);
|
||||
static void ScriptingInit();
|
||||
|
||||
|
||||
// patch rendering stuff
|
||||
void RenderPatchSubmissions();
|
||||
void RenderPatches();
|
||||
void RenderWater();
|
||||
|
||||
// model rendering stuff
|
||||
void RenderModels();
|
||||
void RenderTransparentModels();
|
||||
|
||||
// shadow rendering stuff
|
||||
void CreateShadowMap();
|
||||
void RenderShadowMap();
|
||||
void ApplyShadowMap();
|
||||
void BuildTransformation(const CVector3D& pos,const CVector3D& right,const CVector3D& up,
|
||||
const CVector3D& dir,CMatrix3D& result);
|
||||
void ConstructLightTransform(const CVector3D& pos,const CVector3D& lightdir,CMatrix3D& result);
|
||||
void CalcShadowMatrices();
|
||||
void CalcShadowBounds(CBound& bounds);
|
||||
|
||||
// RENDERER DATA:
|
||||
/// Private data that is not needed by inline functions
|
||||
@ -361,18 +333,10 @@ protected:
|
||||
CSHCoeffs m_SHCoeffsTerrain;
|
||||
// ogl_tex handle of composite alpha map (all the alpha maps packed into one texture)
|
||||
Handle m_hCompositeAlphaMap;
|
||||
// handle of shadow map
|
||||
u32 m_ShadowMap;
|
||||
// width, height of shadow map
|
||||
u32 m_ShadowMapWidth,m_ShadowMapHeight;
|
||||
// object space bound of shadow casting objects
|
||||
CBound m_ShadowBound;
|
||||
// per-frame flag: has the shadow map been rendered this frame?
|
||||
bool m_ShadowRendered;
|
||||
// projection matrix of shadow casting light
|
||||
CMatrix3D m_LightProjection;
|
||||
// transformation matrix of shadow casting light
|
||||
CMatrix3D m_LightTransform;
|
||||
// object space bound of shadow casting objects
|
||||
CBound m_ShadowBound;
|
||||
// coordinates of each (untransformed) alpha map within the packed texture
|
||||
struct {
|
||||
float u0,u1,v0,v1;
|
||||
@ -390,14 +354,20 @@ protected:
|
||||
Stats m_Stats;
|
||||
// active textures on each unit
|
||||
GLuint m_ActiveTextures[MaxTextureUnits];
|
||||
|
||||
|
||||
// Additional state that is only available when the vertex shader
|
||||
// render path is used (according to m_Options.m_RenderPath)
|
||||
RenderPathVertexShader* m_VertexShader;
|
||||
|
||||
/// If false, use a multipass fallback for player colors.
|
||||
bool m_FastPlayerColor;
|
||||
|
||||
|
||||
/**
|
||||
* m_WaterManager: the WaterManager object used for water textures and settings
|
||||
* (e.g. water color, water height)
|
||||
*/
|
||||
WaterManager* m_WaterManager;
|
||||
|
||||
/**
|
||||
* m_SortAllTransparent: If true, all transparent models are
|
||||
* rendered using the TransparencyRenderer which performs sorting.
|
||||
@ -406,8 +376,8 @@ protected:
|
||||
* batching renderer when possible.
|
||||
*/
|
||||
bool m_SortAllTransparent;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* m_FastNormals: Use faster normal transformation in the
|
||||
* software transform by multiplying with the bone matrix itself
|
||||
@ -415,9 +385,6 @@ protected:
|
||||
*/
|
||||
bool m_FastNormals;
|
||||
|
||||
// State used by LoadWaterTextures with progressive loading
|
||||
uint cur_loading_water_tex;
|
||||
|
||||
// Various model renderers
|
||||
struct Models {
|
||||
ModelRenderer* NormalFF;
|
||||
@ -426,11 +393,11 @@ protected:
|
||||
ModelRenderer* PlayerHWLit;
|
||||
ModelRenderer* NormalInstancing;
|
||||
ModelRenderer* PlayerInstancing;
|
||||
|
||||
|
||||
ModelRenderer* TranspFF;
|
||||
ModelRenderer* TranspHWLit;
|
||||
ModelRenderer* TranspSortAll;
|
||||
|
||||
|
||||
ModelVertexRendererPtr VertexFF;
|
||||
ModelVertexRendererPtr VertexHWLit;
|
||||
ModelVertexRendererPtr VertexInstancing;
|
||||
|
430
source/renderer/ShadowMap.cpp
Normal file
430
source/renderer/ShadowMap.cpp
Normal file
@ -0,0 +1,430 @@
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : ShadowMap.cpp
|
||||
* Project : Pyrogenesis
|
||||
* Description : Shadow mapping related texture and matrix management
|
||||
*
|
||||
* @author Nicolai Hähnle <nicolai@wildfiregames.com>
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "ogl.h"
|
||||
|
||||
#include "graphics/LightEnv.h"
|
||||
|
||||
#include "maths/Bound.h"
|
||||
#include "maths/MathUtil.h"
|
||||
#include "maths/Matrix3D.h"
|
||||
|
||||
#include "renderer/Renderer.h"
|
||||
#include "renderer/ShadowMap.h"
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ShadowMap implementation
|
||||
|
||||
/**
|
||||
* Struct ShadowMapInternals: Internal data for the ShadowMap implementation
|
||||
*/
|
||||
struct ShadowMapInternals
|
||||
{
|
||||
// handle of shadow map
|
||||
GLuint Texture;
|
||||
// width, height of shadow map
|
||||
u32 Width, Height;
|
||||
// object space bound of shadow casting objects
|
||||
CBound m_ShadowBound;
|
||||
// project light space into projected light space
|
||||
CMatrix3D LightProjection;
|
||||
// transform world space into light space
|
||||
CMatrix3D LightTransform;
|
||||
// transform world space into texture space
|
||||
CMatrix3D TextureMatrix;
|
||||
|
||||
// Helper functions
|
||||
void BuildTransformation(
|
||||
const CVector3D& pos,const CVector3D& right,const CVector3D& up,
|
||||
const CVector3D& dir,CMatrix3D& result);
|
||||
void ConstructLightTransform(const CVector3D& pos,const CVector3D& dir,CMatrix3D& result);
|
||||
void CalcShadowMatrices(const CBound& bound);
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
ShadowMap::ShadowMap()
|
||||
{
|
||||
m = new ShadowMapInternals;
|
||||
m->Texture = 0;
|
||||
}
|
||||
|
||||
|
||||
ShadowMap::~ShadowMap()
|
||||
{
|
||||
if (m->Texture)
|
||||
glDeleteTextures(1, &m->Texture);
|
||||
|
||||
delete m;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// BuildTransformation: build transformation matrix from a position and standard basis vectors
|
||||
// TODO: Shouldn't this be part of CMatrix3D?
|
||||
void ShadowMapInternals::BuildTransformation(
|
||||
const CVector3D& pos,const CVector3D& right,const CVector3D& up,
|
||||
const CVector3D& dir,CMatrix3D& result)
|
||||
{
|
||||
// build basis
|
||||
result._11=right.X;
|
||||
result._12=right.Y;
|
||||
result._13=right.Z;
|
||||
result._14=0;
|
||||
|
||||
result._21=up.X;
|
||||
result._22=up.Y;
|
||||
result._23=up.Z;
|
||||
result._24=0;
|
||||
|
||||
result._31=dir.X;
|
||||
result._32=dir.Y;
|
||||
result._33=dir.Z;
|
||||
result._34=0;
|
||||
|
||||
result._41=0;
|
||||
result._42=0;
|
||||
result._43=0;
|
||||
result._44=1;
|
||||
|
||||
CMatrix3D trans;
|
||||
trans.SetTranslation(-pos.X,-pos.Y,-pos.Z);
|
||||
result=result*trans;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ConstructLightTransform: build transformation matrix for light at given position casting in
|
||||
// given direction
|
||||
void ShadowMapInternals::ConstructLightTransform(const CVector3D& pos,const CVector3D& dir,CMatrix3D& result)
|
||||
{
|
||||
CVector3D right,up;
|
||||
|
||||
CVector3D viewdir = g_Renderer.GetCamera().m_Orientation.GetIn();
|
||||
if (fabs(dir.Y)>0.01f) {
|
||||
up=CVector3D(viewdir.X,(-dir.Z*viewdir.Z-dir.X*dir.X)/dir.Y,viewdir.Z);
|
||||
} else {
|
||||
up=CVector3D(0,0,1);
|
||||
}
|
||||
|
||||
up.Normalize();
|
||||
right=dir.Cross(up);
|
||||
right.Normalize();
|
||||
BuildTransformation(pos,right,up,dir,result);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CalcShadowMatrices: calculate required matrices for shadow map generation - the light's
|
||||
// projection and transformation matrices
|
||||
void ShadowMapInternals::CalcShadowMatrices(const CBound& bounds)
|
||||
{
|
||||
const CLightEnv& lightenv = g_Renderer.GetLightEnv();
|
||||
const CCamera& camera = g_Renderer.GetCamera();
|
||||
int i;
|
||||
|
||||
// get centre of bounds
|
||||
CVector3D centre;
|
||||
bounds.GetCentre(centre);
|
||||
|
||||
// get sunlight direction
|
||||
// ??? RC more optimal light placement?
|
||||
CVector3D lightpos=centre-(lightenv.m_SunDir * 1000);
|
||||
|
||||
// make light transformation matrix
|
||||
ConstructLightTransform(lightpos, lightenv.m_SunDir, LightTransform);
|
||||
|
||||
// transform shadow bounds to light space, calculate near and far bounds
|
||||
CVector3D vp[8];
|
||||
LightTransform.Transform(CVector3D(bounds[0].X,bounds[0].Y,bounds[0].Z),vp[0]);
|
||||
LightTransform.Transform(CVector3D(bounds[1].X,bounds[0].Y,bounds[0].Z),vp[1]);
|
||||
LightTransform.Transform(CVector3D(bounds[0].X,bounds[1].Y,bounds[0].Z),vp[2]);
|
||||
LightTransform.Transform(CVector3D(bounds[1].X,bounds[1].Y,bounds[0].Z),vp[3]);
|
||||
LightTransform.Transform(CVector3D(bounds[0].X,bounds[0].Y,bounds[1].Z),vp[4]);
|
||||
LightTransform.Transform(CVector3D(bounds[1].X,bounds[0].Y,bounds[1].Z),vp[5]);
|
||||
LightTransform.Transform(CVector3D(bounds[0].X,bounds[1].Y,bounds[1].Z),vp[6]);
|
||||
LightTransform.Transform(CVector3D(bounds[1].X,bounds[1].Y,bounds[1].Z),vp[7]);
|
||||
|
||||
float left=vp[0].X;
|
||||
float right=vp[0].X;
|
||||
float top=vp[0].Y;
|
||||
float bottom=vp[0].Y;
|
||||
float znear=vp[0].Z;
|
||||
float zfar=vp[0].Z;
|
||||
|
||||
for (i=1;i<8;i++) {
|
||||
if (vp[i].X<left) left=vp[i].X;
|
||||
else if (vp[i].X>right) right=vp[i].X;
|
||||
|
||||
if (vp[i].Y<bottom) bottom=vp[i].Y;
|
||||
else if (vp[i].Y>top) top=vp[i].Y;
|
||||
|
||||
if (vp[i].Z<znear) znear=vp[i].Z;
|
||||
else if (vp[i].Z>zfar) zfar=vp[i].Z;
|
||||
}
|
||||
|
||||
// shift near and far clip planes slightly to avoid artifacts with points
|
||||
// exactly on the clip planes
|
||||
znear=(znear<camera.GetNearPlane()+0.01f) ? camera.GetNearPlane() : znear-0.01f;
|
||||
zfar+=0.01f;
|
||||
|
||||
LightProjection.SetZero();
|
||||
LightProjection._11=2/(right-left);
|
||||
LightProjection._22=2/(top-bottom);
|
||||
LightProjection._33=2/(zfar-znear);
|
||||
LightProjection._14=-(right+left)/(right-left);
|
||||
LightProjection._24=-(top+bottom)/(top-bottom);
|
||||
LightProjection._34=-(zfar+znear)/(zfar-znear);
|
||||
LightProjection._44=1;
|
||||
|
||||
// calculate texture matrix
|
||||
CMatrix3D tmp2;
|
||||
CMatrix3D texturematrix;
|
||||
|
||||
float dx=0.5f*float(g_Renderer.GetWidth())/float(Width);
|
||||
float dy=0.5f*float(g_Renderer.GetHeight())/float(Height);
|
||||
TextureMatrix.SetTranslation(dx,dy,0); // transform (-0.5, 0.5) to (0,1) - texture space
|
||||
tmp2.SetScaling(dx,dy,0); // scale (-1,1) to (-0.5,0.5)
|
||||
TextureMatrix = TextureMatrix*tmp2;
|
||||
|
||||
TextureMatrix = TextureMatrix * LightProjection; // transform light -> projected light space (-1 to 1)
|
||||
TextureMatrix = TextureMatrix * LightTransform; // transform world -> light space
|
||||
|
||||
#if 0
|
||||
|
||||
#if 0
|
||||
// TODO, RC - trim against frustum?
|
||||
// get points of view frustum in world space
|
||||
CVector3D frustumPts[8];
|
||||
m_Camera.GetFrustumPoints(frustumPts);
|
||||
|
||||
// transform to light space
|
||||
for (i=0;i<8;i++) {
|
||||
m_LightTransform.Transform(frustumPts[i],vp[i]);
|
||||
}
|
||||
|
||||
float left1=vp[0].X;
|
||||
float right1=vp[0].X;
|
||||
float top1=vp[0].Y;
|
||||
float bottom1=vp[0].Y;
|
||||
float znear1=vp[0].Z;
|
||||
float zfar1=vp[0].Z;
|
||||
|
||||
for (int i=1;i<8;i++) {
|
||||
if (vp[i].X<left1) left1=vp[i].X;
|
||||
else if (vp[i].X>right1) right1=vp[i].X;
|
||||
|
||||
if (vp[i].Y<bottom1) bottom1=vp[i].Y;
|
||||
else if (vp[i].Y>top1) top1=vp[i].Y;
|
||||
|
||||
if (vp[i].Z<znear1) znear1=vp[i].Z;
|
||||
else if (vp[i].Z>zfar1) zfar1=vp[i].Z;
|
||||
}
|
||||
|
||||
left=max(left,left1);
|
||||
right=min(right,right1);
|
||||
top=min(top,top1);
|
||||
bottom=max(bottom,bottom1);
|
||||
znear=max(znear,znear1);
|
||||
zfar=min(zfar,zfar1);
|
||||
#endif
|
||||
|
||||
// experimental stuff, do not use ..
|
||||
// TODO, RC - desperately need to improve resolution here if we're using shadow maps; investigate
|
||||
// feasibility of PSMs
|
||||
|
||||
// transform light space bounds to image space - TODO, RC: safe to just use 3d transform here?
|
||||
CVector4D vph[8];
|
||||
for (i=0;i<8;i++) {
|
||||
CVector4D tmp(vp[i].X,vp[i].Y,vp[i].Z,1.0f);
|
||||
m_LightProjection.Transform(tmp,vph[i]);
|
||||
vph[i][0]/=vph[i][2];
|
||||
vph[i][1]/=vph[i][2];
|
||||
}
|
||||
|
||||
// find the two points furthest apart
|
||||
int p0,p1;
|
||||
float maxdistsqrd=-1;
|
||||
for (i=0;i<8;i++) {
|
||||
for (int j=i+1;j<8;j++) {
|
||||
float dx=vph[i][0]-vph[j][0];
|
||||
float dy=vph[i][1]-vph[j][1];
|
||||
float distsqrd=dx*dx+dy*dy;
|
||||
if (distsqrd>maxdistsqrd) {
|
||||
p0=i;
|
||||
p1=j;
|
||||
maxdistsqrd=distsqrd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now we want to rotate the camera such that the longest axis lies the diagonal at 45 degrees -
|
||||
// get angle between points
|
||||
float angle=atan2(vph[p0][1]-vph[p1][1],vph[p0][0]-vph[p1][0]);
|
||||
float rotation=-angle;
|
||||
|
||||
// build rotation matrix
|
||||
CQuaternion quat;
|
||||
quat.FromAxisAngle(lightdir,rotation);
|
||||
CMatrix3D m;
|
||||
quat.ToMatrix(m);
|
||||
|
||||
// rotate up vector by given rotation
|
||||
CVector3D up(m_LightTransform._21,m_LightTransform._22,m_LightTransform._23);
|
||||
up=m.Rotate(up);
|
||||
up.Normalize(); // TODO, RC - required??
|
||||
|
||||
// rebuild right vector
|
||||
CVector3D rightvec;
|
||||
rightvec=lightdir.Cross(up);
|
||||
rightvec.Normalize();
|
||||
BuildTransformation(lightpos,rightvec,up,lightdir,m_LightTransform);
|
||||
|
||||
// retransform points
|
||||
m_LightTransform.Transform(CVector3D(bounds[0].X,bounds[0].Y,bounds[0].Z),vp[0]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[1].X,bounds[0].Y,bounds[0].Z),vp[1]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[0].X,bounds[1].Y,bounds[0].Z),vp[2]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[1].X,bounds[1].Y,bounds[0].Z),vp[3]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[0].X,bounds[0].Y,bounds[1].Z),vp[4]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[1].X,bounds[0].Y,bounds[1].Z),vp[5]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[0].X,bounds[1].Y,bounds[1].Z),vp[6]);
|
||||
m_LightTransform.Transform(CVector3D(bounds[1].X,bounds[1].Y,bounds[1].Z),vp[7]);
|
||||
|
||||
// recalculate projection
|
||||
left=vp[0].X;
|
||||
right=vp[0].X;
|
||||
top=vp[0].Y;
|
||||
bottom=vp[0].Y;
|
||||
znear=vp[0].Z;
|
||||
zfar=vp[0].Z;
|
||||
|
||||
for (i=1;i<8;i++) {
|
||||
if (vp[i].X<left) left=vp[i].X;
|
||||
else if (vp[i].X>right) right=vp[i].X;
|
||||
|
||||
if (vp[i].Y<bottom) bottom=vp[i].Y;
|
||||
else if (vp[i].Y>top) top=vp[i].Y;
|
||||
|
||||
if (vp[i].Z<znear) znear=vp[i].Z;
|
||||
else if (vp[i].Z>zfar) zfar=vp[i].Z;
|
||||
}
|
||||
|
||||
// shift near and far clip planes slightly to avoid artifacts with points
|
||||
// exactly on the clip planes
|
||||
znear-=0.01f;
|
||||
zfar+=0.01f;
|
||||
|
||||
m_LightProjection.SetZero();
|
||||
m_LightProjection._11=2/(right-left);
|
||||
m_LightProjection._22=2/(top-bottom);
|
||||
m_LightProjection._33=2/(zfar-znear);
|
||||
m_LightProjection._14=-(right+left)/(right-left);
|
||||
m_LightProjection._24=-(top+bottom)/(top-bottom);
|
||||
m_LightProjection._34=-(zfar+znear)/(zfar-znear);
|
||||
m_LightProjection._44=1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Prepare for the next frame: Matrix calculations and texture creation if necessary
|
||||
void ShadowMap::SetupFrame(const CBound& visibleBounds)
|
||||
{
|
||||
m->CalcShadowMatrices(visibleBounds);
|
||||
|
||||
if (!m->Texture)
|
||||
{
|
||||
// get shadow map size as next power of two up from view width and height
|
||||
m->Width = g_Renderer.GetWidth();
|
||||
m->Width = RoundUpToPowerOf2(m->Width);
|
||||
m->Height = g_Renderer.GetHeight();
|
||||
m->Height = RoundUpToPowerOf2(m->Height);
|
||||
|
||||
// create texture object - initially filled with white, so clamp to edge clamps to correct color
|
||||
glGenTextures(1, &m->Texture);
|
||||
g_Renderer.BindTexture(0, m->Texture);
|
||||
|
||||
u32 size = m->Width*m->Height;
|
||||
u32* buf=new u32[size];
|
||||
for (uint i=0;i<size;i++) buf[i]=0x00ffffff;
|
||||
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,m->Width,m->Height,0,GL_RGBA,GL_UNSIGNED_BYTE,buf);
|
||||
delete[] buf;
|
||||
|
||||
// set texture parameters
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Set up to render into shadow map texture
|
||||
void ShadowMap::BeginRender()
|
||||
{
|
||||
// HACK HACK: this depends in non-obvious ways on the behaviour of the caller
|
||||
|
||||
CRenderer& renderer = g_Renderer;
|
||||
int renderWidth = renderer.GetWidth();
|
||||
int renderHeight = renderer.GetHeight();
|
||||
|
||||
// clear buffers
|
||||
glClearColor(1,1,1,0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
// setup viewport
|
||||
glViewport(0, 0, renderWidth, renderHeight);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadMatrixf(&m->LightProjection._11);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadMatrixf(&m->LightTransform._11);
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(1,1, renderWidth-2, renderHeight-2);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Finish rendering into shadow map texture
|
||||
void ShadowMap::EndRender()
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
// copy result into shadow map texture
|
||||
g_Renderer.BindTexture(0, m->Texture);
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, g_Renderer.GetWidth(), g_Renderer.GetHeight());
|
||||
|
||||
// restore matrix stack
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Retrieve the texture handle and texture matrix for shadowing
|
||||
GLuint ShadowMap::GetTexture()
|
||||
{
|
||||
return m->Texture;
|
||||
}
|
||||
|
||||
const CMatrix3D& ShadowMap::GetTextureMatrix()
|
||||
{
|
||||
return m->TextureMatrix;
|
||||
}
|
77
source/renderer/ShadowMap.h
Normal file
77
source/renderer/ShadowMap.h
Normal file
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : ShadowMap.h
|
||||
* Project : Pyrogenesis
|
||||
* Description : Shadow mapping related texture and matrix management
|
||||
*
|
||||
* @author Nicolai Hähnle <nicolai@wildfiregames.com>
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
#ifndef SHADOWMAP_H
|
||||
#define SHADOWMAP_H
|
||||
|
||||
#include "ogl.h"
|
||||
|
||||
class CBound;
|
||||
class CMatrix3D;
|
||||
|
||||
struct ShadowMapInternals;
|
||||
|
||||
/**
|
||||
* Class ShadowMap: Maintain the shadow map texture and perform necessary OpenGL setup,
|
||||
* including matrix calculations.
|
||||
*
|
||||
* The class will automatically generate a texture the first time the shadow map is rendered into.
|
||||
* The texture will not be resized afterwards.
|
||||
*
|
||||
* @todo use depth textures for self-shadowing
|
||||
*/
|
||||
class ShadowMap
|
||||
{
|
||||
public:
|
||||
ShadowMap();
|
||||
~ShadowMap();
|
||||
|
||||
/**
|
||||
* SetupFrame: Setup shadow map texture and matrices for this frame.
|
||||
*
|
||||
* @param visibleBounds bound around objects that are visible on the screen
|
||||
*/
|
||||
void SetupFrame(const CBound& visibleBounds);
|
||||
|
||||
/**
|
||||
* BeginRender: Set OpenGL state for rendering into the shadow map texture.
|
||||
*
|
||||
* @todo this depends in non-obvious ways on the behaviour of the call-site
|
||||
*/
|
||||
void BeginRender();
|
||||
|
||||
/**
|
||||
* EndRender: Finish rendering into the shadow map.
|
||||
*
|
||||
* @todo this depends in non-obvious ways on the behaviour of the call-site
|
||||
*/
|
||||
void EndRender();
|
||||
|
||||
/**
|
||||
* GetTexture: Retrieve the OpenGL texture object name that contains the shadow map.
|
||||
*
|
||||
* @return the texture name of the shadow map texture
|
||||
*/
|
||||
GLuint GetTexture();
|
||||
|
||||
/**
|
||||
* GetTextureMatrix: Retrieve the world-space to shadow map texture coordinates
|
||||
* transformation matrix.
|
||||
*
|
||||
* @return the matrix that transforms world-space coordinates into homogenous
|
||||
* shadow map texture coordinates
|
||||
*/
|
||||
const CMatrix3D& GetTextureMatrix();
|
||||
|
||||
private:
|
||||
ShadowMapInternals* m;
|
||||
};
|
||||
|
||||
#endif // SHADOWMAP_H
|
402
source/renderer/TerrainRenderer.cpp
Normal file
402
source/renderer/TerrainRenderer.cpp
Normal file
@ -0,0 +1,402 @@
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : TerrainRenderer.cpp
|
||||
* Project : Pyrogenesis
|
||||
* Description : Terrain rendering (everything related to patches and
|
||||
* : water) is encapsulated in TerrainRenderer
|
||||
*
|
||||
* @author Nicolai Hähnle <nicolai@wildfiregames.com>
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "graphics/Camera.h"
|
||||
#include "graphics/Patch.h"
|
||||
#include "graphics/Terrain.h"
|
||||
|
||||
#include "maths/MathUtil.h"
|
||||
|
||||
#include "ps/Game.h"
|
||||
#include "ps/Profile.h"
|
||||
|
||||
#include "simulation/LOSManager.h"
|
||||
|
||||
#include "renderer/PatchRData.h"
|
||||
#include "renderer/Renderer.h"
|
||||
#include "renderer/TerrainRenderer.h"
|
||||
#include "renderer/WaterManager.h"
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TerrainRenderer implementation
|
||||
|
||||
|
||||
/**
|
||||
* TerrainRenderer keeps track of which phase it is in, to detect
|
||||
* when Submit, PrepareForRendering etc. are called in the wrong order.
|
||||
*/
|
||||
enum Phase {
|
||||
Phase_Submit,
|
||||
Phase_Render
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Struct TerrainRendererInternals: Internal variables used by the TerrainRenderer class.
|
||||
*/
|
||||
struct TerrainRendererInternals
|
||||
{
|
||||
/// Which phase (submitting or rendering patches) are we in right now?
|
||||
Phase phase;
|
||||
|
||||
/**
|
||||
* VisiblePatches: Patches that were submitted for this frame
|
||||
*
|
||||
* @todo Merge this list with CPatchRData list
|
||||
*/
|
||||
std::vector<CPatch*> visiblePatches;
|
||||
};
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
TerrainRenderer::TerrainRenderer()
|
||||
{
|
||||
m = new TerrainRendererInternals();
|
||||
m->phase = Phase_Submit;
|
||||
}
|
||||
|
||||
TerrainRenderer::~TerrainRenderer()
|
||||
{
|
||||
delete m;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Submit a patch for rendering
|
||||
void TerrainRenderer::Submit(CPatch* patch)
|
||||
{
|
||||
debug_assert(m->phase == Phase_Submit);
|
||||
|
||||
CPatchRData* data=(CPatchRData*) patch->GetRenderData();
|
||||
if (data == 0)
|
||||
{
|
||||
// no renderdata for patch, create it now
|
||||
data = new CPatchRData(patch);
|
||||
patch->SetRenderData(data);
|
||||
}
|
||||
data->Update();
|
||||
|
||||
m->visiblePatches.push_back(patch);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Prepare for rendering
|
||||
void TerrainRenderer::PrepareForRendering()
|
||||
{
|
||||
debug_assert(m->phase == Phase_Submit);
|
||||
|
||||
m->phase = Phase_Render;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Clear submissions lists
|
||||
void TerrainRenderer::EndFrame()
|
||||
{
|
||||
debug_assert(m->phase == Phase_Render);
|
||||
|
||||
m->visiblePatches.clear();
|
||||
|
||||
m->phase = Phase_Submit;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Query if patches have been submitted this frame
|
||||
bool TerrainRenderer::HaveSubmissions()
|
||||
{
|
||||
return m->visiblePatches.size() > 0;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Full-featured terrain rendering with blending and everything
|
||||
void TerrainRenderer::RenderTerrain()
|
||||
{
|
||||
debug_assert(m->phase == Phase_Render);
|
||||
|
||||
// switch on required client states
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
// render everything
|
||||
// set up texture environment for base pass
|
||||
MICROLOG(L"base splat textures");
|
||||
pglActiveTextureARB(GL_TEXTURE0);
|
||||
pglClientActiveTextureARB(GL_TEXTURE0);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
|
||||
|
||||
// Set alpha to 1.0
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_CONSTANT);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
||||
float one[4] = { 1.f, 1.f, 1.f, 1.f };
|
||||
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, one);
|
||||
|
||||
for(uint i = 0; i < m->visiblePatches.size(); ++i)
|
||||
{
|
||||
CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
|
||||
patchdata->RenderBase();
|
||||
}
|
||||
|
||||
// render blends
|
||||
// switch on the composite alpha map texture
|
||||
(void)ogl_tex_bind(g_Renderer.m_hCompositeAlphaMap, 1);
|
||||
|
||||
// switch on second uv set
|
||||
pglClientActiveTextureARB(GL_TEXTURE1);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
// setup additional texenv required by blend pass
|
||||
pglActiveTextureARB(GL_TEXTURE1);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// switch on blending
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// no need to write to the depth buffer a second time
|
||||
glDepthMask(0);
|
||||
|
||||
// render blend passes for each patch
|
||||
for(uint i = 0; i < m->visiblePatches.size(); ++i)
|
||||
{
|
||||
CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
|
||||
patchdata->RenderBlends();
|
||||
}
|
||||
|
||||
// restore OpenGL state
|
||||
glDepthMask(1);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
pglClientActiveTextureARB(GL_TEXTURE1);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
g_Renderer.BindTexture(1,0);
|
||||
|
||||
pglClientActiveTextureARB(GL_TEXTURE0);
|
||||
pglActiveTextureARB(GL_TEXTURE0);
|
||||
|
||||
// switch off all client states
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Render un-textured patches as polygons
|
||||
void TerrainRenderer::RenderPatches()
|
||||
{
|
||||
debug_assert(m->phase == Phase_Render);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
for(uint i = 0; i < m->visiblePatches.size(); ++i)
|
||||
{
|
||||
CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
|
||||
patchdata->RenderStreams(STREAM_POS);
|
||||
}
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Render outlines of submitted patches as lines
|
||||
void TerrainRenderer::RenderOutlines()
|
||||
{
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
for(uint i = 0; i < m->visiblePatches.size(); ++i)
|
||||
{
|
||||
CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
|
||||
patchdata->RenderOutline();
|
||||
}
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Render water that is part of the terrain
|
||||
void TerrainRenderer::RenderWater()
|
||||
{
|
||||
PROFILE(" render water ");
|
||||
|
||||
//Fresnel effect
|
||||
CCamera* Camera=g_Game->GetView()->GetCamera();
|
||||
CVector3D CamFace=Camera->m_Orientation.GetIn();
|
||||
CamFace.Normalize();
|
||||
float FresnelScalar = CamFace.Dot( CVector3D(0.0f, -1.0f, 0.0f) );
|
||||
//Invert and set boundaries
|
||||
FresnelScalar = (1 - FresnelScalar) * 0.4f + 0.6f;
|
||||
|
||||
const int DX[] = {1,1,0,0};
|
||||
const int DZ[] = {0,1,1,0};
|
||||
|
||||
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
|
||||
int mapSize = terrain->GetVerticesPerSide();
|
||||
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
|
||||
WaterManager* WaterMgr = g_Renderer.GetWaterManager();
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
double time = get_time();
|
||||
|
||||
double period = 1.6;
|
||||
int curTex = (int)(time*60/period) % 60;
|
||||
ogl_tex_bind(WaterMgr->m_WaterTexture[curTex], 0);
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
float tx = -fmod(time, 20.0)/20.0;
|
||||
float ty = fmod(time, 35.0)/35.0;
|
||||
glTranslatef(tx, ty, 0);
|
||||
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
||||
|
||||
// Set the proper LOD bias
|
||||
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
for(size_t i=0; i<m->visiblePatches.size(); i++)
|
||||
{
|
||||
CPatch* patch = m->visiblePatches[i];
|
||||
|
||||
for(int dx=0; dx<PATCH_SIZE; dx++)
|
||||
{
|
||||
for(int dz=0; dz<PATCH_SIZE; dz++)
|
||||
{
|
||||
int x = (patch->m_X*PATCH_SIZE + dx);
|
||||
int z = (patch->m_Z*PATCH_SIZE + dz);
|
||||
|
||||
// is any corner of the tile below the water height? if not, no point rendering it
|
||||
bool shouldRender = false;
|
||||
for(int j=0; j<4; j++)
|
||||
{
|
||||
float terrainHeight = terrain->getVertexGroundLevel(x + DX[j], z + DZ[j]);
|
||||
if(terrainHeight < WaterMgr->m_WaterHeight)
|
||||
{
|
||||
shouldRender = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!shouldRender)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for(int j=0; j<4; j++)
|
||||
{
|
||||
int ix = x + DX[j];
|
||||
int iz = z + DZ[j];
|
||||
|
||||
float vertX = ix * CELL_SIZE;
|
||||
float vertZ = iz * CELL_SIZE;
|
||||
|
||||
float terrainHeight = terrain->getVertexGroundLevel(ix, iz);
|
||||
|
||||
float alpha = clamp(
|
||||
(WaterMgr->m_WaterHeight - terrainHeight) / WaterMgr->m_WaterFullDepth + WaterMgr->m_WaterAlphaOffset,
|
||||
-100.0f, WaterMgr->m_WaterMaxAlpha);
|
||||
|
||||
float losMod = 1.0f;
|
||||
for(int k=0; k<4; k++)
|
||||
{
|
||||
int tx = ix - DX[k];
|
||||
int tz = iz - DZ[k];
|
||||
|
||||
if(tx >= 0 && tz >= 0 && tx <= mapSize-2 && tz <= mapSize-2)
|
||||
{
|
||||
ELOSStatus s = losMgr->GetStatus(tx, tz, g_Game->GetLocalPlayer());
|
||||
if(s == LOS_EXPLORED && losMod > 0.7f)
|
||||
losMod = 0.7f;
|
||||
else if(s==LOS_UNEXPLORED && losMod > 0.0f)
|
||||
losMod = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
glColor4f(WaterMgr->m_WaterColor.r*losMod, WaterMgr->m_WaterColor.g*losMod, WaterMgr->m_WaterColor.b*losMod, alpha * FresnelScalar);
|
||||
pglMultiTexCoord2fARB(GL_TEXTURE0, vertX/16.0f, vertZ/16.0f);
|
||||
glVertex3f(vertX, WaterMgr->m_WaterHeight, vertZ);
|
||||
}
|
||||
} //end of x loop
|
||||
} //end of z loop
|
||||
}
|
||||
|
||||
glEnd();
|
||||
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
glDepthMask(GL_TRUE);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
void TerrainRenderer::ApplyShadowMap(GLuint shadowmaphandle)
|
||||
{
|
||||
debug_assert(m->phase == Phase_Render);
|
||||
|
||||
g_Renderer.BindTexture(0, shadowmaphandle);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
||||
|
||||
glColor3f(1,1,1);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_DST_COLOR,GL_ZERO);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
for (uint i = 0; i < m->visiblePatches.size(); ++i)
|
||||
{
|
||||
CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
|
||||
patchdata->RenderStreams(STREAM_POS|STREAM_POSTOUV0);
|
||||
}
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
112
source/renderer/TerrainRenderer.h
Normal file
112
source/renderer/TerrainRenderer.h
Normal file
@ -0,0 +1,112 @@
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : TerrainRenderer.h
|
||||
* Project : Pyrogenesis
|
||||
* Description : Terrain rendering (everything related to patches and
|
||||
* : water) is encapsulated in TerrainRenderer
|
||||
*
|
||||
* @author Nicolai Hähnle <nicolai@wildfiregames.com>
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
#ifndef TERRAINRENDERER_H
|
||||
#define TERRAINRENDERER_H
|
||||
|
||||
class CPatch;
|
||||
class WaterManager;
|
||||
|
||||
struct TerrainRendererInternals;
|
||||
|
||||
/**
|
||||
* Class TerrainRenderer: Render everything related to the terrain,
|
||||
* especially patches and water.
|
||||
*/
|
||||
class TerrainRenderer
|
||||
{
|
||||
public:
|
||||
TerrainRenderer();
|
||||
~TerrainRenderer();
|
||||
|
||||
/**
|
||||
* Submit: Add a patch for rendering in this frame.
|
||||
*
|
||||
* preconditions : PrepareForRendering must not have been called
|
||||
* for this frame yet.
|
||||
* The patch must not have been submitted in this frame yet (i.e. you
|
||||
* can only submit a frame once).
|
||||
*
|
||||
* @param patch the patch
|
||||
*/
|
||||
void Submit(CPatch* patch);
|
||||
|
||||
/**
|
||||
* PrepareForRendering: Prepare internal data structures like vertex
|
||||
* buffers for rendering.
|
||||
*
|
||||
* All patches must have been submitted before the call to
|
||||
* PrepareForRendering.
|
||||
* PrepareForRendering must be called before any rendering calls.
|
||||
*/
|
||||
void PrepareForRendering();
|
||||
|
||||
/**
|
||||
* EndFrame: Remove all patches from the list of submitted patches.
|
||||
*/
|
||||
void EndFrame();
|
||||
|
||||
/**
|
||||
* HaveSubmissions: Query whether any patches have been submitted
|
||||
* for this frame.
|
||||
*
|
||||
* @return @c true if a patch has been submitted for this frame,
|
||||
* @c false otherwise.
|
||||
*/
|
||||
bool HaveSubmissions();
|
||||
|
||||
/**
|
||||
* RenderTerrain: Render textured terrain (including blends between
|
||||
* different terrain types).
|
||||
*
|
||||
* preconditions : PrepareForRendering must have been called this
|
||||
* frame before calling RenderTerrain.
|
||||
*/
|
||||
void RenderTerrain();
|
||||
|
||||
/**
|
||||
* RenderPatches: Render all patches un-textured as polygons.
|
||||
*
|
||||
* preconditions : PrepareForRendering must have been called this
|
||||
* frame before calling RenderPatches.
|
||||
*/
|
||||
void RenderPatches();
|
||||
|
||||
/**
|
||||
* RenderOutlines: Render the outline of patches as lines.
|
||||
*
|
||||
* preconditions : PrepareForRendering must have been called this
|
||||
* frame before calling RenderOutline.
|
||||
*/
|
||||
void RenderOutlines();
|
||||
|
||||
/**
|
||||
* RenderWater: Render water for all patches that have been submitted
|
||||
* this frame.
|
||||
*
|
||||
* preconditions : PrepareForRendering must have been called this
|
||||
* frame before calling RenderOutline.
|
||||
*/
|
||||
void RenderWater();
|
||||
|
||||
/**
|
||||
* ApplyShadowMap: transition measure during refactoring
|
||||
*
|
||||
* @todo fix this
|
||||
* @deprecated
|
||||
*/
|
||||
void ApplyShadowMap(GLuint handle);
|
||||
|
||||
private:
|
||||
TerrainRendererInternals* m;
|
||||
};
|
||||
|
||||
#endif // TERRAINRENDERER_H
|
@ -2,8 +2,8 @@
|
||||
* =========================================================================
|
||||
* File : TransparencyRenderer.h
|
||||
* Project : Pyrogenesis
|
||||
* Description : ModelRenderer implementation that sorts models and/or
|
||||
* : polygons based on distance from viewer, for transparency
|
||||
* Description : ModelRenderer implementation that sorts models and/or
|
||||
* : polygons based on distance from viewer, for transparency
|
||||
* : rendering.
|
||||
*
|
||||
* @author Rich Cross <rich@wildfiregames.com>
|
||||
@ -41,10 +41,10 @@
|
||||
struct PSModelDef : public CModelDefRPrivate
|
||||
{
|
||||
PSModelDef(CModelDefPtr mdef);
|
||||
|
||||
|
||||
/// Static vertex array
|
||||
VertexArray m_Array;
|
||||
|
||||
|
||||
/// UV is static
|
||||
VertexArray::Attribute m_UV;
|
||||
};
|
||||
@ -55,14 +55,14 @@ PSModelDef::PSModelDef(CModelDefPtr mdef)
|
||||
m_UV.type = GL_FLOAT;
|
||||
m_UV.elems = 2;
|
||||
m_Array.AddAttribute(&m_UV);
|
||||
|
||||
|
||||
m_Array.SetNumVertices(mdef->GetNumVertices());
|
||||
m_Array.Layout();
|
||||
|
||||
VertexArrayIterator<float[2]> UVit = m_UV.GetIterator<float[2]>();
|
||||
|
||||
|
||||
ModelRenderer::BuildUV(mdef, UVit);
|
||||
|
||||
|
||||
m_Array.Upload();
|
||||
m_Array.FreeBackingStore();
|
||||
}
|
||||
@ -75,7 +75,7 @@ struct PSModel
|
||||
{
|
||||
PSModel(CModel* model);
|
||||
~PSModel();
|
||||
|
||||
|
||||
/**
|
||||
* BackToFrontIndexSort: Sort polygons by distance to camera for
|
||||
* transparency rendering and fill the indices array appropriately.
|
||||
@ -85,13 +85,13 @@ struct PSModel
|
||||
* @return Square of the estimated distance to the nearest triangle.
|
||||
*/
|
||||
float BackToFrontIndexSort(const CMatrix3D& objToCam);
|
||||
|
||||
|
||||
/// Back-link to the model
|
||||
CModel* m_Model;
|
||||
|
||||
|
||||
/// Dynamic per-CModel vertex array
|
||||
VertexArray m_Array;
|
||||
|
||||
|
||||
/// Position and lighting are recalculated on CPU every frame
|
||||
VertexArray::Attribute m_Position;
|
||||
VertexArray::Attribute m_Color;
|
||||
@ -104,7 +104,7 @@ PSModel::PSModel(CModel* model)
|
||||
: m_Model(model), m_Array(true)
|
||||
{
|
||||
CModelDefPtr mdef = m_Model->GetModelDef();
|
||||
|
||||
|
||||
m_Position.type = GL_FLOAT;
|
||||
m_Position.elems = 3;
|
||||
m_Array.AddAttribute(&m_Position);
|
||||
@ -112,10 +112,10 @@ PSModel::PSModel(CModel* model)
|
||||
m_Color.type = GL_UNSIGNED_BYTE;
|
||||
m_Color.elems = 4;
|
||||
m_Array.AddAttribute(&m_Color);
|
||||
|
||||
|
||||
m_Array.SetNumVertices(mdef->GetNumVertices());
|
||||
m_Array.Layout();
|
||||
|
||||
|
||||
m_Indices = new u16[mdef->GetNumFaces()*3];
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ float PSModel::BackToFrontIndexSort(const CMatrix3D& worldToCam)
|
||||
CModelDefPtr mdef = m_Model->GetModelDef();
|
||||
size_t numFaces = mdef->GetNumFaces();
|
||||
const SModelFace* faces = mdef->GetFaces();
|
||||
|
||||
|
||||
if (IndexSorter.size() < numFaces)
|
||||
IndexSorter.resize(numFaces);
|
||||
|
||||
@ -162,7 +162,7 @@ float PSModel::BackToFrontIndexSort(const CMatrix3D& worldToCam)
|
||||
}
|
||||
|
||||
std::sort(IndexSorter.begin(),IndexSorter.begin()+numFaces,SortFacesByDist());
|
||||
|
||||
|
||||
// now build index list
|
||||
u32 idxidx = 0;
|
||||
for (size_t i = 0; i < numFaces; ++i) {
|
||||
@ -203,13 +203,13 @@ void* PolygonSortModelRenderer::CreateModelData(CModel* model)
|
||||
{
|
||||
CModelDefPtr mdef = model->GetModelDef();
|
||||
PSModelDef* psmdef = (PSModelDef*)mdef->GetRenderData(m);
|
||||
|
||||
|
||||
if (!psmdef)
|
||||
{
|
||||
psmdef = new PSModelDef(mdef);
|
||||
mdef->SetRenderData(m, psmdef);
|
||||
}
|
||||
|
||||
|
||||
return new PSModel(model);
|
||||
}
|
||||
|
||||
@ -240,14 +240,14 @@ void PolygonSortModelRenderer::UpdateModelData(CModel* model, void* data, u32 up
|
||||
// upload everything to vertex buffer
|
||||
psmdl->m_Array.Upload();
|
||||
}
|
||||
|
||||
|
||||
// resort model indices from back to front, according to camera position - and store
|
||||
// the returned sqrd distance to the centre of the nearest triangle
|
||||
PROFILE_START( "sorting transparent" );
|
||||
|
||||
|
||||
CMatrix3D worldToCam;
|
||||
g_Renderer.GetCamera().m_Orientation.GetInverse(worldToCam);
|
||||
|
||||
|
||||
psmdl->BackToFrontIndexSort(worldToCam);
|
||||
PROFILE_END( "sorting transparent" );
|
||||
}
|
||||
@ -257,7 +257,7 @@ void PolygonSortModelRenderer::UpdateModelData(CModel* model, void* data, u32 up
|
||||
void PolygonSortModelRenderer::DestroyModelData(CModel* UNUSED(model), void* data)
|
||||
{
|
||||
PSModel* psmdl = (PSModel*)data;
|
||||
|
||||
|
||||
delete psmdl;
|
||||
}
|
||||
|
||||
@ -277,7 +277,7 @@ void PolygonSortModelRenderer::EndPass(uint streamflags)
|
||||
{
|
||||
if (streamflags & STREAM_UV0) glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
if (streamflags & STREAM_COLOR) glDisableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
@ -288,12 +288,12 @@ void PolygonSortModelRenderer::PrepareModelDef(uint streamflags, CModelDefPtr de
|
||||
if (streamflags & STREAM_UV0)
|
||||
{
|
||||
PSModelDef* psmdef = (PSModelDef*)def->GetRenderData(m);
|
||||
|
||||
|
||||
debug_assert(psmdef);
|
||||
|
||||
|
||||
u8* base = psmdef->m_Array.Bind();
|
||||
GLsizei stride = (GLsizei)psmdef->m_Array.GetStride();
|
||||
|
||||
|
||||
glTexCoordPointer(2, GL_FLOAT, stride, base + psmdef->m_UV.offset);
|
||||
}
|
||||
}
|
||||
@ -304,14 +304,14 @@ void PolygonSortModelRenderer::RenderModel(uint streamflags, CModel* model, void
|
||||
{
|
||||
CModelDefPtr mdef = model->GetModelDef();
|
||||
PSModel* psmdl = (PSModel*)data;
|
||||
|
||||
|
||||
// Setup per-CModel arrays
|
||||
u8* base = psmdl->m_Array.Bind();
|
||||
GLsizei stride = (GLsizei)psmdl->m_Array.GetStride();
|
||||
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, stride, base + psmdl->m_Position.offset);
|
||||
if (streamflags & STREAM_COLOR)
|
||||
glColorPointer(3, psmdl->m_Color.type, stride, base + psmdl->m_Color.offset);
|
||||
glColorPointer(3, psmdl->m_Color.type, stride, base + psmdl->m_Color.offset);
|
||||
|
||||
// render the lot
|
||||
size_t numFaces = mdef->GetNumFaces();
|
||||
@ -335,13 +335,13 @@ struct SModel : public CModelRData
|
||||
{
|
||||
SModel(SortModelRendererInternals* tri, CModel* model);
|
||||
~SModel();
|
||||
|
||||
|
||||
// Back-link to the Model renderer
|
||||
SortModelRendererInternals* m_SMRI;
|
||||
|
||||
|
||||
// Private data of the ModelVertexRenderer
|
||||
void* m_Data;
|
||||
|
||||
|
||||
// Distance to camera (for sorting)
|
||||
float m_Distance;
|
||||
};
|
||||
@ -354,7 +354,7 @@ struct SortModelRendererInternals
|
||||
{
|
||||
/// Vertex renderer used for transform and lighting
|
||||
ModelVertexRendererPtr vertexRenderer;
|
||||
|
||||
|
||||
/// List of submitted models.
|
||||
std::vector<SModel*> models;
|
||||
};
|
||||
@ -392,7 +392,7 @@ void SortModelRenderer::Submit(CModel* model)
|
||||
{
|
||||
CModelRData* rdata = (CModelRData*)model->GetRenderData();
|
||||
SModel* smdl;
|
||||
|
||||
|
||||
if (rdata && rdata->GetKey() == m)
|
||||
{
|
||||
smdl = (SModel*)rdata;
|
||||
@ -405,7 +405,7 @@ void SortModelRenderer::Submit(CModel* model)
|
||||
model->SetDirty(~0u);
|
||||
g_Renderer.LoadTexture(model->GetTexture(), GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
|
||||
m->models.push_back(smdl);
|
||||
}
|
||||
|
||||
@ -420,26 +420,26 @@ struct SortModelsByDist {
|
||||
void SortModelRenderer::PrepareModels()
|
||||
{
|
||||
CMatrix3D worldToCam;
|
||||
|
||||
|
||||
if (m->models.size() == 0)
|
||||
return;
|
||||
|
||||
|
||||
g_Renderer.m_Camera.m_Orientation.GetInverse(worldToCam);
|
||||
|
||||
|
||||
for(std::vector<SModel*>::iterator it = m->models.begin(); it != m->models.end(); ++it)
|
||||
{
|
||||
SModel* smdl = *it;
|
||||
CModel* model = smdl->GetModel();
|
||||
|
||||
|
||||
debug_assert(model->GetRenderData() == smdl);
|
||||
|
||||
|
||||
m->vertexRenderer->UpdateModelData(model, smdl->m_Data, smdl->m_UpdateFlags);
|
||||
smdl->m_UpdateFlags = 0;
|
||||
|
||||
|
||||
CVector3D modelpos = model->GetTransform().GetTranslation();
|
||||
|
||||
|
||||
modelpos = worldToCam.Transform(modelpos);
|
||||
|
||||
|
||||
smdl->m_Distance = modelpos.Z;
|
||||
}
|
||||
|
||||
@ -467,51 +467,51 @@ bool SortModelRenderer::HaveSubmissions()
|
||||
void SortModelRenderer::Render(RenderModifierPtr modifier, u32 flags)
|
||||
{
|
||||
uint pass = 0;
|
||||
|
||||
|
||||
if (m->models.size() == 0)
|
||||
return;
|
||||
|
||||
|
||||
do
|
||||
{
|
||||
u32 streamflags = modifier->BeginPass(pass);
|
||||
CModelDefPtr lastmdef;
|
||||
CTexture* lasttex = 0;
|
||||
|
||||
|
||||
m->vertexRenderer->BeginPass(streamflags);
|
||||
|
||||
|
||||
for(std::vector<SModel*>::iterator it = m->models.begin(); it != m->models.end(); ++it)
|
||||
{
|
||||
SModel* smdl = *it;
|
||||
CModel* mdl = smdl->GetModel();
|
||||
|
||||
|
||||
if (flags & !(mdl->GetFlags() & flags))
|
||||
continue;
|
||||
|
||||
|
||||
debug_assert(smdl->GetKey() == m);
|
||||
|
||||
CModelDefPtr mdef = mdl->GetModelDef();
|
||||
CTexture* tex = mdl->GetTexture();
|
||||
|
||||
|
||||
// Prepare per-CModelDef data if changed
|
||||
if (mdef != lastmdef)
|
||||
{
|
||||
m->vertexRenderer->PrepareModelDef(streamflags, mdef);
|
||||
lastmdef = mdef;
|
||||
}
|
||||
|
||||
|
||||
// Prepare necessary RenderModifier stuff
|
||||
if (tex != lasttex)
|
||||
{
|
||||
modifier->PrepareTexture(pass, tex);
|
||||
lasttex = tex;
|
||||
}
|
||||
|
||||
|
||||
modifier->PrepareModel(pass, mdl);
|
||||
|
||||
|
||||
// Render the model
|
||||
m->vertexRenderer->RenderModel(streamflags, mdl, smdl->m_Data);
|
||||
}
|
||||
|
||||
|
||||
m->vertexRenderer->EndPass(streamflags);
|
||||
} while(!modifier->EndPass(pass++));
|
||||
}
|
||||
@ -547,13 +547,13 @@ u32 TransparentRenderModifier::BeginPass(uint pass)
|
||||
|
||||
// Set the proper LOD bias
|
||||
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
|
||||
|
||||
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER,0.975f);
|
||||
|
||||
// render everything with color writes off to setup depth buffer correctly
|
||||
glColorMask(0,0,0,0);
|
||||
|
||||
|
||||
return STREAM_POS|STREAM_UV0;
|
||||
}
|
||||
else
|
||||
@ -574,10 +574,10 @@ u32 TransparentRenderModifier::BeginPass(uint pass)
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
|
||||
// Set the proper LOD bias
|
||||
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
|
||||
|
||||
|
||||
return STREAM_POS|STREAM_COLOR|STREAM_UV0;
|
||||
}
|
||||
}
|
||||
@ -586,11 +586,11 @@ bool TransparentRenderModifier::EndPass(uint pass)
|
||||
{
|
||||
if (pass == 0)
|
||||
return false; // multi-pass
|
||||
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glDepthMask(1);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -619,7 +619,7 @@ TransparentShadowRenderModifier::~TransparentShadowRenderModifier()
|
||||
u32 TransparentShadowRenderModifier::BeginPass(uint pass)
|
||||
{
|
||||
debug_assert(pass == 0);
|
||||
|
||||
|
||||
glDepthMask(0);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
@ -643,7 +643,7 @@ bool TransparentShadowRenderModifier::EndPass(uint UNUSED(pass))
|
||||
{
|
||||
glDepthMask(1);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
106
source/renderer/WaterManager.cpp
Normal file
106
source/renderer/WaterManager.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : WaterManager.cpp
|
||||
* Project : Pyrogenesis
|
||||
* Description : Water settings (speed, height) and texture management
|
||||
*
|
||||
* @author Nicolai Hähnle <nicolai@wildfiregames.com>
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "lib/timer.h"
|
||||
#include "lib/res/file/vfs.h"
|
||||
#include "lib/res/graphics/tex.h"
|
||||
#include "lib/res/graphics/ogl_tex.h"
|
||||
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Loader.h"
|
||||
|
||||
#include "renderer/WaterManager.h"
|
||||
|
||||
#define LOG_CATEGORY "graphics"
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// WaterManager implementation
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
WaterManager::WaterManager()
|
||||
{
|
||||
// water
|
||||
m_RenderWater = true;
|
||||
m_WaterHeight = 5.0f;
|
||||
m_WaterColor = CColor(0.3f, 0.35f, 0.7f, 1.0f);
|
||||
m_WaterFullDepth = 4.0f;
|
||||
m_WaterMaxAlpha = 0.85f;
|
||||
m_WaterAlphaOffset = -0.05f;
|
||||
m_SWaterTrans=0;
|
||||
m_TWaterTrans=0;
|
||||
m_SWaterSpeed=0.0015f;
|
||||
m_TWaterSpeed=0.0015f;
|
||||
m_SWaterScrollCounter=0;
|
||||
m_TWaterScrollCounter=0;
|
||||
m_WaterCurrentTex=0;
|
||||
|
||||
for (uint i = 0; i < ARRAY_SIZE(m_WaterTexture); i++)
|
||||
m_WaterTexture[i] = 0;
|
||||
|
||||
cur_loading_water_tex = 0;
|
||||
}
|
||||
|
||||
WaterManager::~WaterManager()
|
||||
{
|
||||
// Cleanup if the caller messed up
|
||||
UnloadWaterTextures();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Progressive load of water textures
|
||||
int WaterManager::LoadWaterTextures()
|
||||
{
|
||||
const uint num_textures = ARRAY_SIZE(m_WaterTexture);
|
||||
|
||||
// yield after this time is reached. balances increased progress bar
|
||||
// smoothness vs. slowing down loading.
|
||||
const double end_time = get_time() + 100e-3;
|
||||
|
||||
while (cur_loading_water_tex < num_textures)
|
||||
{
|
||||
char waterName[VFS_MAX_PATH];
|
||||
// TODO: add a member variable and setter for this. (can't make this
|
||||
// a parameter because this function is called via delay-load code)
|
||||
static const char* const water_type = "animation2";
|
||||
snprintf(waterName, ARRAY_SIZE(waterName), "art/textures/terrain/types/water/%s/water%02d.dds", water_type, cur_loading_water_tex+1);
|
||||
Handle ht = ogl_tex_load(waterName);
|
||||
if (ht <= 0)
|
||||
{
|
||||
LOG(ERROR, LOG_CATEGORY, "LoadWaterTextures failed on \"%s\"", waterName);
|
||||
return ht;
|
||||
}
|
||||
m_WaterTexture[cur_loading_water_tex] = ht;
|
||||
RETURN_ERR(ogl_tex_upload(ht));
|
||||
|
||||
cur_loading_water_tex++;
|
||||
LDR_CHECK_TIMEOUT(cur_loading_water_tex, num_textures);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Unload water textures
|
||||
void WaterManager::UnloadWaterTextures()
|
||||
{
|
||||
for(uint i = 0; i < ARRAY_SIZE(m_WaterTexture); i++)
|
||||
{
|
||||
ogl_tex_free(m_WaterTexture[i]);
|
||||
m_WaterTexture[i] = 0;
|
||||
}
|
||||
cur_loading_water_tex = 0; // so they will be reloaded if LoadWaterTextures is called again
|
||||
}
|
68
source/renderer/WaterManager.h
Normal file
68
source/renderer/WaterManager.h
Normal file
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : WaterManager.h
|
||||
* Project : Pyrogenesis
|
||||
* Description : Water settings (speed, height) and texture management
|
||||
*
|
||||
* @author Nicolai Hähnle <nicolai@wildfiregames.com>
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
#ifndef WATERMANAGER_H
|
||||
#define WATERMANAGER_H
|
||||
|
||||
#include "ps/Overlay.h"
|
||||
|
||||
/**
|
||||
* Class WaterManager: Maintain water settings and textures.
|
||||
*
|
||||
* This could be extended to provide more advanced water rendering effects
|
||||
* (refractive/reflective water) in the future.
|
||||
*/
|
||||
class WaterManager
|
||||
{
|
||||
public:
|
||||
Handle m_WaterTexture[60];
|
||||
int m_WaterCurrentTex;
|
||||
CColor m_WaterColor;
|
||||
bool m_RenderWater;
|
||||
bool m_WaterScroll;
|
||||
float m_WaterHeight;
|
||||
float m_WaterMaxAlpha;
|
||||
float m_WaterFullDepth;
|
||||
float m_WaterAlphaOffset;
|
||||
|
||||
float m_SWaterSpeed;
|
||||
float m_TWaterSpeed;
|
||||
float m_SWaterTrans;
|
||||
float m_TWaterTrans;
|
||||
float m_SWaterScrollCounter;
|
||||
float m_TWaterScrollCounter;
|
||||
float m_WaterTexTimer;
|
||||
|
||||
public:
|
||||
WaterManager();
|
||||
~WaterManager();
|
||||
|
||||
/**
|
||||
* LoadWaterTextures: Load water textures from within the
|
||||
* progressive load framework.
|
||||
*
|
||||
* @return 0 if loading has completed, a value from 1 to 100 (in percent of completion)
|
||||
* if more textures need to be loaded and a negative error value on failure.
|
||||
*/
|
||||
int LoadWaterTextures();
|
||||
|
||||
/**
|
||||
* UnloadWaterTextures: Free any loaded water textures and reset the internal state
|
||||
* so that another call to LoadWaterTextures will begin progressive loading.
|
||||
*/
|
||||
void UnloadWaterTextures();
|
||||
|
||||
private:
|
||||
/// State of progressive loading (in # of loaded textures)
|
||||
uint cur_loading_water_tex;
|
||||
};
|
||||
|
||||
|
||||
#endif // WATERMANAGER_H
|
@ -36,6 +36,7 @@
|
||||
#include "scripting/JSInterface_Console.h"
|
||||
#include "scripting/JSInterface_VFS.h"
|
||||
#include "scripting/JSConversions.h"
|
||||
#include "renderer/WaterManager.h"
|
||||
#ifndef NO_GUI
|
||||
# include "gui/scripting/JSInterface_IGUIObject.h"
|
||||
#endif
|
||||
@ -181,7 +182,7 @@ JSBool getEntityTemplate( JSContext* cx, JSObject*, uint argc, jsval* argv, jsva
|
||||
JS_ReportError( cx, "No such template: %s", CStr8(templateName).c_str() );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
|
||||
*rval = OBJECT_TO_JSVAL( v->GetScript() );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
@ -201,7 +202,7 @@ JSBool issueCommand( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* rv
|
||||
|
||||
if (JS_GetClass(JSVAL_TO_OBJECT(argv[0])) == &CEntity::JSI_class)
|
||||
entities.push_back( (ToNative<CEntity>(argv[0])) ->me);
|
||||
else
|
||||
else
|
||||
entities = *EntityCollection::RetrieveSet(cx, JSVAL_TO_OBJECT(argv[0]));
|
||||
|
||||
CNetMessage *msg = CNetMessage::CommandFromJSArgs(entities, cx, argc-1, argv+1);
|
||||
@ -389,7 +390,7 @@ JSBool cancelInterval( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval*
|
||||
}
|
||||
|
||||
|
||||
// Cause the scheduled task (timeout or interval) with the given ID to
|
||||
// Cause the scheduled task (timeout or interval) with the given ID to
|
||||
// no longer be called.
|
||||
// params:
|
||||
// returns:
|
||||
@ -431,7 +432,7 @@ JSBool createServer(JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* rva
|
||||
g_Game = new CGame();
|
||||
if( !g_NetServer )
|
||||
g_NetServer = new CNetServer(g_Game, &g_GameAttributes);
|
||||
|
||||
|
||||
*rval = OBJECT_TO_JSVAL(g_NetServer->GetScript());
|
||||
return( JS_TRUE );
|
||||
}
|
||||
@ -817,7 +818,7 @@ JSBool toggleWater( JSContext* cx, JSObject* UNUSED(globalObject), uint argc, js
|
||||
{
|
||||
REQUIRE_NO_PARAMS( toggleWater );
|
||||
debug_printf("Toggling water!\n");
|
||||
g_Renderer.m_RenderWater = !g_Renderer.m_RenderWater;
|
||||
g_Renderer.GetWaterManager()->m_RenderWater = !g_Renderer.GetWaterManager()->m_RenderWater;
|
||||
*rval = JSVAL_VOID;
|
||||
return( JS_TRUE );
|
||||
}
|
||||
@ -833,7 +834,7 @@ JSBool setWaterHeight( JSContext* cx, JSObject* UNUSED(globalObject), uint argc,
|
||||
*rval = JSVAL_VOID;
|
||||
return( JS_FALSE );
|
||||
}
|
||||
g_Renderer.m_WaterHeight = newHeight;
|
||||
g_Renderer.GetWaterManager()->m_WaterHeight = newHeight;
|
||||
g_TerrainModified = true;
|
||||
*rval = JSVAL_VOID;
|
||||
return( JS_TRUE );
|
||||
@ -843,7 +844,7 @@ JSBool setWaterHeight( JSContext* cx, JSObject* UNUSED(globalObject), uint argc,
|
||||
JSBool getWaterHeight( JSContext* cx, JSObject* UNUSED(globalObject), uint argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
REQUIRE_NO_PARAMS( getWaterHeight );
|
||||
*rval = ToJSVal(g_Renderer.m_WaterHeight);
|
||||
*rval = ToJSVal(g_Renderer.GetWaterManager()->m_WaterHeight);
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
@ -860,7 +861,7 @@ JSBool setWaterColor( JSContext* cx, JSObject* UNUSED(globalObject), uint argc,
|
||||
*rval = JSVAL_VOID;
|
||||
return( JS_FALSE );
|
||||
}
|
||||
g_Renderer.m_WaterColor = CColor(r, g, b, 1.0f);
|
||||
g_Renderer.GetWaterManager()->m_WaterColor = CColor(r, g, b, 1.0f);
|
||||
*rval = JSVAL_VOID;
|
||||
return( JS_TRUE );
|
||||
}
|
||||
@ -876,7 +877,7 @@ JSBool setWaterMaxAlpha( JSContext* cx, JSObject* UNUSED(globalObject), uint arg
|
||||
*rval = JSVAL_VOID;
|
||||
return( JS_FALSE );
|
||||
}
|
||||
g_Renderer.m_WaterMaxAlpha = val;
|
||||
g_Renderer.GetWaterManager()->m_WaterMaxAlpha = val;
|
||||
*rval = JSVAL_VOID;
|
||||
return( JS_TRUE );
|
||||
}
|
||||
@ -892,7 +893,7 @@ JSBool setWaterFullDepth( JSContext* cx, JSObject* UNUSED(globalObject), uint ar
|
||||
*rval = JSVAL_VOID;
|
||||
return( JS_FALSE );
|
||||
}
|
||||
g_Renderer.m_WaterFullDepth = val;
|
||||
g_Renderer.GetWaterManager()->m_WaterFullDepth = val;
|
||||
*rval = JSVAL_VOID;
|
||||
return( JS_TRUE );
|
||||
}
|
||||
@ -908,7 +909,7 @@ JSBool setWaterAlphaOffset( JSContext* cx, JSObject* UNUSED(globalObject), uint
|
||||
*rval = JSVAL_VOID;
|
||||
return( JS_FALSE );
|
||||
}
|
||||
g_Renderer.m_WaterAlphaOffset = val;
|
||||
g_Renderer.GetWaterManager()->m_WaterAlphaOffset = val;
|
||||
*rval = JSVAL_VOID;
|
||||
return( JS_TRUE );
|
||||
}
|
||||
@ -973,7 +974,7 @@ JSBool revealMap( JSContext* cx, JSObject* UNUSED(globalObject), uint argc, jsva
|
||||
// we simplify this a bit with a macro:
|
||||
#define JS_FUNC(script_name, cpp_function, min_params) { #script_name, cpp_function, min_params, 0, 0 },
|
||||
|
||||
JSFunctionSpec ScriptFunctionTable[] =
|
||||
JSFunctionSpec ScriptFunctionTable[] =
|
||||
{
|
||||
// Console
|
||||
JS_FUNC(writeConsole, JSI_Console::writeConsole, 1) // external
|
||||
@ -996,7 +997,7 @@ JSFunctionSpec ScriptFunctionTable[] =
|
||||
JS_FUNC(setWaterFullDepth, setWaterFullDepth, 0)
|
||||
JS_FUNC(setWaterAlphaOffset, setWaterAlphaOffset, 0)
|
||||
|
||||
// GUI
|
||||
// GUI
|
||||
#ifndef NO_GUI
|
||||
JS_FUNC(getGUIObjectByName, JSI_IGUIObject::getByName, 1) // external
|
||||
JS_FUNC(getGUIGlobal, getGUIGlobal, 0)
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "scripting/JSInterface_Vector3D.h"
|
||||
#include "MathUtil.h"
|
||||
#include "CConsole.h"
|
||||
#include "renderer/WaterManager.h"
|
||||
|
||||
extern CConsole* g_Console;
|
||||
extern int g_xres, g_yres;
|
||||
@ -878,7 +879,7 @@ float CEntity::getAnchorLevel( float x, float z )
|
||||
}
|
||||
else
|
||||
{
|
||||
return max( groundLevel, g_Renderer.m_WaterHeight );
|
||||
return max( groundLevel, g_Renderer.GetWaterManager()->m_WaterHeight );
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user