2010-09-10 23:02:10 +02:00
|
|
|
/* Copyright (C) 2010 Wildfire Games.
|
2009-04-18 19:00:33 +02:00
|
|
|
* This file is part of 0 A.D.
|
|
|
|
*
|
|
|
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* 0 A.D. is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2009-04-18 19:51:05 +02:00
|
|
|
/*
|
|
|
|
* higher level interface on top of OpenGL to render basic objects:
|
|
|
|
* terrain, models, sprites, particles etc.
|
2007-05-07 18:33:24 +02:00
|
|
|
*/
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2004-06-03 20:38:14 +02:00
|
|
|
#include "precompiled.h"
|
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
#include <map>
|
|
|
|
#include <set>
|
|
|
|
#include <algorithm>
|
2007-05-09 23:01:11 +02:00
|
|
|
#include "lib/bits.h" // is_pow2
|
2007-12-22 19:15:52 +01:00
|
|
|
#include "lib/res/graphics/ogl_tex.h"
|
2004-05-30 02:46:58 +02:00
|
|
|
#include "Renderer.h"
|
2006-06-02 04:10:27 +02:00
|
|
|
#include "maths/Matrix3D.h"
|
|
|
|
#include "maths/MathUtil.h"
|
2006-06-02 05:56:24 +02:00
|
|
|
#include "ps/Pyrogenesis.h" // MICROLOG
|
2006-06-02 04:10:27 +02:00
|
|
|
#include "ps/CLogger.h"
|
2004-09-26 06:05:35 +02:00
|
|
|
#include "ps/Game.h"
|
2006-06-02 04:10:27 +02:00
|
|
|
#include "ps/Profile.h"
|
2007-12-22 19:15:52 +01:00
|
|
|
#include "ps/Filesystem.h"
|
2006-06-02 04:10:27 +02:00
|
|
|
#include "ps/World.h"
|
2007-12-20 21:21:45 +01:00
|
|
|
#include "ps/Loader.h"
|
|
|
|
#include "ps/ProfileViewer.h"
|
|
|
|
#include "graphics/Camera.h"
|
|
|
|
#include "graphics/Texture.h"
|
2010-09-10 23:02:10 +02:00
|
|
|
#include "graphics/TextureManager.h"
|
2007-12-20 21:21:45 +01:00
|
|
|
#include "graphics/LightEnv.h"
|
|
|
|
#include "graphics/Terrain.h"
|
|
|
|
#include "graphics/Model.h"
|
|
|
|
#include "graphics/ModelDef.h"
|
2007-02-10 20:37:33 +01:00
|
|
|
#include "graphics/GameView.h"
|
2006-02-11 10:40:04 +01:00
|
|
|
#include "graphics/ParticleEngine.h"
|
|
|
|
#include "graphics/DefaultEmitter.h"
|
2005-10-25 03:43:07 +02:00
|
|
|
#include "renderer/FixedFunctionModelRenderer.h"
|
|
|
|
#include "renderer/HWLightingModelRenderer.h"
|
2005-10-30 02:22:22 +02:00
|
|
|
#include "renderer/InstancingModelRenderer.h"
|
2005-10-25 03:43:07 +02:00
|
|
|
#include "renderer/ModelRenderer.h"
|
2010-01-09 20:20:14 +01:00
|
|
|
#include "renderer/OverlayRenderer.h"
|
2005-10-25 03:43:07 +02:00
|
|
|
#include "renderer/PlayerRenderer.h"
|
|
|
|
#include "renderer/RenderModifiers.h"
|
2005-10-05 18:42:09 +02:00
|
|
|
#include "renderer/RenderPathVertexShader.h"
|
2006-01-07 02:04:26 +01:00
|
|
|
#include "renderer/ShadowMap.h"
|
2010-01-09 20:20:14 +01:00
|
|
|
#include "renderer/SkyManager.h"
|
2006-04-17 22:02:51 +02:00
|
|
|
#include "renderer/TerrainOverlay.h"
|
2006-01-07 02:04:26 +01:00
|
|
|
#include "renderer/TerrainRenderer.h"
|
2005-10-25 03:43:07 +02:00
|
|
|
#include "renderer/TransparencyRenderer.h"
|
2006-01-07 02:04:26 +01:00
|
|
|
#include "renderer/WaterManager.h"
|
2005-10-05 18:42:09 +02:00
|
|
|
|
2009-11-03 22:46:35 +01:00
|
|
|
#define LOG_CATEGORY L"graphics"
|
2004-08-15 22:57:31 +02:00
|
|
|
|
2005-11-19 17:15:34 +01:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// CRendererStatsTable - Profile display of rendering stats
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Class CRendererStatsTable: Implementation of AbstractProfileTable to
|
|
|
|
* display the renderer stats in-game.
|
|
|
|
*
|
|
|
|
* Accesses CRenderer::m_Stats by keeping the reference passed to the
|
|
|
|
* constructor.
|
|
|
|
*/
|
2009-01-03 19:40:28 +01:00
|
|
|
class CRendererStatsTable : public AbstractProfileTable
|
2005-11-19 17:15:34 +01:00
|
|
|
{
|
2009-01-03 19:40:28 +01:00
|
|
|
NONCOPYABLE(CRendererStatsTable);
|
2005-11-19 17:15:34 +01:00
|
|
|
public:
|
|
|
|
CRendererStatsTable(const CRenderer::Stats& st);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-19 17:15:34 +01:00
|
|
|
// Implementation of AbstractProfileTable interface
|
|
|
|
CStr GetName();
|
|
|
|
CStr GetTitle();
|
2006-09-01 08:59:29 +02:00
|
|
|
size_t GetNumberRows();
|
2005-11-19 17:15:34 +01:00
|
|
|
const std::vector<ProfileColumn>& GetColumns();
|
2006-09-01 08:59:29 +02:00
|
|
|
CStr GetCellText(size_t row, size_t col);
|
|
|
|
AbstractProfileTable* GetChild(size_t row);
|
2005-11-19 17:15:34 +01:00
|
|
|
|
|
|
|
private:
|
|
|
|
/// Reference to the renderer singleton's stats
|
|
|
|
const CRenderer::Stats& Stats;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-19 17:15:34 +01:00
|
|
|
/// Column descriptions
|
|
|
|
std::vector<ProfileColumn> columnDescriptions;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-19 17:15:34 +01:00
|
|
|
enum {
|
|
|
|
Row_Counter = 0,
|
|
|
|
Row_DrawCalls,
|
|
|
|
Row_TerrainTris,
|
|
|
|
Row_ModelTris,
|
|
|
|
Row_BlendSplats,
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-19 17:15:34 +01:00
|
|
|
// Must be last to count number of rows
|
|
|
|
NumberRows
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
// Construction
|
|
|
|
CRendererStatsTable::CRendererStatsTable(const CRenderer::Stats& st)
|
|
|
|
: Stats(st)
|
|
|
|
{
|
|
|
|
columnDescriptions.push_back(ProfileColumn("Name", 230));
|
|
|
|
columnDescriptions.push_back(ProfileColumn("Value", 100));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Implementation of AbstractProfileTable interface
|
|
|
|
CStr CRendererStatsTable::GetName()
|
|
|
|
{
|
|
|
|
return "renderer";
|
|
|
|
}
|
|
|
|
|
|
|
|
CStr CRendererStatsTable::GetTitle()
|
|
|
|
{
|
|
|
|
return "Renderer statistics";
|
|
|
|
}
|
|
|
|
|
2006-09-01 08:59:29 +02:00
|
|
|
size_t CRendererStatsTable::GetNumberRows()
|
2005-11-19 17:15:34 +01:00
|
|
|
{
|
|
|
|
return NumberRows;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::vector<ProfileColumn>& CRendererStatsTable::GetColumns()
|
|
|
|
{
|
|
|
|
return columnDescriptions;
|
|
|
|
}
|
|
|
|
|
2006-09-01 08:59:29 +02:00
|
|
|
CStr CRendererStatsTable::GetCellText(size_t row, size_t col)
|
2005-11-19 17:15:34 +01:00
|
|
|
{
|
|
|
|
char buf[256];
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-19 17:15:34 +01:00
|
|
|
switch(row)
|
|
|
|
{
|
|
|
|
case Row_Counter:
|
|
|
|
if (col == 0)
|
|
|
|
return "counter";
|
2009-11-06 11:59:10 +01:00
|
|
|
sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)Stats.m_Counter);
|
2005-11-19 17:15:34 +01:00
|
|
|
return buf;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-19 17:15:34 +01:00
|
|
|
case Row_DrawCalls:
|
|
|
|
if (col == 0)
|
|
|
|
return "# draw calls";
|
2009-11-06 11:59:10 +01:00
|
|
|
sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)Stats.m_DrawCalls);
|
2005-11-19 17:15:34 +01:00
|
|
|
return buf;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-19 17:15:34 +01:00
|
|
|
case Row_TerrainTris:
|
|
|
|
if (col == 0)
|
|
|
|
return "# terrain tris";
|
2009-11-06 11:59:10 +01:00
|
|
|
sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)Stats.m_TerrainTris);
|
2005-11-19 17:15:34 +01:00
|
|
|
return buf;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-19 17:15:34 +01:00
|
|
|
case Row_ModelTris:
|
|
|
|
if (col == 0)
|
|
|
|
return "# model tris";
|
2009-11-06 11:59:10 +01:00
|
|
|
sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)Stats.m_ModelTris);
|
2005-11-19 17:15:34 +01:00
|
|
|
return buf;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-19 17:15:34 +01:00
|
|
|
case Row_BlendSplats:
|
|
|
|
if (col == 0)
|
|
|
|
return "# blend splats";
|
2009-11-06 11:59:10 +01:00
|
|
|
sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)Stats.m_BlendSplats);
|
2005-11-19 17:15:34 +01:00
|
|
|
return buf;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-19 17:15:34 +01:00
|
|
|
default:
|
|
|
|
return "???";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-09-01 08:59:29 +02:00
|
|
|
AbstractProfileTable* CRendererStatsTable::GetChild(size_t UNUSED(row))
|
2005-11-19 17:15:34 +01:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// CRenderer implementation
|
|
|
|
|
2006-03-26 01:54:20 +01:00
|
|
|
enum {
|
|
|
|
AmbientDiffuse = 0,
|
|
|
|
OnlyDiffuse,
|
|
|
|
|
|
|
|
NumVertexTypes
|
|
|
|
};
|
|
|
|
|
2005-11-19 17:15:34 +01:00
|
|
|
/**
|
|
|
|
* Struct CRendererInternals: Truly hide data that is supposed to be hidden
|
|
|
|
* in this structure so it won't even appear in header files.
|
|
|
|
*/
|
2009-01-03 19:40:28 +01:00
|
|
|
struct CRendererInternals
|
2005-11-19 17:15:34 +01:00
|
|
|
{
|
2009-01-03 19:40:28 +01:00
|
|
|
NONCOPYABLE(CRendererInternals);
|
|
|
|
public:
|
2006-03-28 21:45:44 +02:00
|
|
|
/// true if CRenderer::Open has been called
|
|
|
|
bool IsOpen;
|
|
|
|
|
2005-11-19 17:15:34 +01:00
|
|
|
/// Table to display renderer stats in-game via profile system
|
|
|
|
CRendererStatsTable profileTable;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
|
|
|
/// Water manager
|
|
|
|
WaterManager waterManager;
|
|
|
|
|
2006-05-16 06:41:37 +02:00
|
|
|
/// Sky manager
|
|
|
|
SkyManager skyManager;
|
|
|
|
|
2010-09-10 23:02:10 +02:00
|
|
|
/// Texture manager
|
|
|
|
CTextureManager textureManager;
|
|
|
|
|
2006-01-07 02:04:26 +01:00
|
|
|
/// Terrain renderer
|
|
|
|
TerrainRenderer* terrainRenderer;
|
|
|
|
|
2010-01-09 20:20:14 +01:00
|
|
|
/// Overlay renderer
|
|
|
|
OverlayRenderer overlayRenderer;
|
|
|
|
|
2006-01-07 02:04:26 +01:00
|
|
|
/// Shadow map
|
|
|
|
ShadowMap* shadow;
|
2006-01-22 20:12:30 +01:00
|
|
|
|
2006-03-26 01:54:20 +01:00
|
|
|
/// Various model renderers
|
|
|
|
struct Models {
|
|
|
|
// The following model renderers are aliases for the appropriate real_*
|
|
|
|
// model renderers (depending on hardware availability and current settings)
|
|
|
|
// and must be used for actual model submission and rendering
|
|
|
|
ModelRenderer* Normal;
|
|
|
|
ModelRenderer* NormalInstancing;
|
|
|
|
ModelRenderer* Player;
|
|
|
|
ModelRenderer* PlayerInstancing;
|
|
|
|
ModelRenderer* Transp;
|
|
|
|
|
|
|
|
// "Palette" of available ModelRenderers. Do not use these directly for
|
|
|
|
// rendering and submission; use the aliases above instead.
|
|
|
|
ModelRenderer* pal_NormalFF[NumVertexTypes];
|
|
|
|
ModelRenderer* pal_PlayerFF[NumVertexTypes];
|
|
|
|
ModelRenderer* pal_NormalHWLit[NumVertexTypes];
|
|
|
|
ModelRenderer* pal_PlayerHWLit[NumVertexTypes];
|
|
|
|
ModelRenderer* pal_NormalInstancing[NumVertexTypes];
|
|
|
|
ModelRenderer* pal_PlayerInstancing[NumVertexTypes];
|
|
|
|
ModelRenderer* pal_TranspFF[NumVertexTypes];
|
|
|
|
ModelRenderer* pal_TranspHWLit[NumVertexTypes];
|
|
|
|
ModelRenderer* pal_TranspSortAll;
|
|
|
|
|
|
|
|
ModelVertexRendererPtr VertexFF[NumVertexTypes];
|
|
|
|
ModelVertexRendererPtr VertexHWLit[NumVertexTypes];
|
|
|
|
ModelVertexRendererPtr VertexInstancing[NumVertexTypes];
|
|
|
|
ModelVertexRendererPtr VertexPolygonSort;
|
|
|
|
|
|
|
|
// generic RenderModifiers that are supposed to be used directly
|
|
|
|
RenderModifierPtr ModWireframe;
|
|
|
|
RenderModifierPtr ModSolidColor;
|
|
|
|
RenderModifierPtr ModTransparentShadow;
|
|
|
|
RenderModifierPtr ModTransparentDepthShadow;
|
|
|
|
|
|
|
|
// RenderModifiers that are selected from the palette below
|
|
|
|
RenderModifierPtr ModNormal;
|
|
|
|
RenderModifierPtr ModPlayer;
|
|
|
|
RenderModifierPtr ModTransparent;
|
|
|
|
|
|
|
|
// Palette of available RenderModifiers
|
|
|
|
RenderModifierPtr ModPlain;
|
|
|
|
LitRenderModifierPtr ModPlainLit;
|
|
|
|
RenderModifierPtr ModPlayerUnlit;
|
|
|
|
LitRenderModifierPtr ModPlayerLit;
|
|
|
|
RenderModifierPtr ModTransparentUnlit;
|
|
|
|
LitRenderModifierPtr ModTransparentLit;
|
|
|
|
} Model;
|
|
|
|
|
|
|
|
|
2005-11-19 17:15:34 +01:00
|
|
|
CRendererInternals()
|
2010-09-10 23:02:10 +02:00
|
|
|
: IsOpen(false), profileTable(g_Renderer.m_Stats), textureManager(g_VFS)
|
2005-11-19 17:15:34 +01:00
|
|
|
{
|
2006-01-07 02:04:26 +01:00
|
|
|
terrainRenderer = new TerrainRenderer();
|
|
|
|
shadow = new ShadowMap();
|
2006-03-28 21:45:44 +02:00
|
|
|
|
|
|
|
for(int vertexType = 0; vertexType < NumVertexTypes; ++vertexType)
|
|
|
|
{
|
|
|
|
Model.pal_NormalFF[vertexType] = 0;
|
|
|
|
Model.pal_PlayerFF[vertexType] = 0;
|
|
|
|
Model.pal_TranspFF[vertexType] = 0;
|
|
|
|
Model.pal_NormalHWLit[vertexType] = 0;
|
|
|
|
Model.pal_PlayerHWLit[vertexType] = 0;
|
|
|
|
Model.pal_TranspHWLit[vertexType] = 0;
|
|
|
|
Model.pal_NormalInstancing[vertexType] = 0;
|
|
|
|
Model.pal_PlayerInstancing[vertexType] = 0;
|
|
|
|
}
|
|
|
|
Model.pal_TranspSortAll = 0;
|
|
|
|
|
|
|
|
Model.Normal = 0;
|
|
|
|
Model.NormalInstancing = 0;
|
|
|
|
Model.Player = 0;
|
|
|
|
Model.PlayerInstancing = 0;
|
|
|
|
Model.Transp = 0;
|
2006-01-07 02:04:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
~CRendererInternals()
|
|
|
|
{
|
|
|
|
delete shadow;
|
|
|
|
delete terrainRenderer;
|
2005-11-19 17:15:34 +01:00
|
|
|
}
|
2006-03-31 04:19:11 +02:00
|
|
|
|
|
|
|
bool CanUseRenderPathVertexShader()
|
|
|
|
{
|
|
|
|
for(int vertexType = 0; vertexType < NumVertexTypes; ++vertexType)
|
|
|
|
{
|
|
|
|
if (!Model.pal_NormalHWLit[vertexType] ||
|
|
|
|
!Model.pal_PlayerHWLit[vertexType])
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2006-09-14 22:06:21 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Load the OpenGL projection and modelview matrices and the viewport according
|
|
|
|
* to the given camera.
|
|
|
|
*/
|
|
|
|
void SetOpenGLCamera(const CCamera& camera)
|
|
|
|
{
|
|
|
|
CMatrix3D view;
|
|
|
|
camera.m_Orientation.GetInverse(view);
|
|
|
|
const CMatrix3D& proj = camera.GetProjection();
|
|
|
|
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadMatrixf(&proj._11);
|
|
|
|
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadMatrixf(&view._11);
|
|
|
|
|
|
|
|
const SViewPort &vp = camera.GetViewPort();
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
glViewport((GLint)vp.m_X,(GLint)vp.m_Y,(GLsizei)vp.m_Width,(GLsizei)vp.m_Height);
|
2006-09-14 22:06:21 +02:00
|
|
|
}
|
2005-11-19 17:15:34 +01:00
|
|
|
};
|
|
|
|
|
2004-06-11 00:24:03 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
2010-06-20 00:07:27 +02:00
|
|
|
// CRenderer constructor
|
2004-06-07 21:53:58 +02:00
|
|
|
CRenderer::CRenderer()
|
2004-05-30 02:46:58 +02:00
|
|
|
{
|
2005-11-19 17:15:34 +01:00
|
|
|
m = new CRendererInternals;
|
2006-01-07 02:04:26 +01:00
|
|
|
m_WaterManager = &m->waterManager;
|
2006-05-16 06:41:37 +02:00
|
|
|
m_SkyManager = &m->skyManager;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-19 17:15:34 +01:00
|
|
|
g_ProfileViewer.AddRootTable(&m->profileTable);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
m_Width=0;
|
|
|
|
m_Height=0;
|
|
|
|
m_FrameCounter=0;
|
|
|
|
m_TerrainRenderMode=SOLID;
|
|
|
|
m_ModelRenderMode=SOLID;
|
|
|
|
m_ClearColor[0]=m_ClearColor[1]=m_ClearColor[2]=m_ClearColor[3]=0;
|
2004-06-11 00:24:03 +02:00
|
|
|
|
2005-10-25 04:22:22 +02:00
|
|
|
m_SortAllTransparent = false;
|
2006-01-22 20:12:30 +01:00
|
|
|
m_DisplayFrustum = false;
|
2006-02-16 00:50:24 +01:00
|
|
|
m_DisableCopyShadow = false;
|
2006-03-26 19:36:33 +02:00
|
|
|
m_FastPlayerColor = true;
|
2006-09-23 18:04:54 +02:00
|
|
|
m_SkipSubmit = false;
|
2006-12-05 03:08:52 +01:00
|
|
|
m_RenderTerritories = true;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-05 18:42:09 +02:00
|
|
|
m_VertexShader = 0;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2010-06-20 00:07:27 +02:00
|
|
|
m_Options.m_NoVBO = false;
|
2006-03-26 19:36:33 +02:00
|
|
|
m_Options.m_NoFramebufferObject = false;
|
2005-10-05 18:42:09 +02:00
|
|
|
m_Options.m_RenderPath = RP_DEFAULT;
|
2006-09-08 00:16:15 +02:00
|
|
|
m_Options.m_FancyWater = false;
|
2010-06-20 00:07:27 +02:00
|
|
|
m_Options.m_Shadows = false;
|
2004-06-11 00:24:03 +02:00
|
|
|
|
2006-07-17 02:59:32 +02:00
|
|
|
m_ShadowZBias = 0.02f;
|
2007-02-09 18:04:55 +01:00
|
|
|
m_ShadowMapSize = 0;
|
2006-03-26 19:36:33 +02:00
|
|
|
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
for (size_t i=0;i<MaxTextureUnits;i++) {
|
2004-06-11 00:24:03 +02:00
|
|
|
m_ActiveTextures[i]=0;
|
|
|
|
}
|
2008-10-18 19:58:04 +02:00
|
|
|
m_hCompositeAlphaMap = 0;
|
2005-09-18 05:47:15 +02:00
|
|
|
|
2010-06-20 00:07:27 +02:00
|
|
|
AddLocalProperty(L"shadows", &m_Options.m_Shadows, false);
|
2006-09-23 14:48:06 +02:00
|
|
|
AddLocalProperty(L"fancyWater", &m_Options.m_FancyWater, false);
|
|
|
|
AddLocalProperty(L"horizonHeight", &m->skyManager.m_HorizonHeight, false);
|
|
|
|
AddLocalProperty(L"waterMurkiness", &m->waterManager.m_Murkiness, false);
|
|
|
|
AddLocalProperty(L"waterReflTintStrength", &m->waterManager.m_ReflectionTintStrength, false);
|
|
|
|
AddLocalProperty(L"waterRepeatPeriod", &m->waterManager.m_RepeatPeriod, false);
|
|
|
|
AddLocalProperty(L"waterShininess", &m->waterManager.m_Shininess, false);
|
|
|
|
AddLocalProperty(L"waterSpecularStrength", &m->waterManager.m_SpecularStrength, false);
|
|
|
|
AddLocalProperty(L"waterWaviness", &m->waterManager.m_Waviness, false);
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
2004-06-11 00:24:03 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// CRenderer destructor
|
2004-06-07 21:53:58 +02:00
|
|
|
CRenderer::~CRenderer()
|
2004-05-30 02:46:58 +02:00
|
|
|
{
|
2005-10-25 03:43:07 +02:00
|
|
|
// model rendering
|
2006-03-26 01:54:20 +01:00
|
|
|
for(int vertexType = 0; vertexType < NumVertexTypes; ++vertexType)
|
|
|
|
{
|
|
|
|
delete m->Model.pal_NormalFF[vertexType];
|
|
|
|
delete m->Model.pal_PlayerFF[vertexType];
|
|
|
|
delete m->Model.pal_TranspFF[vertexType];
|
|
|
|
delete m->Model.pal_NormalHWLit[vertexType];
|
|
|
|
delete m->Model.pal_PlayerHWLit[vertexType];
|
|
|
|
delete m->Model.pal_TranspHWLit[vertexType];
|
|
|
|
delete m->Model.pal_NormalInstancing[vertexType];
|
|
|
|
delete m->Model.pal_PlayerInstancing[vertexType];
|
|
|
|
}
|
|
|
|
delete m->Model.pal_TranspSortAll;
|
2005-10-25 03:43:07 +02:00
|
|
|
|
|
|
|
// general
|
2005-10-06 18:07:36 +02:00
|
|
|
delete m_VertexShader;
|
|
|
|
m_VertexShader = 0;
|
2005-10-12 06:16:41 +02:00
|
|
|
|
2007-05-02 14:07:08 +02:00
|
|
|
CParticleEngine::GetInstance()->Cleanup();
|
2006-03-15 19:32:24 +01:00
|
|
|
|
2005-10-31 19:57:03 +01:00
|
|
|
// we no longer UnloadAlphaMaps / UnloadWaterTextures here -
|
|
|
|
// that is the responsibility of the module that asked for
|
|
|
|
// them to be loaded (i.e. CGameView).
|
2005-11-19 17:15:34 +01:00
|
|
|
delete m;
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-07 21:53:58 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
2004-05-30 02:46:58 +02:00
|
|
|
// EnumCaps: build card cap bits
|
|
|
|
void CRenderer::EnumCaps()
|
|
|
|
{
|
|
|
|
// assume support for nothing
|
|
|
|
m_Caps.m_VBO=false;
|
|
|
|
m_Caps.m_TextureBorderClamp=false;
|
|
|
|
m_Caps.m_GenerateMipmaps=false;
|
2005-10-01 00:23:48 +02:00
|
|
|
m_Caps.m_VertexShader=false;
|
2010-03-21 15:18:15 +01:00
|
|
|
m_Caps.m_FragmentShader=false;
|
2006-02-11 19:04:32 +01:00
|
|
|
m_Caps.m_DepthTextureShadows = false;
|
2006-03-26 19:36:33 +02:00
|
|
|
m_Caps.m_FramebufferObject = false;
|
2004-05-30 02:46:58 +02:00
|
|
|
|
|
|
|
// now start querying extensions
|
|
|
|
if (!m_Options.m_NoVBO) {
|
2007-05-02 14:07:08 +02:00
|
|
|
if (ogl_HaveExtension("GL_ARB_vertex_buffer_object")) {
|
2004-05-30 02:46:58 +02:00
|
|
|
m_Caps.m_VBO=true;
|
|
|
|
}
|
|
|
|
}
|
2007-05-02 14:07:08 +02:00
|
|
|
if (ogl_HaveExtension("GL_ARB_texture_border_clamp")) {
|
2004-05-30 02:46:58 +02:00
|
|
|
m_Caps.m_TextureBorderClamp=true;
|
|
|
|
}
|
2007-05-02 14:07:08 +02:00
|
|
|
if (ogl_HaveExtension("GL_SGIS_generate_mipmap")) {
|
2004-05-30 02:46:58 +02:00
|
|
|
m_Caps.m_GenerateMipmaps=true;
|
|
|
|
}
|
2009-08-04 18:08:41 +02:00
|
|
|
if (0 == ogl_HaveExtensions(0, "GL_ARB_shader_objects", "GL_ARB_shading_language_100", NULL))
|
2005-10-01 00:23:48 +02:00
|
|
|
{
|
2007-05-02 14:07:08 +02:00
|
|
|
if (ogl_HaveExtension("GL_ARB_vertex_shader"))
|
2005-10-01 00:23:48 +02:00
|
|
|
m_Caps.m_VertexShader=true;
|
2010-03-21 15:18:15 +01:00
|
|
|
if (ogl_HaveExtension("GL_ARB_fragment_shader"))
|
|
|
|
m_Caps.m_FragmentShader=true;
|
2005-10-01 00:23:48 +02:00
|
|
|
}
|
2006-02-15 01:45:16 +01:00
|
|
|
|
2009-08-04 18:08:41 +02:00
|
|
|
if (0 == ogl_HaveExtensions(0, "GL_ARB_shadow", "GL_ARB_depth_texture", NULL)) {
|
2006-02-15 01:45:16 +01:00
|
|
|
// According to Delphi3d.net, all relevant graphics chips that support depth textures
|
|
|
|
// (i.e. Geforce3+, Radeon9500+, even i915) also have >= 4 TMUs, so this restriction
|
|
|
|
// isn't actually a restriction, and it helps with integrating depth texture
|
|
|
|
// shadows into rendering paths.
|
|
|
|
if (ogl_max_tex_units >= 4)
|
|
|
|
m_Caps.m_DepthTextureShadows = true;
|
2006-02-11 19:04:32 +01:00
|
|
|
}
|
2006-03-26 19:36:33 +02:00
|
|
|
if (!m_Options.m_NoFramebufferObject)
|
|
|
|
{
|
2007-05-02 14:07:08 +02:00
|
|
|
if (ogl_HaveExtension("GL_EXT_framebuffer_object"))
|
2006-03-26 19:36:33 +02:00
|
|
|
m_Caps.m_FramebufferObject = true;
|
|
|
|
}
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
2005-10-01 00:23:48 +02:00
|
|
|
|
2010-06-03 21:07:59 +02:00
|
|
|
bool CRenderer::Open(int width, int height)
|
2004-05-30 02:46:58 +02:00
|
|
|
{
|
2006-03-28 21:45:44 +02:00
|
|
|
m->IsOpen = true;
|
|
|
|
|
2006-03-26 19:36:33 +02:00
|
|
|
// Must query card capabilities before creating renderers that depend
|
|
|
|
// on card capabilities.
|
|
|
|
EnumCaps();
|
|
|
|
m->shadow->SetUseDepthTexture(true);
|
|
|
|
|
|
|
|
m_VertexShader = new RenderPathVertexShader;
|
|
|
|
if (!m_VertexShader->Init())
|
|
|
|
{
|
|
|
|
delete m_VertexShader;
|
|
|
|
m_VertexShader = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// model rendering
|
|
|
|
m->Model.VertexFF[AmbientDiffuse] = ModelVertexRendererPtr(new FixedFunctionModelRenderer(false));
|
|
|
|
m->Model.VertexFF[OnlyDiffuse] = ModelVertexRendererPtr(new FixedFunctionModelRenderer(true));
|
|
|
|
if (HWLightingModelRenderer::IsAvailable())
|
|
|
|
{
|
|
|
|
m->Model.VertexHWLit[AmbientDiffuse] = ModelVertexRendererPtr(new HWLightingModelRenderer(false));
|
|
|
|
m->Model.VertexHWLit[OnlyDiffuse] = ModelVertexRendererPtr(new HWLightingModelRenderer(true));
|
|
|
|
}
|
|
|
|
if (InstancingModelRenderer::IsAvailable())
|
|
|
|
{
|
|
|
|
m->Model.VertexInstancing[AmbientDiffuse] = ModelVertexRendererPtr(new InstancingModelRenderer(false));
|
|
|
|
m->Model.VertexInstancing[OnlyDiffuse] = ModelVertexRendererPtr(new InstancingModelRenderer(true));
|
|
|
|
}
|
|
|
|
m->Model.VertexPolygonSort = ModelVertexRendererPtr(new PolygonSortModelRenderer);
|
|
|
|
|
|
|
|
for(int vertexType = 0; vertexType < NumVertexTypes; ++vertexType)
|
|
|
|
{
|
|
|
|
m->Model.pal_NormalFF[vertexType] = new BatchModelRenderer(m->Model.VertexFF[vertexType]);
|
|
|
|
m->Model.pal_PlayerFF[vertexType] = new BatchModelRenderer(m->Model.VertexFF[vertexType]);
|
|
|
|
m->Model.pal_TranspFF[vertexType] = new SortModelRenderer(m->Model.VertexFF[vertexType]);
|
|
|
|
if (m->Model.VertexHWLit[vertexType])
|
|
|
|
{
|
|
|
|
m->Model.pal_NormalHWLit[vertexType] = new BatchModelRenderer(m->Model.VertexHWLit[vertexType]);
|
|
|
|
m->Model.pal_PlayerHWLit[vertexType] = new BatchModelRenderer(m->Model.VertexHWLit[vertexType]);
|
|
|
|
m->Model.pal_TranspHWLit[vertexType] = new SortModelRenderer(m->Model.VertexHWLit[vertexType]);
|
|
|
|
}
|
|
|
|
if (m->Model.VertexInstancing[vertexType])
|
|
|
|
{
|
|
|
|
m->Model.pal_NormalInstancing[vertexType] = new BatchModelRenderer(m->Model.VertexInstancing[vertexType]);
|
|
|
|
m->Model.pal_PlayerInstancing[vertexType] = new BatchModelRenderer(m->Model.VertexInstancing[vertexType]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m->Model.pal_TranspSortAll = new SortModelRenderer(m->Model.VertexPolygonSort);
|
|
|
|
|
|
|
|
m->Model.ModWireframe = RenderModifierPtr(new WireframeRenderModifier);
|
|
|
|
m->Model.ModPlain = RenderModifierPtr(new PlainRenderModifier);
|
|
|
|
m->Model.ModPlainLit = LitRenderModifierPtr(new PlainLitRenderModifier);
|
|
|
|
SetFastPlayerColor(true);
|
|
|
|
m->Model.ModPlayerLit = LitRenderModifierPtr(new LitPlayerColorRender);
|
|
|
|
m->Model.ModSolidColor = RenderModifierPtr(new SolidColorRenderModifier);
|
|
|
|
m->Model.ModTransparentUnlit = RenderModifierPtr(new TransparentRenderModifier);
|
|
|
|
m->Model.ModTransparentLit = LitRenderModifierPtr(new LitTransparentRenderModifier);
|
|
|
|
m->Model.ModTransparentShadow = RenderModifierPtr(new TransparentShadowRenderModifier);
|
|
|
|
m->Model.ModTransparentDepthShadow = RenderModifierPtr(new TransparentDepthShadowModifier);
|
|
|
|
|
|
|
|
// Particle engine
|
2007-05-02 14:07:08 +02:00
|
|
|
CParticleEngine::GetInstance()->InitParticleSystem();
|
2007-02-10 19:26:57 +01:00
|
|
|
// CEmitter *pEmitter = new CDefaultEmitter(1000, -1);
|
2007-05-02 14:07:08 +02:00
|
|
|
// CParticleEngine::GetInstance()->AddEmitter(pEmitter);
|
2006-03-26 19:36:33 +02:00
|
|
|
|
|
|
|
// Dimensions
|
2004-05-30 02:46:58 +02:00
|
|
|
m_Width = width;
|
|
|
|
m_Height = height;
|
|
|
|
|
|
|
|
// set packing parameters
|
|
|
|
glPixelStorei(GL_PACK_ALIGNMENT,1);
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
|
|
|
|
|
|
|
|
// setup default state
|
|
|
|
glDepthFunc(GL_LEQUAL);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glCullFace(GL_BACK);
|
|
|
|
glFrontFace(GL_CCW);
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
|
2004-06-11 00:24:03 +02:00
|
|
|
GLint bits;
|
|
|
|
glGetIntegerv(GL_DEPTH_BITS,&bits);
|
2009-11-03 22:46:35 +01:00
|
|
|
LOG(CLogger::Normal, LOG_CATEGORY, L"CRenderer::Open: depth bits %d",bits);
|
2004-06-11 00:24:03 +02:00
|
|
|
glGetIntegerv(GL_STENCIL_BITS,&bits);
|
2009-11-03 22:46:35 +01:00
|
|
|
LOG(CLogger::Normal, LOG_CATEGORY, L"CRenderer::Open: stencil bits %d",bits);
|
2004-06-11 00:24:03 +02:00
|
|
|
glGetIntegerv(GL_ALPHA_BITS,&bits);
|
2009-11-03 22:46:35 +01:00
|
|
|
LOG(CLogger::Normal, LOG_CATEGORY, L"CRenderer::Open: alpha bits %d",bits);
|
2004-06-07 21:53:58 +02:00
|
|
|
|
2006-03-28 21:45:44 +02:00
|
|
|
// Validate the currently selected render path
|
|
|
|
SetRenderPath(m_Options.m_RenderPath);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// resize renderer view
|
|
|
|
void CRenderer::Resize(int width,int height)
|
|
|
|
{
|
2006-01-07 02:04:26 +01:00
|
|
|
// need to recreate the shadow map object to resize the shadow texture
|
2006-05-31 18:42:50 +02:00
|
|
|
m->shadow->RecreateTexture();
|
2006-01-07 02:04:26 +01:00
|
|
|
|
|
|
|
m_Width = width;
|
|
|
|
m_Height = height;
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
2004-06-07 21:53:58 +02:00
|
|
|
// SetOptionBool: set boolean renderer option
|
2004-05-30 02:46:58 +02:00
|
|
|
void CRenderer::SetOptionBool(enum Option opt,bool value)
|
|
|
|
{
|
|
|
|
switch (opt) {
|
|
|
|
case OPT_NOVBO:
|
|
|
|
m_Options.m_NoVBO=value;
|
|
|
|
break;
|
2006-03-26 19:36:33 +02:00
|
|
|
case OPT_NOFRAMEBUFFEROBJECT:
|
|
|
|
m_Options.m_NoFramebufferObject=value;
|
|
|
|
break;
|
2004-05-30 02:46:58 +02:00
|
|
|
case OPT_SHADOWS:
|
|
|
|
m_Options.m_Shadows=value;
|
|
|
|
break;
|
2006-05-17 05:53:54 +02:00
|
|
|
case OPT_FANCYWATER:
|
|
|
|
m_Options.m_FancyWater=value;
|
|
|
|
break;
|
2005-10-07 17:24:29 +02:00
|
|
|
default:
|
2009-11-03 22:46:35 +01:00
|
|
|
debug_warn(L"CRenderer::SetOptionBool: unknown option");
|
2005-10-07 17:24:29 +02:00
|
|
|
break;
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
2004-06-07 21:53:58 +02:00
|
|
|
// GetOptionBool: get boolean renderer option
|
2004-05-30 02:46:58 +02:00
|
|
|
bool CRenderer::GetOptionBool(enum Option opt) const
|
|
|
|
{
|
|
|
|
switch (opt) {
|
|
|
|
case OPT_NOVBO:
|
|
|
|
return m_Options.m_NoVBO;
|
2006-03-26 19:36:33 +02:00
|
|
|
case OPT_NOFRAMEBUFFEROBJECT:
|
|
|
|
return m_Options.m_NoFramebufferObject;
|
2004-05-30 02:46:58 +02:00
|
|
|
case OPT_SHADOWS:
|
|
|
|
return m_Options.m_Shadows;
|
2006-05-17 05:53:54 +02:00
|
|
|
case OPT_FANCYWATER:
|
|
|
|
return m_Options.m_FancyWater;
|
2005-10-07 17:24:29 +02:00
|
|
|
default:
|
2009-11-03 22:46:35 +01:00
|
|
|
debug_warn(L"CRenderer::GetOptionBool: unknown option");
|
2005-10-07 17:24:29 +02:00
|
|
|
break;
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
2004-06-07 21:53:58 +02:00
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
2004-06-07 21:53:58 +02:00
|
|
|
// SetOptionColor: set color renderer option
|
2006-09-26 03:44:20 +02:00
|
|
|
// void CRenderer::SetOptionColor(Option UNUSED(opt),const RGBAColor& UNUSED(value))
|
|
|
|
// {
|
|
|
|
// // switch (opt) {
|
|
|
|
// // default:
|
2009-11-03 22:46:35 +01:00
|
|
|
// debug_warn(L"CRenderer::SetOptionColor: unknown option");
|
2006-09-26 03:44:20 +02:00
|
|
|
// // break;
|
|
|
|
// // }
|
|
|
|
// }
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2004-10-17 23:01:00 +02:00
|
|
|
void CRenderer::SetOptionFloat(enum Option opt, float val)
|
|
|
|
{
|
2004-10-21 17:04:19 +02:00
|
|
|
switch(opt)
|
|
|
|
{
|
|
|
|
case OPT_LODBIAS:
|
|
|
|
m_Options.m_LodBias = val;
|
|
|
|
break;
|
2005-10-07 17:24:29 +02:00
|
|
|
default:
|
2009-11-03 22:46:35 +01:00
|
|
|
debug_warn(L"CRenderer::SetOptionFloat: unknown option");
|
2005-10-07 17:24:29 +02:00
|
|
|
break;
|
2004-10-21 17:04:19 +02:00
|
|
|
}
|
2004-10-17 23:01:00 +02:00
|
|
|
}
|
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
2004-06-07 21:53:58 +02:00
|
|
|
// GetOptionColor: get color renderer option
|
2006-09-26 03:44:20 +02:00
|
|
|
// const RGBAColor& CRenderer::GetOptionColor(Option UNUSED(opt)) const
|
|
|
|
// {
|
|
|
|
// static const RGBAColor defaultColor(1.0f,1.0f,1.0f,1.0f);
|
|
|
|
//
|
|
|
|
// // switch (opt) {
|
|
|
|
// // default:
|
2009-11-03 22:46:35 +01:00
|
|
|
// debug_warn(L"CRenderer::GetOptionColor: unknown option");
|
2006-09-26 03:44:20 +02:00
|
|
|
// // break;
|
|
|
|
// // }
|
|
|
|
//
|
|
|
|
// return defaultColor;
|
|
|
|
// }
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2005-10-05 18:42:09 +02:00
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// SetRenderPath: Select the preferred render path.
|
|
|
|
// This may only be called before Open(), because the layout of vertex arrays and other
|
|
|
|
// data may depend on the chosen render path.
|
|
|
|
void CRenderer::SetRenderPath(RenderPath rp)
|
|
|
|
{
|
2006-03-28 21:45:44 +02:00
|
|
|
if (!m->IsOpen)
|
|
|
|
{
|
|
|
|
// Delay until Open() is called.
|
|
|
|
m_Options.m_RenderPath = rp;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Renderer has been opened, so validate the selected renderpath
|
2005-10-25 03:43:07 +02:00
|
|
|
if (rp == RP_DEFAULT)
|
2005-10-05 18:42:09 +02:00
|
|
|
{
|
2006-03-31 04:19:11 +02:00
|
|
|
if (m->CanUseRenderPathVertexShader())
|
2005-10-25 03:43:07 +02:00
|
|
|
rp = RP_VERTEXSHADER;
|
|
|
|
else
|
|
|
|
rp = RP_FIXED;
|
|
|
|
}
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
if (rp == RP_VERTEXSHADER)
|
|
|
|
{
|
2006-03-31 04:19:11 +02:00
|
|
|
if (!m->CanUseRenderPathVertexShader())
|
2005-10-25 03:43:07 +02:00
|
|
|
{
|
2009-11-03 22:46:35 +01:00
|
|
|
LOG(CLogger::Warning, LOG_CATEGORY, L"Falling back to fixed function\n");
|
2005-10-25 03:43:07 +02:00
|
|
|
rp = RP_FIXED;
|
|
|
|
}
|
2005-10-05 18:42:09 +02:00
|
|
|
}
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-05 18:42:09 +02:00
|
|
|
m_Options.m_RenderPath = rp;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CStr CRenderer::GetRenderPathName(RenderPath rp)
|
|
|
|
{
|
|
|
|
switch(rp) {
|
|
|
|
case RP_DEFAULT: return "default";
|
|
|
|
case RP_FIXED: return "fixed";
|
|
|
|
case RP_VERTEXSHADER: return "vertexshader";
|
|
|
|
default: return "(invalid)";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
CRenderer::RenderPath CRenderer::GetRenderPathByName(const CStr& name)
|
2005-10-05 18:42:09 +02:00
|
|
|
{
|
|
|
|
if (name == "fixed")
|
|
|
|
return RP_FIXED;
|
|
|
|
if (name == "vertexshader")
|
|
|
|
return RP_VERTEXSHADER;
|
|
|
|
if (name == "default")
|
|
|
|
return RP_DEFAULT;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2009-11-03 22:46:35 +01:00
|
|
|
LOG(CLogger::Warning, LOG_CATEGORY, L"Unknown render path name '%hs', assuming 'default'", name.c_str());
|
2005-10-05 18:42:09 +02:00
|
|
|
return RP_DEFAULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// SetFastPlayerColor
|
|
|
|
void CRenderer::SetFastPlayerColor(bool fast)
|
|
|
|
{
|
|
|
|
m_FastPlayerColor = fast;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
if (m_FastPlayerColor)
|
|
|
|
{
|
|
|
|
if (!FastPlayerColorRender::IsAvailable())
|
|
|
|
{
|
2009-11-03 22:46:35 +01:00
|
|
|
LOG(CLogger::Warning, LOG_CATEGORY, L"Falling back to slower player color rendering.");
|
2005-10-25 03:43:07 +02:00
|
|
|
m_FastPlayerColor = false;
|
|
|
|
}
|
|
|
|
}
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
if (m_FastPlayerColor)
|
2006-03-26 01:54:20 +01:00
|
|
|
m->Model.ModPlayerUnlit = RenderModifierPtr(new FastPlayerColorRender);
|
2005-10-25 03:43:07 +02:00
|
|
|
else
|
2006-03-26 01:54:20 +01:00
|
|
|
m->Model.ModPlayerUnlit = RenderModifierPtr(new SlowPlayerColorRender);
|
2005-10-25 03:43:07 +02:00
|
|
|
}
|
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// BeginFrame: signal frame start
|
|
|
|
void CRenderer::BeginFrame()
|
|
|
|
{
|
|
|
|
// bump frame counter
|
|
|
|
m_FrameCounter++;
|
|
|
|
|
2005-10-05 18:42:09 +02:00
|
|
|
if (m_VertexShader)
|
|
|
|
m_VertexShader->BeginFrame();
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
// zero out all the per-frame stats
|
|
|
|
m_Stats.Reset();
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2006-03-26 01:54:20 +01:00
|
|
|
// choose model renderers for this frame
|
|
|
|
int vertexType;
|
|
|
|
|
|
|
|
if (m_Options.m_Shadows && m->shadow->GetUseDepthTexture())
|
|
|
|
{
|
|
|
|
vertexType = OnlyDiffuse;
|
|
|
|
m->Model.ModNormal = m->Model.ModPlainLit;
|
|
|
|
m->Model.ModPlainLit->SetShadowMap(m->shadow);
|
|
|
|
m->Model.ModPlainLit->SetLightEnv(m_LightEnv);
|
|
|
|
|
|
|
|
m->Model.ModPlayer = m->Model.ModPlayerLit;
|
|
|
|
m->Model.ModPlayerLit->SetShadowMap(m->shadow);
|
|
|
|
m->Model.ModPlayerLit->SetLightEnv(m_LightEnv);
|
|
|
|
|
|
|
|
m->Model.ModTransparent = m->Model.ModTransparentLit;
|
|
|
|
m->Model.ModTransparentLit->SetShadowMap(m->shadow);
|
|
|
|
m->Model.ModTransparentLit->SetLightEnv(m_LightEnv);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vertexType = AmbientDiffuse;
|
|
|
|
m->Model.ModNormal = m->Model.ModPlain;
|
|
|
|
m->Model.ModPlayer = m->Model.ModPlayerUnlit;
|
|
|
|
m->Model.ModTransparent = m->Model.ModTransparentUnlit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_Options.m_RenderPath == RP_VERTEXSHADER)
|
|
|
|
{
|
2006-03-28 21:45:44 +02:00
|
|
|
debug_assert(m->Model.pal_NormalHWLit[vertexType] != 0);
|
|
|
|
|
2006-03-26 01:54:20 +01:00
|
|
|
if (m->Model.pal_NormalInstancing)
|
|
|
|
m->Model.NormalInstancing = m->Model.pal_NormalInstancing[vertexType];
|
|
|
|
else
|
|
|
|
m->Model.NormalInstancing = m->Model.pal_NormalHWLit[vertexType];
|
|
|
|
m->Model.Normal = m->Model.pal_NormalHWLit[vertexType];
|
|
|
|
|
|
|
|
if (m->Model.pal_PlayerInstancing)
|
|
|
|
m->Model.PlayerInstancing = m->Model.pal_PlayerInstancing[vertexType];
|
|
|
|
else
|
|
|
|
m->Model.PlayerInstancing = m->Model.pal_PlayerHWLit[vertexType];
|
|
|
|
m->Model.Player = m->Model.pal_PlayerHWLit[vertexType];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m->Model.NormalInstancing = m->Model.pal_NormalFF[vertexType];
|
|
|
|
m->Model.Normal = m->Model.pal_NormalFF[vertexType];
|
|
|
|
|
|
|
|
m->Model.PlayerInstancing = m->Model.pal_PlayerFF[vertexType];
|
|
|
|
m->Model.Player = m->Model.pal_PlayerFF[vertexType];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_SortAllTransparent)
|
|
|
|
m->Model.Transp = m->Model.pal_TranspSortAll;
|
|
|
|
else if (m_Options.m_RenderPath == RP_VERTEXSHADER)
|
|
|
|
m->Model.Transp = m->Model.pal_TranspHWLit[vertexType];
|
|
|
|
else
|
|
|
|
m->Model.Transp = m->Model.pal_TranspFF[vertexType];
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
2006-03-26 01:54:20 +01:00
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// SetClearColor: set color used to clear screen in BeginFrame()
|
2008-07-19 02:36:42 +02:00
|
|
|
void CRenderer::SetClearColor(SColor4ub color)
|
2004-06-07 21:53:58 +02:00
|
|
|
{
|
2008-07-19 02:36:42 +02:00
|
|
|
m_ClearColor[0] = float(color.R) / 255.0f;
|
|
|
|
m_ClearColor[1] = float(color.G) / 255.0f;
|
|
|
|
m_ClearColor[2] = float(color.B) / 255.0f;
|
|
|
|
m_ClearColor[3] = float(color.A) / 255.0f;
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CRenderer::RenderShadowMap()
|
|
|
|
{
|
2005-05-20 19:09:47 +02:00
|
|
|
PROFILE( "render shadow map" );
|
|
|
|
|
2006-01-07 02:04:26 +01:00
|
|
|
m->shadow->BeginRender();
|
2006-01-22 20:12:30 +01:00
|
|
|
|
2006-02-15 01:45:16 +01:00
|
|
|
float shadowTransp = m_LightEnv->GetTerrainShadowTransparency();
|
|
|
|
glColor3f(shadowTransp, shadowTransp, shadowTransp);
|
2004-06-11 00:24:03 +02:00
|
|
|
|
2006-02-13 15:18:20 +01:00
|
|
|
// Figure out transparent rendering strategy
|
2006-03-26 01:54:20 +01:00
|
|
|
RenderModifierPtr transparentShadows = m->Model.ModTransparentShadow;
|
2006-02-13 15:18:20 +01:00
|
|
|
|
|
|
|
if (m->shadow->GetUseDepthTexture())
|
2006-03-26 01:54:20 +01:00
|
|
|
transparentShadows = m->Model.ModTransparentDepthShadow;
|
2006-02-13 15:18:20 +01:00
|
|
|
|
|
|
|
// Render all closed models (i.e. models where rendering back faces will produce
|
|
|
|
// the correct result)
|
|
|
|
glCullFace(GL_FRONT);
|
|
|
|
|
|
|
|
if (m->shadow->GetUseDepthTexture())
|
|
|
|
m->terrainRenderer->RenderPatches();
|
|
|
|
|
|
|
|
glCullFace(GL_BACK);
|
|
|
|
|
|
|
|
// Render models that aren't closed
|
2004-06-11 00:24:03 +02:00
|
|
|
glDisable(GL_CULL_FACE);
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2006-03-26 01:54:20 +01:00
|
|
|
m->Model.Normal->Render(m->Model.ModSolidColor, MODELFLAG_CASTSHADOWS);
|
|
|
|
if (m->Model.Normal != m->Model.NormalInstancing)
|
|
|
|
m->Model.NormalInstancing->Render(m->Model.ModSolidColor, MODELFLAG_CASTSHADOWS);
|
|
|
|
m->Model.Player->Render(m->Model.ModSolidColor, MODELFLAG_CASTSHADOWS);
|
|
|
|
if (m->Model.Player != m->Model.PlayerInstancing)
|
|
|
|
m->Model.PlayerInstancing->Render(m->Model.ModSolidColor, MODELFLAG_CASTSHADOWS);
|
2005-10-05 18:42:09 +02:00
|
|
|
|
2006-03-26 01:54:20 +01:00
|
|
|
m->Model.Transp->Render(transparentShadows, MODELFLAG_CASTSHADOWS);
|
2004-06-11 00:24:03 +02:00
|
|
|
|
2006-02-11 19:04:32 +01:00
|
|
|
glEnable(GL_CULL_FACE);
|
2004-06-11 00:24:03 +02:00
|
|
|
|
2006-02-11 19:04:32 +01:00
|
|
|
glColor3f(1.0, 1.0, 1.0);
|
2004-06-11 00:24:03 +02:00
|
|
|
|
2006-02-11 19:04:32 +01:00
|
|
|
m->shadow->EndRender();
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CRenderer::RenderPatches()
|
|
|
|
{
|
2006-04-19 02:56:24 +02:00
|
|
|
PROFILE( "render patches" );
|
2005-05-20 19:09:47 +02:00
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
// switch on wireframe if we need it
|
|
|
|
if (m_TerrainRenderMode==WIREFRAME) {
|
2004-07-15 21:29:56 +02:00
|
|
|
MICROLOG(L"wireframe on");
|
2004-05-30 02:46:58 +02:00
|
|
|
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
|
2004-06-07 21:53:58 +02:00
|
|
|
}
|
2004-05-30 02:46:58 +02:00
|
|
|
|
|
|
|
// render all the patches, including blend pass
|
2004-07-15 21:29:56 +02:00
|
|
|
MICROLOG(L"render patch submissions");
|
2006-02-13 15:18:20 +01:00
|
|
|
m->terrainRenderer->RenderTerrain(m_Options.m_Shadows ? m->shadow : 0);
|
2004-06-07 21:53:58 +02:00
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
if (m_TerrainRenderMode==WIREFRAME) {
|
|
|
|
// switch wireframe off again
|
2004-07-15 21:29:56 +02:00
|
|
|
MICROLOG(L"wireframe off");
|
2004-05-30 02:46:58 +02:00
|
|
|
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
|
|
|
|
} else if (m_TerrainRenderMode==EDGED_FACES) {
|
|
|
|
// edged faces: need to make a second pass over the data:
|
|
|
|
// first switch on wireframe
|
|
|
|
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
|
2004-06-07 21:53:58 +02:00
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
// setup some renderstate ..
|
|
|
|
glDepthMask(0);
|
2010-09-10 23:02:10 +02:00
|
|
|
ogl_tex_bind(0, 0);
|
2004-05-30 02:46:58 +02:00
|
|
|
glColor4f(1,1,1,0.35f);
|
|
|
|
glLineWidth(2.0f);
|
2004-06-07 21:53:58 +02:00
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
2006-01-07 02:04:26 +01:00
|
|
|
// render tiles edges
|
|
|
|
m->terrainRenderer->RenderPatches();
|
2004-05-30 02:46:58 +02:00
|
|
|
|
|
|
|
// set color for outline
|
|
|
|
glColor3f(0,0,1);
|
|
|
|
glLineWidth(4.0f);
|
2004-06-07 21:53:58 +02:00
|
|
|
|
|
|
|
// render outline of each patch
|
2006-01-07 02:04:26 +01:00
|
|
|
m->terrainRenderer->RenderOutlines();
|
2004-05-30 02:46:58 +02:00
|
|
|
|
|
|
|
// .. and restore the renderstates
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glDepthMask(1);
|
|
|
|
|
|
|
|
// restore fill mode, and we're done
|
2006-02-13 01:59:59 +01:00
|
|
|
glLineWidth(1.0f);
|
2004-05-30 02:46:58 +02:00
|
|
|
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
|
2004-06-11 00:24:03 +02:00
|
|
|
}
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CRenderer::RenderModels()
|
2004-06-11 00:24:03 +02:00
|
|
|
{
|
2005-05-20 19:09:47 +02:00
|
|
|
PROFILE( "render models ");
|
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
// switch on wireframe if we need it
|
|
|
|
if (m_ModelRenderMode==WIREFRAME) {
|
|
|
|
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
|
2004-06-07 21:53:58 +02:00
|
|
|
}
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2006-03-26 01:54:20 +01:00
|
|
|
m->Model.Normal->Render(m->Model.ModNormal, 0);
|
|
|
|
m->Model.Player->Render(m->Model.ModPlayer, 0);
|
|
|
|
if (m->Model.Normal != m->Model.NormalInstancing)
|
|
|
|
m->Model.NormalInstancing->Render(m->Model.ModNormal, 0);
|
|
|
|
if (m->Model.Player != m->Model.PlayerInstancing)
|
|
|
|
m->Model.PlayerInstancing->Render(m->Model.ModPlayer, 0);
|
2004-06-07 21:53:58 +02:00
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
if (m_ModelRenderMode==WIREFRAME) {
|
|
|
|
// switch wireframe off again
|
|
|
|
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
|
|
|
|
} else if (m_ModelRenderMode==EDGED_FACES) {
|
2006-03-26 01:54:20 +01:00
|
|
|
m->Model.Normal->Render(m->Model.ModWireframe, 0);
|
|
|
|
m->Model.Player->Render(m->Model.ModWireframe, 0);
|
|
|
|
if (m->Model.Normal != m->Model.NormalInstancing)
|
|
|
|
m->Model.NormalInstancing->Render(m->Model.ModWireframe, 0);
|
|
|
|
if (m->Model.Player != m->Model.PlayerInstancing)
|
|
|
|
m->Model.PlayerInstancing->Render(m->Model.ModWireframe, 0);
|
2005-10-25 03:43:07 +02:00
|
|
|
}
|
|
|
|
}
|
2004-06-07 21:53:58 +02:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
void CRenderer::RenderTransparentModels()
|
|
|
|
{
|
|
|
|
PROFILE( "render transparent models ");
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
// switch on wireframe if we need it
|
|
|
|
if (m_ModelRenderMode==WIREFRAME) {
|
|
|
|
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
|
|
|
|
}
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2006-03-26 01:54:20 +01:00
|
|
|
m->Model.Transp->Render(m->Model.ModTransparent, 0);
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
if (m_ModelRenderMode==WIREFRAME) {
|
|
|
|
// switch wireframe off again
|
2004-05-30 02:46:58 +02:00
|
|
|
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
|
2005-10-25 03:43:07 +02:00
|
|
|
} else if (m_ModelRenderMode==EDGED_FACES) {
|
2006-03-26 01:54:20 +01:00
|
|
|
m->Model.Transp->Render(m->Model.ModWireframe, 0);
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-28 04:13:32 +02:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// GetModelViewProjectionMatrix: save the current OpenGL model-view-projection matrix
|
|
|
|
CMatrix3D CRenderer::GetModelViewProjectionMatrix()
|
|
|
|
{
|
|
|
|
CMatrix3D proj;
|
|
|
|
CMatrix3D view;
|
|
|
|
|
|
|
|
glGetFloatv( GL_PROJECTION_MATRIX, &proj._11 );
|
|
|
|
glGetFloatv( GL_MODELVIEW_MATRIX, &view._11 );
|
|
|
|
|
|
|
|
return( proj * view );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// SetObliqueFrustumClipping: change the near plane to the given clip plane (in world space)
|
|
|
|
// Based on code from Game Programming Gems 5, from http://www.terathon.com/code/oblique.html
|
2007-05-02 14:07:08 +02:00
|
|
|
// - cp is a clip plane in camera space (cp.Dot(v) = 0 for any vector v on the plane)
|
2006-05-28 04:13:32 +02:00
|
|
|
// - sign is 1 or -1, to specify the side to clip on
|
|
|
|
void CRenderer::SetObliqueFrustumClipping(const CVector4D& cp, int sign)
|
|
|
|
{
|
|
|
|
float matrix[16];
|
|
|
|
CVector4D q;
|
|
|
|
|
|
|
|
// First, we'll convert the given clip plane to camera space, then we'll
|
|
|
|
// Get the view matrix and normal matrix (top 3x3 part of view matrix)
|
|
|
|
CMatrix3D viewMatrix;
|
|
|
|
m_ViewCamera.m_Orientation.GetInverse(viewMatrix);
|
|
|
|
CMatrix3D normalMatrix = viewMatrix;
|
|
|
|
normalMatrix._14 = 0;
|
|
|
|
normalMatrix._24 = 0;
|
|
|
|
normalMatrix._34 = 0;
|
|
|
|
normalMatrix._44 = 1;
|
|
|
|
normalMatrix._41 = 0;
|
|
|
|
normalMatrix._42 = 0;
|
|
|
|
normalMatrix._43 = 0;
|
|
|
|
|
|
|
|
// Convert the normal to camera space
|
|
|
|
CVector4D planeNormal(cp.m_X, cp.m_Y, cp.m_Z, 0);
|
|
|
|
planeNormal = normalMatrix.Transform(planeNormal);
|
2007-05-02 14:07:08 +02:00
|
|
|
planeNormal.Normalize();
|
2006-05-28 04:13:32 +02:00
|
|
|
|
|
|
|
// Find a point on the plane: we'll take the normal times -D
|
|
|
|
float oldD = cp.m_W;
|
|
|
|
CVector4D pointOnPlane(-oldD * cp.m_X, -oldD * cp.m_Y, -oldD * cp.m_Z, 1);
|
|
|
|
pointOnPlane = viewMatrix.Transform(pointOnPlane);
|
2007-05-02 14:07:08 +02:00
|
|
|
float newD = -pointOnPlane.Dot(planeNormal);
|
2006-05-28 04:13:32 +02:00
|
|
|
|
|
|
|
// Now create a clip plane from the new normal and new D
|
|
|
|
CVector4D camPlane = planeNormal;
|
|
|
|
camPlane.m_W = newD;
|
|
|
|
|
|
|
|
// Grab the current projection matrix from OpenGL
|
|
|
|
glGetFloatv(GL_PROJECTION_MATRIX, matrix);
|
|
|
|
|
|
|
|
// Calculate the clip-space corner point opposite the clipping plane
|
|
|
|
// as (sgn(camPlane.x), sgn(camPlane.y), 1, 1) and
|
|
|
|
// transform it into camera space by multiplying it
|
|
|
|
// by the inverse of the projection matrix
|
|
|
|
|
|
|
|
q.m_X = (sgn(camPlane.m_X) + matrix[8]) / matrix[0];
|
|
|
|
q.m_Y = (sgn(camPlane.m_Y) + matrix[9]) / matrix[5];
|
|
|
|
q.m_Z = -1.0f;
|
|
|
|
q.m_W = (1.0f + matrix[10]) / matrix[14];
|
|
|
|
|
|
|
|
// Calculate the scaled plane vector
|
2007-05-02 14:07:08 +02:00
|
|
|
CVector4D c = camPlane * (sign * 2.0f / camPlane.Dot(q));
|
2006-05-28 04:13:32 +02:00
|
|
|
|
|
|
|
// Replace the third row of the projection matrix
|
|
|
|
matrix[2] = c.m_X;
|
|
|
|
matrix[6] = c.m_Y;
|
|
|
|
matrix[10] = c.m_Z + 1.0f;
|
|
|
|
matrix[14] = c.m_W;
|
|
|
|
|
|
|
|
// Load it back into OpenGL
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadMatrixf(matrix);
|
|
|
|
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// RenderReflections: render the water reflections to the reflection texture
|
|
|
|
void CRenderer::RenderReflections()
|
|
|
|
{
|
2010-03-21 15:18:15 +01:00
|
|
|
PROFILE("render reflections");
|
2006-05-28 04:13:32 +02:00
|
|
|
|
|
|
|
WaterManager& wm = m->waterManager;
|
|
|
|
|
|
|
|
// Remember old camera
|
|
|
|
CCamera normalCamera = m_ViewCamera;
|
|
|
|
|
2006-06-01 00:37:23 +02:00
|
|
|
// Temporarily change the camera to one that is reflected.
|
|
|
|
// Also, for texturing purposes, make it render to a view port the size of the
|
|
|
|
// water texture, stretch the image according to our aspect ratio so it covers
|
|
|
|
// the whole screen despite being rendered into a square, and cover slightly more
|
|
|
|
// of the view so we can see wavy reflections of slightly off-screen objects.
|
2006-05-28 04:13:32 +02:00
|
|
|
m_ViewCamera.m_Orientation.Translate(0, -wm.m_WaterHeight, 0);
|
|
|
|
m_ViewCamera.m_Orientation.Scale(1, -1, 1);
|
|
|
|
m_ViewCamera.m_Orientation.Translate(0, wm.m_WaterHeight, 0);
|
|
|
|
SViewPort vp;
|
|
|
|
vp.m_Height = wm.m_ReflectionTextureSize;
|
|
|
|
vp.m_Width = wm.m_ReflectionTextureSize;
|
|
|
|
vp.m_X = 0;
|
|
|
|
vp.m_Y = 0;
|
2010-06-03 21:07:59 +02:00
|
|
|
m_ViewCamera.SetViewPort(vp);
|
2007-02-10 20:37:33 +01:00
|
|
|
m_ViewCamera.SetProjection(CGameView::defaultNear, CGameView::defaultFar, CGameView::defaultFOV*1.05f); // Slightly higher than view FOV
|
2006-06-01 00:37:23 +02:00
|
|
|
CMatrix3D scaleMat;
|
|
|
|
scaleMat.SetScaling(m_Height/float(std::max(1, m_Width)), 1.0f, 1.0f);
|
|
|
|
m_ViewCamera.m_ProjMat = scaleMat * m_ViewCamera.m_ProjMat;
|
2006-09-14 22:06:21 +02:00
|
|
|
|
|
|
|
m->SetOpenGLCamera(m_ViewCamera);
|
2006-05-28 04:13:32 +02:00
|
|
|
|
|
|
|
CVector4D camPlane(0, 1, 0, -wm.m_WaterHeight);
|
|
|
|
SetObliqueFrustumClipping(camPlane, -1);
|
|
|
|
|
|
|
|
// Save the model-view-projection matrix so the shaders can use it for projective texturing
|
|
|
|
wm.m_ReflectionMatrix = GetModelViewProjectionMatrix();
|
|
|
|
|
|
|
|
// Disable backface culling so trees render properly (it might also be possible to flip
|
|
|
|
// the culling direction here, but this seems to lead to problems)
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
|
|
|
|
// Make the depth buffer work backwards; there seems to be some oddness with
|
|
|
|
// oblique frustum clipping and the "sign" parameter here
|
|
|
|
glClearDepth(0);
|
|
|
|
glClear(GL_DEPTH_BUFFER_BIT);
|
|
|
|
glDepthFunc(GL_GEQUAL);
|
|
|
|
|
|
|
|
// Render sky, terrain and models
|
|
|
|
m->skyManager.RenderSky();
|
2007-05-02 14:07:08 +02:00
|
|
|
ogl_WarnIfError();
|
2006-05-28 04:13:32 +02:00
|
|
|
RenderPatches();
|
2007-05-02 14:07:08 +02:00
|
|
|
ogl_WarnIfError();
|
2006-05-28 04:13:32 +02:00
|
|
|
RenderModels();
|
2007-05-02 14:07:08 +02:00
|
|
|
ogl_WarnIfError();
|
2006-05-28 04:13:32 +02:00
|
|
|
RenderTransparentModels();
|
2007-05-02 14:07:08 +02:00
|
|
|
ogl_WarnIfError();
|
2006-05-28 04:13:32 +02:00
|
|
|
|
|
|
|
// Copy the image to a texture
|
|
|
|
pglActiveTextureARB(GL_TEXTURE0_ARB);
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, wm.m_ReflectionTexture);
|
|
|
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
(GLsizei)wm.m_ReflectionTextureSize, (GLsizei)wm.m_ReflectionTextureSize);
|
2006-05-28 04:13:32 +02:00
|
|
|
|
|
|
|
//Reset old camera and re-enable backface culling
|
2006-09-14 22:06:21 +02:00
|
|
|
m_ViewCamera = normalCamera;
|
|
|
|
m->SetOpenGLCamera(m_ViewCamera);
|
|
|
|
|
2006-05-28 04:13:32 +02:00
|
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
//glClearDepth(1);
|
|
|
|
//glClear(GL_DEPTH_BUFFER_BIT);
|
|
|
|
//glDepthFunc(GL_LEQUAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// RenderRefractions: render the water refractions to the refraction texture
|
|
|
|
void CRenderer::RenderRefractions()
|
|
|
|
{
|
2010-03-21 15:18:15 +01:00
|
|
|
PROFILE("render refractions");
|
2006-05-28 04:13:32 +02:00
|
|
|
|
|
|
|
WaterManager& wm = m->waterManager;
|
|
|
|
|
|
|
|
// Remember old camera
|
|
|
|
CCamera normalCamera = m_ViewCamera;
|
|
|
|
|
2006-06-01 00:37:23 +02:00
|
|
|
// Temporarily change the camera to make it render to a view port the size of the
|
|
|
|
// water texture, stretch the image according to our aspect ratio so it covers
|
|
|
|
// the whole screen despite being rendered into a square, and cover slightly more
|
|
|
|
// of the view so we can see wavy refractions of slightly off-screen objects.
|
2006-05-28 04:13:32 +02:00
|
|
|
SViewPort vp;
|
|
|
|
vp.m_Height = wm.m_RefractionTextureSize;
|
|
|
|
vp.m_Width = wm.m_RefractionTextureSize;
|
|
|
|
vp.m_X = 0;
|
|
|
|
vp.m_Y = 0;
|
2010-06-03 21:07:59 +02:00
|
|
|
m_ViewCamera.SetViewPort(vp);
|
2007-02-10 20:37:33 +01:00
|
|
|
m_ViewCamera.SetProjection(CGameView::defaultNear, CGameView::defaultFar, CGameView::defaultFOV*1.05f); // Slightly higher than view FOV
|
2006-06-01 00:37:23 +02:00
|
|
|
CMatrix3D scaleMat;
|
|
|
|
scaleMat.SetScaling(m_Height/float(std::max(1, m_Width)), 1.0f, 1.0f);
|
|
|
|
m_ViewCamera.m_ProjMat = scaleMat * m_ViewCamera.m_ProjMat;
|
2006-09-14 22:06:21 +02:00
|
|
|
m->SetOpenGLCamera(m_ViewCamera);
|
2006-05-28 04:13:32 +02:00
|
|
|
|
|
|
|
CVector4D camPlane(0, 1, 0, -wm.m_WaterHeight);
|
|
|
|
SetObliqueFrustumClipping(camPlane, -1);
|
|
|
|
|
|
|
|
// Save the model-view-projection matrix so the shaders can use it for projective texturing
|
|
|
|
wm.m_RefractionMatrix = GetModelViewProjectionMatrix();
|
|
|
|
|
|
|
|
// Make the depth buffer work backwards; there seems to be some oddness with
|
|
|
|
// oblique frustum clipping and the "sign" parameter here
|
|
|
|
glClearDepth(0);
|
|
|
|
glClearColor(0.5f, 0.5f, 0.5f, 1.0f); // a neutral gray to blend in with shores
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
glDepthFunc(GL_GEQUAL);
|
|
|
|
|
|
|
|
// Render terrain and models
|
|
|
|
RenderPatches();
|
2007-05-02 14:07:08 +02:00
|
|
|
ogl_WarnIfError();
|
2006-05-28 04:13:32 +02:00
|
|
|
RenderModels();
|
2007-05-02 14:07:08 +02:00
|
|
|
ogl_WarnIfError();
|
2006-05-28 04:13:32 +02:00
|
|
|
RenderTransparentModels();
|
2007-05-02 14:07:08 +02:00
|
|
|
ogl_WarnIfError();
|
2006-05-28 04:13:32 +02:00
|
|
|
|
|
|
|
// Copy the image to a texture
|
|
|
|
pglActiveTextureARB(GL_TEXTURE0_ARB);
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, wm.m_RefractionTexture);
|
|
|
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
(GLsizei)wm.m_RefractionTextureSize, (GLsizei)wm.m_RefractionTextureSize);
|
2006-05-28 04:13:32 +02:00
|
|
|
|
|
|
|
//Reset old camera and re-enable backface culling
|
2006-09-14 22:06:21 +02:00
|
|
|
m_ViewCamera = normalCamera;
|
|
|
|
m->SetOpenGLCamera(m_ViewCamera);
|
|
|
|
|
2006-05-28 04:13:32 +02:00
|
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
glClearDepth(1);
|
|
|
|
glDepthFunc(GL_LEQUAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
2006-09-24 13:25:11 +02:00
|
|
|
// RenderSubmissions: force rendering of any batched objects
|
|
|
|
void CRenderer::RenderSubmissions()
|
2004-06-07 21:53:58 +02:00
|
|
|
{
|
2007-05-02 14:07:08 +02:00
|
|
|
ogl_WarnIfError();
|
2004-08-06 17:01:23 +02:00
|
|
|
|
2006-09-14 22:06:21 +02:00
|
|
|
// Set the camera
|
|
|
|
m->SetOpenGLCamera(m_ViewCamera);
|
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
// Prepare model renderers
|
2005-10-25 04:00:09 +02:00
|
|
|
PROFILE_START("prepare models");
|
2006-03-26 01:54:20 +01:00
|
|
|
m->Model.Normal->PrepareModels();
|
|
|
|
m->Model.Player->PrepareModels();
|
|
|
|
if (m->Model.Normal != m->Model.NormalInstancing)
|
|
|
|
m->Model.NormalInstancing->PrepareModels();
|
|
|
|
if (m->Model.Player != m->Model.PlayerInstancing)
|
|
|
|
m->Model.PlayerInstancing->PrepareModels();
|
|
|
|
m->Model.Transp->PrepareModels();
|
2005-10-25 04:00:09 +02:00
|
|
|
PROFILE_END("prepare models");
|
2005-01-30 07:27:07 +01:00
|
|
|
|
2006-01-07 02:04:26 +01:00
|
|
|
PROFILE_START("prepare terrain");
|
|
|
|
m->terrainRenderer->PrepareForRendering();
|
|
|
|
PROFILE_END("prepare terrain");
|
|
|
|
|
2010-01-09 20:20:14 +01:00
|
|
|
PROFILE_START("prepare overlays");
|
|
|
|
m->overlayRenderer.PrepareForRendering();
|
|
|
|
PROFILE_END("prepare overlays");
|
|
|
|
|
# Added tool for viewing models and animations outside the game.
Atlas: Added ActorViewer. Moved GL canvas into separate class for shared
use. Disabled message-handling callback while blocked on the game, and
stopped creating dialog boxes inside the game thread in order to avoid
deadlocks (hopefully). Support multiple Views (for independent sets of
camera/update/render code). Recalculate territory boundaries when
necessary. Changed default list of animations to match those currently
used by actors.
# Tidied up more code.
Moved some more #includes out of .h files, to minimise unnecessary
compilation.
MathUtil: Deleted unused/unuseful macros (M_PI (use PI instead), M_PI_2
(use PI/2), MAX3, ABS (use abs)).
ObjectManager: Removed some ScEd-specific things.
Unit: Moved creation out of UnitManager, so units can be created without
adding to the manager. Changed CStr8 to the more conventional CStr.
app_hooks: Removed warning for setting multiple times.
win: Restored SEH catcher.
GameSetup, GameView: Removed RenderNoCull, because it doesn't seem to do
what it says it does ("force renderer to load everything") since we're
loading-on-demand most stuff and it doesn't seem especially useful since
we'd prefer to minimise loading times (but feel free to correct me if
I'm wrong). (And because it crashes when things need to be initialised
in a different order, so it's easier to remove than to understand and
fix it.)
PatchRData, Renderer: Work sensibly when there's no game (hence no LOS
manager, water, etc).
LOSManager: Use entity position instead of actor position when possible.
TerritoryManager: Allow delayed recalculations (so Atlas can issue lots
of move+recalculate commands per frame).
Cinematic: Non-pointer wxTimer, so it doesn't leak and doesn't have to
be deleted manually.
This was SVN commit r4261.
2006-08-28 19:36:42 +02:00
|
|
|
if (m_Options.m_Shadows)
|
|
|
|
{
|
2006-02-11 19:04:32 +01:00
|
|
|
MICROLOG(L"render shadows");
|
|
|
|
RenderShadowMap();
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
2006-02-11 19:04:32 +01:00
|
|
|
// clear buffers
|
|
|
|
glClearColor(m_ClearColor[0],m_ClearColor[1],m_ClearColor[2],m_ClearColor[3]);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
|
|
|
|
2007-05-02 14:07:08 +02:00
|
|
|
ogl_WarnIfError();
|
2004-08-06 17:01:23 +02:00
|
|
|
|
2010-03-21 15:18:15 +01:00
|
|
|
if (m_WaterManager->m_RenderWater && m_WaterManager->WillRenderFancyWater())
|
2006-05-28 04:13:32 +02:00
|
|
|
{
|
|
|
|
// render reflected and refracted scenes, then re-clear the screen
|
|
|
|
RenderReflections();
|
|
|
|
RenderRefractions();
|
|
|
|
glClearColor(m_ClearColor[0],m_ClearColor[1],m_ClearColor[2],m_ClearColor[3]);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
}
|
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
// render submitted patches and models
|
2004-07-15 21:29:56 +02:00
|
|
|
MICROLOG(L"render patches");
|
2004-05-30 02:46:58 +02:00
|
|
|
RenderPatches();
|
2007-05-02 14:07:08 +02:00
|
|
|
ogl_WarnIfError();
|
2004-08-06 17:01:23 +02:00
|
|
|
|
2006-12-05 03:08:52 +01:00
|
|
|
if (g_Game && m_RenderTerritories)
|
2006-09-22 19:43:00 +02:00
|
|
|
{
|
2010-05-20 20:09:23 +02:00
|
|
|
// g_Game->GetWorld()->GetTerritoryManager()->RenderTerritories(); // TODO: implement in new sim system
|
2007-05-02 14:07:08 +02:00
|
|
|
ogl_WarnIfError();
|
2006-09-22 19:43:00 +02:00
|
|
|
}
|
2006-09-07 00:26:27 +02:00
|
|
|
|
2006-04-17 22:02:51 +02:00
|
|
|
// render debug-related terrain overlays
|
|
|
|
TerrainOverlay::RenderOverlays();
|
2007-05-02 14:07:08 +02:00
|
|
|
ogl_WarnIfError();
|
2006-04-17 22:02:51 +02:00
|
|
|
|
2010-05-28 01:23:53 +02:00
|
|
|
// render other debug-related overlays before water (so they can be displayed when underwater)
|
|
|
|
PROFILE_START("render overlays");
|
|
|
|
m->overlayRenderer.RenderOverlays();
|
|
|
|
PROFILE_END("render overlays");
|
|
|
|
ogl_WarnIfError();
|
|
|
|
|
2004-07-15 21:29:56 +02:00
|
|
|
MICROLOG(L"render models");
|
2004-06-07 21:53:58 +02:00
|
|
|
RenderModels();
|
2007-05-02 14:07:08 +02:00
|
|
|
ogl_WarnIfError();
|
2004-08-06 17:01:23 +02:00
|
|
|
|
2006-07-09 00:40:01 +02:00
|
|
|
// render transparent stuff, so it can overlap models/terrain
|
2004-07-15 21:29:56 +02:00
|
|
|
MICROLOG(L"render transparent");
|
2005-10-25 03:43:07 +02:00
|
|
|
RenderTransparentModels();
|
2007-05-02 14:07:08 +02:00
|
|
|
ogl_WarnIfError();
|
2004-06-07 21:53:58 +02:00
|
|
|
|
2006-05-29 02:49:09 +02:00
|
|
|
// render water
|
# Added tool for viewing models and animations outside the game.
Atlas: Added ActorViewer. Moved GL canvas into separate class for shared
use. Disabled message-handling callback while blocked on the game, and
stopped creating dialog boxes inside the game thread in order to avoid
deadlocks (hopefully). Support multiple Views (for independent sets of
camera/update/render code). Recalculate territory boundaries when
necessary. Changed default list of animations to match those currently
used by actors.
# Tidied up more code.
Moved some more #includes out of .h files, to minimise unnecessary
compilation.
MathUtil: Deleted unused/unuseful macros (M_PI (use PI instead), M_PI_2
(use PI/2), MAX3, ABS (use abs)).
ObjectManager: Removed some ScEd-specific things.
Unit: Moved creation out of UnitManager, so units can be created without
adding to the manager. Changed CStr8 to the more conventional CStr.
app_hooks: Removed warning for setting multiple times.
win: Restored SEH catcher.
GameSetup, GameView: Removed RenderNoCull, because it doesn't seem to do
what it says it does ("force renderer to load everything") since we're
loading-on-demand most stuff and it doesn't seem especially useful since
we'd prefer to minimise loading times (but feel free to correct me if
I'm wrong). (And because it crashes when things need to be initialised
in a different order, so it's easier to remove than to understand and
fix it.)
PatchRData, Renderer: Work sensibly when there's no game (hence no LOS
manager, water, etc).
LOSManager: Use entity position instead of actor position when possible.
TerritoryManager: Allow delayed recalculations (so Atlas can issue lots
of move+recalculate commands per frame).
Cinematic: Non-pointer wxTimer, so it doesn't leak and doesn't have to
be deleted manually.
This was SVN commit r4261.
2006-08-28 19:36:42 +02:00
|
|
|
if (m_WaterManager->m_RenderWater && g_Game)
|
2006-01-07 02:04:26 +01:00
|
|
|
{
|
|
|
|
MICROLOG(L"render water");
|
|
|
|
m->terrainRenderer->RenderWater();
|
2007-05-02 14:07:08 +02:00
|
|
|
ogl_WarnIfError();
|
2006-07-09 00:40:01 +02:00
|
|
|
|
2006-05-29 02:49:09 +02:00
|
|
|
// render transparent stuff again, so it can overlap the water
|
|
|
|
MICROLOG(L"render transparent 2");
|
|
|
|
RenderTransparentModels();
|
2007-05-02 14:07:08 +02:00
|
|
|
ogl_WarnIfError();
|
2006-07-09 00:40:01 +02:00
|
|
|
|
|
|
|
// TODO: Maybe think of a better way to deal with transparent objects;
|
|
|
|
// they can appear both under and above water (seaweed vs. trees), but doing
|
|
|
|
// 2 renders causes (a) inefficiency and (b) darker over-water objects (e.g.
|
|
|
|
// trees) than usual because the transparent bits get overwritten twice.
|
|
|
|
// This doesn't look particularly bad, but it is noticeable if you try
|
|
|
|
// turning the water off. On the other hand every user will have water
|
|
|
|
// on all the time, so it might not be worth worrying about.
|
2006-01-07 02:04:26 +01:00
|
|
|
}
|
2005-09-18 05:47:15 +02:00
|
|
|
|
2006-05-28 23:58:56 +02:00
|
|
|
// Clean up texture blend mode so particles and other things render OK
|
|
|
|
// (really this should be cleaned up by whoever set it)
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
|
2010-01-09 20:20:14 +01:00
|
|
|
// Particle Engine Rendering.
|
2006-02-11 10:40:04 +01:00
|
|
|
MICROLOG(L"render particles");
|
2007-05-02 14:07:08 +02:00
|
|
|
CParticleEngine::GetInstance()->RenderParticles();
|
|
|
|
ogl_WarnIfError();
|
2006-02-11 10:40:04 +01:00
|
|
|
|
2006-01-22 20:12:30 +01:00
|
|
|
// render debug lines
|
|
|
|
if (m_DisplayFrustum)
|
|
|
|
{
|
|
|
|
MICROLOG(L"display frustum");
|
2006-01-29 18:34:45 +01:00
|
|
|
DisplayFrustum();
|
2006-02-11 01:26:40 +01:00
|
|
|
m->shadow->RenderDebugDisplay();
|
2007-05-02 14:07:08 +02:00
|
|
|
ogl_WarnIfError();
|
2006-01-22 20:12:30 +01:00
|
|
|
}
|
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
// empty lists
|
2004-07-15 21:29:56 +02:00
|
|
|
MICROLOG(L"empty lists");
|
2006-01-07 02:04:26 +01:00
|
|
|
m->terrainRenderer->EndFrame();
|
2010-01-09 20:20:14 +01:00
|
|
|
m->overlayRenderer.EndFrame();
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
// Finish model renderers
|
2006-03-26 01:54:20 +01:00
|
|
|
m->Model.Normal->EndFrame();
|
|
|
|
m->Model.Player->EndFrame();
|
|
|
|
if (m->Model.Normal != m->Model.NormalInstancing)
|
|
|
|
m->Model.NormalInstancing->EndFrame();
|
|
|
|
if (m->Model.Player != m->Model.PlayerInstancing)
|
|
|
|
m->Model.PlayerInstancing->EndFrame();
|
|
|
|
m->Model.Transp->EndFrame();
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
2004-06-11 00:24:03 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
2006-01-22 20:12:30 +01:00
|
|
|
// EndFrame: signal frame end
|
2004-05-30 02:46:58 +02:00
|
|
|
void CRenderer::EndFrame()
|
|
|
|
{
|
2010-09-10 23:02:10 +02:00
|
|
|
ogl_tex_bind(0, 0);
|
2004-06-11 00:24:03 +02:00
|
|
|
|
|
|
|
static bool once=false;
|
|
|
|
if (!once && glGetError()) {
|
2009-11-03 22:46:35 +01:00
|
|
|
LOG(CLogger::Error, LOG_CATEGORY, L"CRenderer::EndFrame: GL errors occurred");
|
2004-06-11 00:24:03 +02:00
|
|
|
once=true;
|
2004-06-07 21:53:58 +02:00
|
|
|
}
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
2006-01-29 18:34:45 +01:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// DisplayFrustum: debug displays
|
|
|
|
// - white: cull camera frustum
|
|
|
|
// - red: bounds of shadow casting objects
|
|
|
|
void CRenderer::DisplayFrustum()
|
|
|
|
{
|
|
|
|
glDepthMask(0);
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glColor4ub(255,255,255,64);
|
|
|
|
m_CullCamera.Render(2);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
|
|
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
|
|
glColor3ub(255,255,255);
|
|
|
|
m_CullCamera.Render(2);
|
|
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
|
|
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
glDepthMask(1);
|
|
|
|
}
|
|
|
|
|
2004-06-11 00:24:03 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
2006-09-14 22:06:21 +02:00
|
|
|
// SetSceneCamera: setup projection and transform of camera and adjust viewport to current view
|
|
|
|
// The camera always represents the actual camera used to render a scene, not any virtual camera
|
|
|
|
// used for shadow rendering or reflections.
|
|
|
|
void CRenderer::SetSceneCamera(const CCamera& viewCamera, const CCamera& cullCamera)
|
2004-05-30 02:46:58 +02:00
|
|
|
{
|
2006-01-22 20:12:30 +01:00
|
|
|
m_ViewCamera = viewCamera;
|
|
|
|
m_CullCamera = cullCamera;
|
|
|
|
|
2006-09-14 22:06:21 +02:00
|
|
|
m->shadow->SetupFrame(m_CullCamera, m_LightEnv->GetSunDir());
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
2006-09-14 22:06:21 +02:00
|
|
|
|
2004-08-05 15:07:51 +02:00
|
|
|
void CRenderer::SetViewport(const SViewPort &vp)
|
|
|
|
{
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
glViewport((GLint)vp.m_X,(GLint)vp.m_Y,(GLsizei)vp.m_Width,(GLsizei)vp.m_Height);
|
2004-08-05 15:07:51 +02:00
|
|
|
}
|
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
void CRenderer::Submit(CPatch* patch)
|
|
|
|
{
|
2006-01-07 02:04:26 +01:00
|
|
|
m->terrainRenderer->Submit(patch);
|
2005-09-18 05:47:15 +02:00
|
|
|
}
|
|
|
|
|
2010-01-09 20:20:14 +01:00
|
|
|
void CRenderer::Submit(SOverlayLine* overlay)
|
|
|
|
{
|
|
|
|
m->overlayRenderer.Submit(overlay);
|
|
|
|
}
|
|
|
|
|
2006-09-24 13:25:11 +02:00
|
|
|
void CRenderer::SubmitNonRecursive(CModel* model)
|
2004-06-11 00:24:03 +02:00
|
|
|
{
|
2004-10-06 20:44:47 +02:00
|
|
|
if (model->GetFlags() & MODELFLAG_CASTSHADOWS) {
|
2005-05-20 19:09:47 +02:00
|
|
|
PROFILE( "updating shadow bounds" );
|
2006-01-29 18:34:45 +01:00
|
|
|
m->shadow->AddShadowedBound(model->GetBounds());
|
2004-06-11 00:24:03 +02:00
|
|
|
}
|
|
|
|
|
2005-10-30 02:22:22 +02:00
|
|
|
// Tricky: The call to GetBounds() above can invalidate the position
|
|
|
|
model->ValidatePosition();
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-30 02:22:22 +02:00
|
|
|
bool canUseInstancing = false;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-30 02:22:22 +02:00
|
|
|
if (model->GetModelDef()->GetNumBones() == 0)
|
|
|
|
canUseInstancing = true;
|
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
if (model->GetMaterial().IsPlayer())
|
|
|
|
{
|
2006-03-26 01:54:20 +01:00
|
|
|
if (canUseInstancing)
|
|
|
|
m->Model.PlayerInstancing->Submit(model);
|
2005-10-25 03:43:07 +02:00
|
|
|
else
|
2006-03-26 01:54:20 +01:00
|
|
|
m->Model.Player->Submit(model);
|
2005-10-25 03:43:07 +02:00
|
|
|
}
|
2005-10-30 02:22:22 +02:00
|
|
|
else if (model->GetMaterial().UsesAlpha())
|
2005-10-25 03:43:07 +02:00
|
|
|
{
|
2006-03-26 01:54:20 +01:00
|
|
|
m->Model.Transp->Submit(model);
|
2005-10-25 03:43:07 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-03-26 01:54:20 +01:00
|
|
|
if (canUseInstancing)
|
|
|
|
m->Model.NormalInstancing->Submit(model);
|
2005-10-25 03:43:07 +02:00
|
|
|
else
|
2006-03-26 01:54:20 +01:00
|
|
|
m->Model.Normal->Submit(model);
|
2005-10-25 03:43:07 +02:00
|
|
|
}
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-09-24 13:25:11 +02:00
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
// Render the given scene
|
|
|
|
void CRenderer::RenderScene(Scene *scene)
|
2004-05-30 02:46:58 +02:00
|
|
|
{
|
2006-09-24 13:25:11 +02:00
|
|
|
CFrustum frustum = m_CullCamera.GetFrustum();
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2006-09-24 13:25:11 +02:00
|
|
|
MICROLOG(L"collect objects");
|
|
|
|
scene->EnumerateObjects(frustum, this);
|
|
|
|
|
2007-05-02 14:07:08 +02:00
|
|
|
ogl_WarnIfError();
|
2006-09-24 13:25:11 +02:00
|
|
|
|
|
|
|
MICROLOG(L"flush objects");
|
|
|
|
RenderSubmissions();
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
2004-06-07 21:53:58 +02:00
|
|
|
// BindTexture: bind a GL texture object to current active unit
|
2004-05-30 02:46:58 +02:00
|
|
|
void CRenderer::BindTexture(int unit,GLuint tex)
|
2004-06-11 00:24:03 +02:00
|
|
|
{
|
2005-10-30 02:18:15 +01:00
|
|
|
pglActiveTextureARB(GL_TEXTURE0+unit);
|
2004-06-11 00:24:03 +02:00
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D,tex);
|
|
|
|
if (tex) {
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
} else {
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
}
|
|
|
|
m_ActiveTextures[unit]=tex;
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
2005-10-30 00:29:55 +02:00
|
|
|
static inline void CopyTriple(unsigned char* dst,const unsigned char* src)
|
2004-05-30 02:46:58 +02:00
|
|
|
{
|
|
|
|
dst[0]=src[0];
|
|
|
|
dst[1]=src[1];
|
|
|
|
dst[2]=src[2];
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
2004-06-07 21:53:58 +02:00
|
|
|
// LoadAlphaMaps: load the 14 default alpha maps, pack them into one composite texture and
|
2005-09-02 04:54:02 +02:00
|
|
|
// calculate the coordinate of each alphamap within this packed texture
|
2005-05-03 23:36:57 +02:00
|
|
|
int CRenderer::LoadAlphaMaps()
|
2004-05-30 02:46:58 +02:00
|
|
|
{
|
2009-11-03 22:46:35 +01:00
|
|
|
const wchar_t* const key = L"(alpha map composite)";
|
2005-10-21 09:47:38 +02:00
|
|
|
Handle ht = ogl_tex_find(key);
|
|
|
|
// alpha map texture had already been created and is still in memory:
|
|
|
|
// reuse it, do not load again.
|
|
|
|
if(ht > 0)
|
|
|
|
{
|
|
|
|
m_hCompositeAlphaMap = ht;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-09-02 04:54:02 +02:00
|
|
|
//
|
|
|
|
// load all textures and store Handle in array
|
|
|
|
//
|
2005-10-30 00:29:55 +02:00
|
|
|
Handle textures[NumAlphaMaps] = {0};
|
2009-11-03 22:46:35 +01:00
|
|
|
VfsPath path(L"art/textures/terrain/alphamaps/special");
|
|
|
|
const wchar_t* fnames[NumAlphaMaps] = {
|
|
|
|
L"blendcircle.dds",
|
|
|
|
L"blendlshape.dds",
|
|
|
|
L"blendedge.dds",
|
|
|
|
L"blendedgecorner.dds",
|
|
|
|
L"blendedgetwocorners.dds",
|
|
|
|
L"blendfourcorners.dds",
|
|
|
|
L"blendtwooppositecorners.dds",
|
|
|
|
L"blendlshapecorner.dds",
|
|
|
|
L"blendtwocorners.dds",
|
|
|
|
L"blendcorner.dds",
|
|
|
|
L"blendtwoedges.dds",
|
|
|
|
L"blendthreecorners.dds",
|
|
|
|
L"blendushape.dds",
|
|
|
|
L"blendbad.dds"
|
2005-03-18 23:02:20 +01:00
|
|
|
};
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
size_t base = 0; // texture width/height (see below)
|
2005-09-02 04:54:02 +02:00
|
|
|
// for convenience, we require all alpha maps to be of the same BPP
|
|
|
|
// (avoids another ogl_tex_get_size call, and doesn't hurt)
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
size_t bpp = 0;
|
|
|
|
for(size_t i=0;i<NumAlphaMaps;i++)
|
2005-09-02 04:54:02 +02:00
|
|
|
{
|
2005-10-21 09:47:38 +02:00
|
|
|
// note: these individual textures can be discarded afterwards;
|
|
|
|
// we cache the composite.
|
2010-07-04 12:15:53 +02:00
|
|
|
textures[i] = ogl_tex_load(g_VFS, path/fnames[i]);
|
2005-10-12 06:16:41 +02:00
|
|
|
RETURN_ERR(textures[i]);
|
2005-09-02 04:54:02 +02:00
|
|
|
|
2005-11-18 17:23:39 +01:00
|
|
|
// quick hack: we require plain RGB(A) format, so convert to that.
|
|
|
|
// ideally the texture would be in uncompressed form; then this wouldn't
|
|
|
|
// be necessary.
|
2008-09-18 13:31:12 +02:00
|
|
|
size_t flags;
|
2005-11-18 17:23:39 +01:00
|
|
|
ogl_tex_get_format(textures[i], &flags, 0);
|
|
|
|
ogl_tex_transform_to(textures[i], flags & ~TEX_DXT);
|
|
|
|
|
2005-09-02 04:54:02 +02:00
|
|
|
// get its size and make sure they are all equal.
|
|
|
|
// (the packing algo assumes this)
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
size_t this_width = 0, this_bpp = 0; // fail-safe
|
2005-09-02 04:54:02 +02:00
|
|
|
(void)ogl_tex_get_size(textures[i], &this_width, 0, &this_bpp);
|
|
|
|
// .. first iteration: establish size
|
|
|
|
if(i == 0)
|
|
|
|
{
|
|
|
|
base = this_width;
|
|
|
|
bpp = this_bpp;
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
2005-09-02 04:54:02 +02:00
|
|
|
// .. not first: make sure texture size matches
|
|
|
|
else if(base != this_width || bpp != this_bpp)
|
2008-01-19 12:33:11 +01:00
|
|
|
DEBUG_DISPLAY_ERROR(L"Alpha maps are not identically sized (including pixel depth)");
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
2005-09-02 04:54:02 +02:00
|
|
|
//
|
|
|
|
// copy each alpha map (tile) into one buffer, arrayed horizontally.
|
|
|
|
//
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
size_t tile_w = 2+base+2; // 2 pixel border (avoids bilinear filtering artifacts)
|
|
|
|
size_t total_w = round_up_to_pow2(tile_w * NumAlphaMaps);
|
|
|
|
size_t total_h = base; debug_assert(is_pow2(total_h));
|
2007-12-20 21:21:45 +01:00
|
|
|
shared_ptr<u8> data = io_Allocate(total_w*total_h*3);
|
2004-05-30 02:46:58 +02:00
|
|
|
// for each tile on row
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
for(size_t i=0;i<NumAlphaMaps;i++)
|
2005-09-02 04:54:02 +02:00
|
|
|
{
|
2004-05-30 02:46:58 +02:00
|
|
|
// get src of copy
|
2008-07-19 02:36:42 +02:00
|
|
|
u8* src = 0;
|
|
|
|
(void)ogl_tex_get_data(textures[i], &src);
|
2004-06-07 21:53:58 +02:00
|
|
|
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
size_t srcstep=bpp/8;
|
2004-05-30 02:46:58 +02:00
|
|
|
|
|
|
|
// get destination of copy
|
2007-12-20 21:21:45 +01:00
|
|
|
u8* dst=data.get()+3*(i*tile_w);
|
2004-06-07 21:53:58 +02:00
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
// for each row of image
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
for (size_t j=0;j<base;j++) {
|
2004-05-30 02:46:58 +02:00
|
|
|
// duplicate first pixel
|
|
|
|
CopyTriple(dst,src);
|
|
|
|
dst+=3;
|
|
|
|
CopyTriple(dst,src);
|
|
|
|
dst+=3;
|
|
|
|
|
|
|
|
// copy a row
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
for (size_t k=0;k<base;k++) {
|
2004-05-30 02:46:58 +02:00
|
|
|
CopyTriple(dst,src);
|
|
|
|
dst+=3;
|
|
|
|
src+=srcstep;
|
|
|
|
}
|
|
|
|
// duplicate last pixel
|
|
|
|
CopyTriple(dst,(src-srcstep));
|
|
|
|
dst+=3;
|
|
|
|
CopyTriple(dst,(src-srcstep));
|
|
|
|
dst+=3;
|
|
|
|
|
|
|
|
// advance write pointer for next row
|
2005-09-02 04:54:02 +02:00
|
|
|
dst+=3*(total_w-tile_w);
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
2005-09-02 04:54:02 +02:00
|
|
|
m_AlphaMapCoords[i].u0=float(i*tile_w+2)/float(total_w);
|
|
|
|
m_AlphaMapCoords[i].u1=float((i+1)*tile_w-2)/float(total_w);
|
2004-05-30 02:46:58 +02:00
|
|
|
m_AlphaMapCoords[i].v0=0.0f;
|
|
|
|
m_AlphaMapCoords[i].v1=1.0f;
|
|
|
|
}
|
|
|
|
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
for (size_t i=0;i<NumAlphaMaps;i++)
|
2005-10-30 00:29:55 +02:00
|
|
|
(void)ogl_tex_free(textures[i]);
|
2004-12-16 13:41:54 +01:00
|
|
|
|
2005-09-02 04:54:02 +02:00
|
|
|
// upload the composite texture
|
2005-09-20 00:48:20 +02:00
|
|
|
Tex t;
|
2007-12-20 21:21:45 +01:00
|
|
|
(void)tex_wrap(total_w, total_h, 24, 0, data, 0, &t);
|
2010-07-04 12:15:53 +02:00
|
|
|
m_hCompositeAlphaMap = ogl_tex_wrap(&t, g_VFS, key);
|
2005-09-29 07:00:20 +02:00
|
|
|
(void)ogl_tex_set_filter(m_hCompositeAlphaMap, GL_LINEAR);
|
|
|
|
(void)ogl_tex_set_wrap (m_hCompositeAlphaMap, GL_CLAMP_TO_EDGE);
|
2005-10-12 06:16:41 +02:00
|
|
|
int ret = ogl_tex_upload(m_hCompositeAlphaMap, 0, 0, GL_INTENSITY);
|
2005-05-03 23:36:57 +02:00
|
|
|
|
2005-10-12 06:16:41 +02:00
|
|
|
return ret;
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
2004-12-16 13:41:54 +01:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// UnloadAlphaMaps: frees the resources allocates by LoadAlphaMaps
|
|
|
|
void CRenderer::UnloadAlphaMaps()
|
|
|
|
{
|
2005-09-20 00:48:20 +02:00
|
|
|
ogl_tex_free(m_hCompositeAlphaMap);
|
2005-12-02 03:08:26 +01:00
|
|
|
m_hCompositeAlphaMap = 0;
|
2004-12-16 13:41:54 +01:00
|
|
|
}
|
2005-10-10 16:15:28 +02:00
|
|
|
|
|
|
|
|
2005-10-12 06:16:41 +02:00
|
|
|
|
2005-10-10 16:15:28 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Scripting Interface
|
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
jsval CRenderer::JSI_GetFastPlayerColor(JSContext*)
|
|
|
|
{
|
|
|
|
return ToJSVal(m_FastPlayerColor);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CRenderer::JSI_SetFastPlayerColor(JSContext* ctx, jsval newval)
|
|
|
|
{
|
|
|
|
bool fast;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
if (!ToPrimitive(ctx, newval, fast))
|
|
|
|
return;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
SetFastPlayerColor(fast);
|
|
|
|
}
|
|
|
|
|
|
|
|
jsval CRenderer::JSI_GetRenderPath(JSContext*)
|
|
|
|
{
|
|
|
|
return ToJSVal(GetRenderPathName(m_Options.m_RenderPath));
|
|
|
|
}
|
|
|
|
|
|
|
|
void CRenderer::JSI_SetRenderPath(JSContext* ctx, jsval newval)
|
|
|
|
{
|
|
|
|
CStr name;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
if (!ToPrimitive(ctx, newval, name))
|
|
|
|
return;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
SetRenderPath(GetRenderPathByName(name));
|
|
|
|
}
|
|
|
|
|
2006-02-11 19:04:32 +01:00
|
|
|
jsval CRenderer::JSI_GetUseDepthTexture(JSContext*)
|
|
|
|
{
|
|
|
|
return ToJSVal(m->shadow->GetUseDepthTexture());
|
|
|
|
}
|
|
|
|
|
|
|
|
void CRenderer::JSI_SetUseDepthTexture(JSContext* ctx, jsval newval)
|
|
|
|
{
|
|
|
|
bool depthTexture;
|
|
|
|
|
|
|
|
if (!ToPrimitive(ctx, newval, depthTexture))
|
|
|
|
return;
|
|
|
|
|
|
|
|
m->shadow->SetUseDepthTexture(depthTexture);
|
|
|
|
}
|
|
|
|
|
2006-02-16 00:50:24 +01:00
|
|
|
jsval CRenderer::JSI_GetDepthTextureBits(JSContext*)
|
|
|
|
{
|
|
|
|
return ToJSVal(m->shadow->GetDepthTextureBits());
|
|
|
|
}
|
|
|
|
|
|
|
|
void CRenderer::JSI_SetDepthTextureBits(JSContext* ctx, jsval newval)
|
|
|
|
{
|
|
|
|
int depthTextureBits;
|
|
|
|
|
|
|
|
if (!ToPrimitive(ctx, newval, depthTextureBits))
|
|
|
|
return;
|
|
|
|
|
|
|
|
m->shadow->SetDepthTextureBits(depthTextureBits);
|
|
|
|
}
|
|
|
|
|
2006-05-17 04:24:17 +02:00
|
|
|
jsval CRenderer::JSI_GetSky(JSContext*)
|
|
|
|
{
|
|
|
|
return ToJSVal(m->skyManager.GetSkySet());
|
|
|
|
}
|
|
|
|
|
|
|
|
void CRenderer::JSI_SetSky(JSContext* ctx, jsval newval)
|
|
|
|
{
|
|
|
|
CStrW skySet;
|
2006-05-28 23:58:56 +02:00
|
|
|
if (!ToPrimitive<CStrW>(ctx, newval, skySet)) return;
|
2006-05-17 04:24:17 +02:00
|
|
|
m->skyManager.SetSkySet(skySet);
|
|
|
|
}
|
|
|
|
|
2005-10-10 16:15:28 +02:00
|
|
|
void CRenderer::ScriptingInit()
|
|
|
|
{
|
2005-10-25 03:43:07 +02:00
|
|
|
AddProperty(L"fastPlayerColor", &CRenderer::JSI_GetFastPlayerColor, &CRenderer::JSI_SetFastPlayerColor);
|
|
|
|
AddProperty(L"renderpath", &CRenderer::JSI_GetRenderPath, &CRenderer::JSI_SetRenderPath);
|
2006-02-11 19:04:32 +01:00
|
|
|
AddProperty(L"useDepthTexture", &CRenderer::JSI_GetUseDepthTexture, &CRenderer::JSI_SetUseDepthTexture);
|
2005-10-25 04:22:22 +02:00
|
|
|
AddProperty(L"sortAllTransparent", &CRenderer::m_SortAllTransparent);
|
2006-01-22 20:12:30 +01:00
|
|
|
AddProperty(L"displayFrustum", &CRenderer::m_DisplayFrustum);
|
2006-02-13 15:18:20 +01:00
|
|
|
AddProperty(L"shadowZBias", &CRenderer::m_ShadowZBias);
|
2007-02-09 18:04:55 +01:00
|
|
|
AddProperty(L"shadowMapSize", &CRenderer::m_ShadowMapSize);
|
2006-02-16 00:50:24 +01:00
|
|
|
AddProperty(L"disableCopyShadow", &CRenderer::m_DisableCopyShadow);
|
|
|
|
AddProperty(L"depthTextureBits", &CRenderer::JSI_GetDepthTextureBits, &CRenderer::JSI_SetDepthTextureBits);
|
2006-09-23 18:04:54 +02:00
|
|
|
AddProperty(L"skipSubmit", &CRenderer::m_SkipSubmit);
|
2006-05-17 04:24:17 +02:00
|
|
|
AddProperty(L"skySet", &CRenderer::JSI_GetSky, &CRenderer::JSI_SetSky);
|
2005-10-10 16:15:28 +02:00
|
|
|
|
|
|
|
CJSObject<CRenderer>::ScriptingInit("Renderer");
|
|
|
|
}
|
|
|
|
|
2007-05-07 18:33:24 +02:00
|
|
|
|
2010-09-10 23:02:10 +02:00
|
|
|
CTextureManager& CRenderer::GetTextureManager()
|
|
|
|
{
|
|
|
|
return m->textureManager;
|
|
|
|
}
|