1
0
forked from 0ad/0ad
0ad/source/renderer/PlayerRenderer.cpp

215 lines
7.1 KiB
C++
Raw Normal View History

2005-01-24 07:14:13 +01:00
/***************************************************************************************
AUTHOR: John M. Mena
EMAIL: JohnMMena@hotmail.com
FILE: PlayerRenderer.cpp
2005-01-24 07:14:13 +01:00
CREATED: 1/23/05
COMPLETED: NULL
DESCRIPTION: Handles rendering all of the player objects.
2005-01-25 04:12:04 +01:00
The structure and overall design was inherited from Rich Cross' Transparency Renderer.
2005-01-24 07:14:13 +01:00
****************************************************************************************/
#include "precompiled.h"
#include <algorithm>
#include "Renderer.h"
#include "PlayerRenderer.h"
#include "Model.h"
#include "Game.h"
#include "Profile.h"
2005-01-24 07:14:13 +01:00
CPlayerRenderer g_PlayerRenderer;
///////////////////////////////////////////////////////////////////////////////////////////////////
2005-01-25 04:12:04 +01:00
// SetupColorRenderStates: setup the render states for the player color pass.
void CPlayerRenderer::SetupColorRenderStates()
2005-01-24 07:14:13 +01:00
{
2005-01-25 04:12:04 +01:00
// Set up second pass: first texture unit carries on doing texture*lighting,
// but passes alpha through inverted; the second texture unit modulates
// with the player colour.
2005-01-24 07:14:13 +01:00
glActiveTextureARB(GL_TEXTURE0);
2005-01-24 07:14:13 +01:00
2005-01-25 04:12:04 +01:00
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);
2005-01-24 07:14:13 +01:00
glActiveTextureARB(GL_TEXTURE1);
2005-01-24 07:14:13 +01:00
2005-01-25 04:12:04 +01:00
glEnable(GL_TEXTURE_2D);
2005-01-24 07:14:13 +01:00
2005-01-25 04:12:04 +01:00
// t1 = t0 * playercolor
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_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
2005-01-24 07:14:13 +01:00
2005-01-25 04:12:04 +01:00
// Continue passing through alpha from texture
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);
}
2005-01-24 07:14:13 +01:00
2005-01-25 04:12:04 +01:00
///////////////////////////////////////////////////////////////////////////////////////////////////
// Render: render all deferred passes; call Sort before using to ensure passes
// are drawn in correct order
void CPlayerRenderer::Render()
{
PROFILE( "render player models" );
2005-01-25 04:12:04 +01:00
if (m_Objects.size()==0) return;
2005-01-24 07:14:13 +01:00
2005-01-25 04:12:04 +01:00
// switch on wireframe if we need it
if (g_Renderer.m_ModelRenderMode==WIREFRAME) {
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
}
2005-01-24 07:14:13 +01:00
2005-01-24 09:28:03 +01:00
2005-01-25 04:12:04 +01:00
// set up texture environment for base pass - modulate texture and primary color
glActiveTextureARB(GL_TEXTURE0);
2005-01-25 04:12:04 +01:00
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 the proper LOD bias
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
2005-01-25 04:12:04 +01:00
// Render two passes: first, render the unit as normal. Second,
// render it again but modulated with the player-colour, using
// the alpha channel as a mask.
// EDIT: The second pass resides in SetupColorRenderStates() [John M. Mena]
//
// This really ought to be done in a single pass on hardware that
// supports register combiners / fragment programs / etc (since it
// would only need a single pass and no blending)
2005-01-25 04:12:04 +01:00
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
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);
// First pass should ignore the alpha channel and render the whole model
2005-01-25 04:12:04 +01:00
glDisable(GL_ALPHA_TEST);
2005-01-24 09:28:03 +01:00
2005-01-25 04:12:04 +01:00
RenderObjectsStreams(STREAM_POS|STREAM_COLOR|STREAM_UV0);
2005-01-24 09:28:03 +01:00
// Render the second pass:
2005-01-24 09:28:03 +01:00
// Second pass uses the alpha channel to blend the coloured model
// with the first pass's solid model
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
2005-01-25 04:12:04 +01:00
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0);
2005-01-24 09:28:03 +01:00
2005-01-25 04:12:04 +01:00
RenderObjectsStreams(STREAM_POS|STREAM_COLOR|STREAM_UV0, true);
2005-01-24 07:14:13 +01:00
// Restore states
glActiveTextureARB(GL_TEXTURE1);
2005-01-24 07:14:13 +01:00
glDisable(GL_TEXTURE_2D);
glDisable(GL_ALPHA_TEST);
glDisable(GL_BLEND);
2005-01-24 07:14:13 +01:00
glActiveTextureARB(GL_TEXTURE0);
2005-01-24 07:14:13 +01:00
// switch off client states
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
2005-01-25 04:27:38 +01:00
if (g_Renderer.m_ModelRenderMode==WIREFRAME) {
// switch wireframe off again
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
} else if (g_Renderer.m_ModelRenderMode==EDGED_FACES) {
// edged faces: need to make a second pass over the data:
// first switch on wireframe
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
// setup some renderstate ..
glDepthMask(0);
g_Renderer.SetTexture(0,0);
glColor4f(1,1,1,0.75f);
glLineWidth(1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
// .. and some client states
glEnableClientState(GL_VERTEX_ARRAY);
// render each model
RenderObjectsStreams(STREAM_POS);
// .. and switch off the client states
glDisableClientState(GL_VERTEX_ARRAY);
// .. and restore the renderstates
glDisable(GL_BLEND);
glDepthMask(1);
// restore fill mode, and we're done
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
}
2005-01-24 07:14:13 +01:00
}
void CPlayerRenderer::Clear()
{
// all transparent objects rendered; release them
m_Objects.clear();
}
void CPlayerRenderer::Add(CModel* model)
{
m_Objects.push_back(model);
2005-01-24 07:14:13 +01:00
}
//TODO: Correctly implement shadows for the players
void CPlayerRenderer::RenderShadows()
{
if (m_Objects.size()==0) return;
RenderObjectsStreams(STREAM_POS|STREAM_UV0, false, MODELFLAG_CASTSHADOWS);
}
2005-01-24 07:14:13 +01:00
///////////////////////////////////////////////////////////////////////////////////////////////
// RenderObjectsStreams: render given streams on all objects
2005-01-25 04:12:04 +01:00
void CPlayerRenderer::RenderObjectsStreams(u32 streamflags, bool iscolorpass, u32 mflags)
{
for (uint i=0;i<m_Objects.size();++i) {
if (!mflags || (m_Objects[i]->GetFlags() & mflags)) {
CModelRData* modeldata=(CModelRData*) m_Objects[i]->GetRenderData();
2005-01-25 04:12:04 +01:00
// Setup the render states to apply the second texture ( i.e. player color )
if (iscolorpass)
{
// I, John Mena, don't think that both passes need a color applied.
// If I am wrong, then just move everything except for the
// SetupColorRenderStates() below this if statement.
// Get the player color
SMaterialColor colour = m_Objects[i]->GetMaterial().GetPlayerColor();
float* color = &colour.r; // because it's stored RGBA
2005-01-25 04:12:04 +01:00
// Just like it says, Sets up the player color render states
SetupColorRenderStates();
// Set the texture environment color the player color
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
}
// Render the model
modeldata->RenderStreams(streamflags, iscolorpass);
}
}
}