prefect
e2bbd9a654
This is a huge patch, including: * add a LitRenderModifier abstract base class for RenderModifiers with shadow+light * add LitRenderModifiers for all types of models * add STREAM_TEXGENTOUV1 to request generation of shadow map texcoords for models * create facilities to pass the texture matrix from the RenderModifier (fragment stage) to the ModelRenderer (vertex stage) * split ambient and diffuse terms of lighting until further down in the pipeline; this is necessary since shadowed regions receive only ambient light * small improvement in how RenderPathVertexShader scales to a greater number of vertex shaders This was SVN commit r3690.
405 lines
13 KiB
C++
405 lines
13 KiB
C++
/**
|
|
* =========================================================================
|
|
* File : PlayerRenderer.cpp
|
|
* Project : Pyrogenesis
|
|
* Description : Implementation of player colour RenderModifiers.
|
|
*
|
|
* @author John M. Mena <JohnMMena@hotmail.com>
|
|
* @author Nicolai Hähnle <nicolai@wildfiregames.com>
|
|
* =========================================================================
|
|
*/
|
|
|
|
#include "precompiled.h"
|
|
|
|
#include "renderer/Renderer.h"
|
|
#include "renderer/PlayerRenderer.h"
|
|
#include "renderer/ShadowMap.h"
|
|
|
|
#include "graphics/LightEnv.h"
|
|
#include "graphics/Model.h"
|
|
|
|
#include "ps/CLogger.h"
|
|
|
|
#define LOG_CATEGORY "graphics"
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// FastPlayerColorRender
|
|
|
|
FastPlayerColorRender::FastPlayerColorRender()
|
|
{
|
|
debug_assert(ogl_max_tex_units >= 3);
|
|
}
|
|
|
|
FastPlayerColorRender::~FastPlayerColorRender()
|
|
{
|
|
}
|
|
|
|
bool FastPlayerColorRender::IsAvailable()
|
|
{
|
|
return (ogl_max_tex_units >= 3);
|
|
}
|
|
|
|
u32 FastPlayerColorRender::BeginPass(uint pass)
|
|
{
|
|
debug_assert(pass == 0);
|
|
|
|
// Fast player color uses a single pass with three texture environments
|
|
// Note: This uses ARB_texture_env_crossbar (which is checked in GameSetup)
|
|
//
|
|
// We calculate: Result = Color*Texture*(PlayerColor*(1-Texture.a) + 1.0*Texture.a)
|
|
// Algebra gives us:
|
|
// Result = (1 - ((1 - PlayerColor) * (1 - Texture.a)))*Texture*Color
|
|
|
|
// TexEnv #0
|
|
pglActiveTextureARB(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_TEXTURE0);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_ONE_MINUS_SRC_ALPHA);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_ONE_MINUS_SRC_COLOR);
|
|
|
|
// Don't care about alpha; set it to something harmless
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE0);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
|
|
|
// TexEnv #1
|
|
pglActiveTextureARB(GL_TEXTURE0+1);
|
|
glEnable(GL_TEXTURE_2D);
|
|
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_PREVIOUS);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_ONE_MINUS_SRC_COLOR);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
|
|
|
|
// Don't care about alpha; set it to something harmless
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
|
|
|
// TexEnv #2
|
|
pglActiveTextureARB(GL_TEXTURE0+2);
|
|
glEnable(GL_TEXTURE_2D);
|
|
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_PREVIOUS);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE0);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
|
|
|
|
// Don't care about alpha; set it to something harmless
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
|
|
|
pglActiveTextureARB(GL_TEXTURE0);
|
|
|
|
return STREAM_POS|STREAM_COLOR|STREAM_UV0;
|
|
}
|
|
|
|
|
|
bool FastPlayerColorRender::EndPass(uint UNUSED(pass))
|
|
{
|
|
// Restore state
|
|
pglActiveTextureARB(GL_TEXTURE1);
|
|
glDisable(GL_TEXTURE_2D);
|
|
pglActiveTextureARB(GL_TEXTURE2);
|
|
glDisable(GL_TEXTURE_2D);
|
|
pglActiveTextureARB(GL_TEXTURE0);
|
|
|
|
return true;
|
|
}
|
|
|
|
void FastPlayerColorRender::PrepareTexture(uint UNUSED(pass), CTexture* texture)
|
|
{
|
|
g_Renderer.SetTexture(2, texture);
|
|
g_Renderer.SetTexture(1, texture);
|
|
g_Renderer.SetTexture(0, texture);
|
|
}
|
|
|
|
void FastPlayerColorRender::PrepareModel(uint UNUSED(pass), CModel* model)
|
|
{
|
|
// Get the player color
|
|
SMaterialColor colour = model->GetMaterial().GetPlayerColor();
|
|
float* color = &colour.r; // because it's stored RGBA
|
|
|
|
// Set the texture environment color the player color
|
|
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// SlowPlayerColorRender
|
|
|
|
SlowPlayerColorRender::SlowPlayerColorRender()
|
|
{
|
|
}
|
|
|
|
SlowPlayerColorRender::~SlowPlayerColorRender()
|
|
{
|
|
}
|
|
|
|
u32 SlowPlayerColorRender::BeginPass(uint pass)
|
|
{
|
|
// We calculate: Result = (Color*Texture)*Texture.a + (Color*Texture*PlayerColor)*(1-Texture.a)
|
|
// Modulation is done via texture environments, the final interpolation is done via blending
|
|
|
|
if (pass == 0)
|
|
{
|
|
// TexEnv #0
|
|
pglActiveTextureARB(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);
|
|
|
|
// Don't care about alpha; set it to something harmless
|
|
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);
|
|
|
|
// Render it!
|
|
return STREAM_POS|STREAM_COLOR|STREAM_UV0;
|
|
}
|
|
else
|
|
{
|
|
// TexEnv #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_CONSTANT);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
|
|
|
|
// Alpha = Opacity of non-player colored layer
|
|
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);
|
|
|
|
// TexEnv #1
|
|
pglActiveTextureARB(GL_TEXTURE1);
|
|
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_PREVIOUS);
|
|
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);
|
|
|
|
// Pass alpha unchanged
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
|
pglActiveTextureARB(GL_TEXTURE0);
|
|
|
|
// Setup blending
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
|
|
glEnable(GL_ALPHA_TEST);
|
|
glAlphaFunc(GL_LESS, 1.0);
|
|
glDepthMask(0);
|
|
|
|
// Render it!
|
|
return STREAM_POS|STREAM_COLOR|STREAM_UV0;
|
|
}
|
|
}
|
|
|
|
bool SlowPlayerColorRender::EndPass(uint pass)
|
|
{
|
|
if (pass == 0)
|
|
return false; // need two passes
|
|
|
|
// Restore state
|
|
pglActiveTextureARB(GL_TEXTURE1);
|
|
glDisable(GL_TEXTURE_2D);
|
|
pglActiveTextureARB(GL_TEXTURE0);
|
|
glDisable(GL_BLEND);
|
|
glDisable(GL_ALPHA_TEST);
|
|
glDepthMask(1);
|
|
|
|
return true;
|
|
}
|
|
|
|
void SlowPlayerColorRender::PrepareTexture(uint pass, CTexture* texture)
|
|
{
|
|
if (pass == 1)
|
|
g_Renderer.SetTexture(1, texture);
|
|
g_Renderer.SetTexture(0, texture);
|
|
}
|
|
|
|
|
|
void SlowPlayerColorRender::PrepareModel(uint pass, CModel* model)
|
|
{
|
|
if (pass == 1)
|
|
{
|
|
// Get the player color
|
|
SMaterialColor colour = model->GetMaterial().GetPlayerColor();
|
|
float* color = &colour.r; // because it's stored RGBA
|
|
|
|
// Set the texture environment color the player color
|
|
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// LitPlayerColorRender
|
|
|
|
LitPlayerColorRender::LitPlayerColorRender()
|
|
{
|
|
}
|
|
|
|
LitPlayerColorRender::~LitPlayerColorRender()
|
|
{
|
|
}
|
|
|
|
u32 LitPlayerColorRender::BeginPass(uint pass)
|
|
{
|
|
debug_assert(GetShadowMap() && GetShadowMap()->GetUseDepthTexture());
|
|
|
|
if (pass == 0)
|
|
{
|
|
// First pass: Lay down the material color
|
|
// We calculate:
|
|
// Material = Texture*(PlayerColor*(1.0-Texture.a) + 1.0*Texture.a))
|
|
// = (1 - ((1 - PlayerColor) * (1 - Texture.a)))*Texture
|
|
|
|
// Incoming Color holds the player color
|
|
// Texture 0 holds the model's texture
|
|
|
|
// TexEnv #0
|
|
pglActiveTextureARB(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_TEXTURE0);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_ONE_MINUS_SRC_ALPHA);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_ONE_MINUS_SRC_COLOR);
|
|
|
|
// Don't care about alpha; set it to something harmless
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE0);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
|
|
|
// TexEnv #1
|
|
pglActiveTextureARB(GL_TEXTURE0+1);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glBindTexture(GL_TEXTURE_2D, GetShadowMap()->GetTexture());
|
|
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_PREVIOUS);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_ONE_MINUS_SRC_COLOR);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE0);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
|
|
|
|
// Don't care about alpha; set it to something harmless
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
|
|
|
pglActiveTextureARB(GL_TEXTURE0);
|
|
|
|
return STREAM_POS|STREAM_UV0;
|
|
}
|
|
else
|
|
{
|
|
// Second pass: Multiply with lighting
|
|
//
|
|
// We calculate:
|
|
// Lighting = Ambient + Diffuse * Shadow
|
|
// and modulate with frame buffer contents
|
|
//
|
|
// Incoming color is diffuse
|
|
// Texture 1 is the shadow map
|
|
|
|
// TexEnv #0
|
|
pglActiveTextureARB(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, GetShadowMap()->GetTexture());
|
|
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_PRIMARY_COLOR);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE1);
|
|
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_PREVIOUS);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
|
|
|
// TexEnv #1
|
|
pglActiveTextureARB(GL_TEXTURE1);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glBindTexture(GL_TEXTURE_2D, GetShadowMap()->GetTexture());
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD);
|
|
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_SOURCE1_RGB_ARB, GL_CONSTANT);
|
|
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_PREVIOUS);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
|
|
|
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &GetLightEnv()->m_UnitsAmbientColor.X);
|
|
|
|
pglActiveTextureARB(GL_TEXTURE0);
|
|
|
|
// Blending, Z settings
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_DST_COLOR, GL_ZERO);
|
|
|
|
glDepthMask(0);
|
|
|
|
return STREAM_POS|STREAM_COLOR|STREAM_TEXGENTOUV1;
|
|
}
|
|
}
|
|
|
|
|
|
bool LitPlayerColorRender::EndPass(uint pass)
|
|
{
|
|
if (pass == 0)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
// Restore state
|
|
pglActiveTextureARB(GL_TEXTURE1);
|
|
glDisable(GL_TEXTURE_2D);
|
|
pglActiveTextureARB(GL_TEXTURE0);
|
|
|
|
glDisable(GL_BLEND);
|
|
glDepthMask(1);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
const CMatrix3D* LitPlayerColorRender::GetTexGenMatrix(uint UNUSED(pass))
|
|
{
|
|
return &GetShadowMap()->GetTextureMatrix();
|
|
}
|
|
|
|
void LitPlayerColorRender::PrepareTexture(uint pass, CTexture* texture)
|
|
{
|
|
if (pass == 0)
|
|
g_Renderer.SetTexture(0, texture);
|
|
}
|
|
|
|
void LitPlayerColorRender::PrepareModel(uint pass, CModel* model)
|
|
{
|
|
if (pass == 0)
|
|
{
|
|
// Get the player color
|
|
SMaterialColor colour = model->GetMaterial().GetPlayerColor();
|
|
|
|
// Send the player color
|
|
glColor3f(colour.r, colour.g, colour.b);
|
|
}
|
|
}
|
|
|
|
|