0ad/source/renderer/PlayerRenderer.cpp
prefect 0346ba1b18 Refactor model rendering to perform vertex setup in ModelVertexRenderer.
Sort all transparent models by distance to camera (however, do not sort
polygons by default).

This was SVN commit r3096.
2005-11-05 23:15:23 +00:00

245 lines
8.0 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 "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);
// Nice 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);
}
}