diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index 562b45f738..3056099da5 100755 --- a/source/graphics/GameView.cpp +++ b/source/graphics/GameView.cpp @@ -129,6 +129,7 @@ void CGameView::RegisterInit(CGameAttributes *pAttribs) RegMemFun(g_TexMan.GetSingletonPtr(), &CTextureManager::LoadTerrainTextures, L"LoadTerrainTextures", 15); RegMemFun(g_ObjMan.GetSingletonPtr(), &CObjectManager::LoadObjects, L"LoadObjects", 1); RegMemFun(g_Renderer.GetSingletonPtr(), &CRenderer::LoadAlphaMaps, L"LoadAlphaMaps", 45); + RegMemFun(g_Renderer.GetSingletonPtr(), &CRenderer::LoadWaterTextures, L"LoadWaterTextures", 100); } diff --git a/source/graphics/Material.cpp b/source/graphics/Material.cpp index 1b048e694a..901c79375a 100755 --- a/source/graphics/Material.cpp +++ b/source/graphics/Material.cpp @@ -81,11 +81,11 @@ bool CMaterial::operator ==(const CMaterial &material) void CMaterial::Bind() { - glMaterialfv(GL_FRONT, GL_DIFFUSE, &m_Diffuse.r); + glMaterialf(GL_FRONT, GL_SHININESS, m_SpecularPower); + glMaterialfv(GL_FRONT, GL_DIFFUSE, &m_Diffuse.r); glMaterialfv(GL_FRONT, GL_AMBIENT, &m_Ambient.r); glMaterialfv(GL_FRONT, GL_SPECULAR, &m_Specular.r); glMaterialfv(GL_FRONT, GL_EMISSION, &m_Emissive.r); - glMaterialf(GL_FRONT, GL_SHININESS, m_SpecularPower); oglCheck(); } diff --git a/source/gui/GUIRenderer.cpp b/source/gui/GUIRenderer.cpp index 405c8209d2..8d5eb79b0c 100644 --- a/source/gui/GUIRenderer.cpp +++ b/source/gui/GUIRenderer.cpp @@ -261,10 +261,6 @@ public: // the number of times the following code is called - it looks like // a rather worrying amount of work for rendering a single button... - // Also TODO: DOT3_RGB requires GL_(EXT|ARB)_texture_env_dot3. What should - // we do if that's not supported? (Probable answer: blindly ignore the problem, - // since it's only relevant for TNT2 / RAGE 128 / etc.) - // Texture unit 0: ogl_tex_bind(tex, 0); @@ -297,6 +293,16 @@ public: glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB); + + // GL_DOT3_RGB requires GL_(EXT|ARB)_texture_env_dot3. + // We currently don't bother implementing a fallback because it's + // only lacking on Riva-class HW, but at least want the rest of the + // game to run there without errors. Therefore, squelch the + // OpenGL error that's raised if they aren't actually present. + // Note: higher-level code checks for this extension, but + // allows users the choice of continuing even if not present. + oglSquelchError(GL_INVALID_ENUM); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT); diff --git a/source/lib/lib.h b/source/lib/lib.h index c039b6ef89..9a3efb9fb0 100755 --- a/source/lib/lib.h +++ b/source/lib/lib.h @@ -53,6 +53,7 @@ scope #define LIB_H__ #include +#include // fabsf #include "config.h" @@ -213,11 +214,8 @@ STMT(\ #define SAFE_DELETE(p)\ STMT(\ - if((p))\ - {\ - delete (p);\ - (p) = 0;\ - }\ + delete (p); /* if p == 0, delete is a no-op */ \ + (p) = 0;\ ) @@ -423,6 +421,16 @@ extern u32 u64_lo(u64 x); extern u64 u64_from_u32(u32 hi, u32 lo); +inline bool feq(float f1, float f2) +{ + // the requisite value will change with the magnitude of f1 and f2! + // this is a sane default, but don't use this routine for very + // large/small comparands. + const float epsilon = 0.00001f; + return fabsf(f1 - f2) < epsilon; +} + + extern u16 fp_to_u16(double in); // return random integer in [0, limit). diff --git a/source/maths/Matrix3D.cpp b/source/maths/Matrix3D.cpp index 351304ad74..c9fa0f3ef2 100755 --- a/source/maths/Matrix3D.cpp +++ b/source/maths/Matrix3D.cpp @@ -539,7 +539,7 @@ static void test_inverse() for (int y = 0; y < 4; ++y) { float expected = (x==y)? 1.0f : 0.0f; // identity should have 1s on diagonal - TEST(fabs(m(x,y) - expected) < 0.0001f); + TEST(feq(m(x,y), expected)); } } } @@ -559,19 +559,18 @@ static void test_quats() q.ToMatrix(m); CQuaternion q2 = m.GetRotation(); - float epsilon = 0.0001f; // I hope there's a good reason why they're sometimes negated, and // it's not just a bug... bool ok_oneway = - fabs(q2.m_W - q.m_W) < epsilon && - fabs(q2.m_V.X - q.m_V.X) < epsilon && - fabs(q2.m_V.Y - q.m_V.Y) < epsilon && - fabs(q2.m_V.Z - q.m_V.Z) < epsilon; + feq(q2.m_W, q.m_W) && + feq(q2.m_V.X, q.m_V.X) && + feq(q2.m_V.Y, q.m_V.Y) && + feq(q2.m_V.Z, q.m_V.Z); bool ok_otherway = - fabs(q2.m_W + q.m_W) < epsilon && - fabs(q2.m_V.X + q.m_V.X) < epsilon && - fabs(q2.m_V.Y + q.m_V.Y) < epsilon && - fabs(q2.m_V.Z + q.m_V.Z) < epsilon; + feq(q2.m_W, -q.m_W) && + feq(q2.m_V.X, -q.m_V.X) && + feq(q2.m_V.Y, -q.m_V.Y) && + feq(q2.m_V.Z, -q.m_V.Z); TEST(ok_oneway ^ ok_otherway); } } diff --git a/source/renderer/ModelDefRData.cpp b/source/renderer/ModelDefRData.cpp index 2357e5b385..f6e52e469e 100644 --- a/source/renderer/ModelDefRData.cpp +++ b/source/renderer/ModelDefRData.cpp @@ -71,7 +71,7 @@ void CModelDefRData::PrepareStream(uint streamflags) return; u8* base = m_Array.Bind(); - size_t stride = m_Array.GetStride(); + GLsizei stride = (GLsizei)m_Array.GetStride(); glTexCoordPointer(2, GL_FLOAT, stride, base + m_UV.offset); } diff --git a/source/renderer/ModelRData.cpp b/source/renderer/ModelRData.cpp index 5a59c2e029..1b5c25162f 100755 --- a/source/renderer/ModelRData.cpp +++ b/source/renderer/ModelRData.cpp @@ -3,6 +3,7 @@ #include #include "MathUtil.h" +#include "lib/ogl.h" #include "lib/res/graphics/ogl_tex.h" #include "lib/res/graphics/ogl_shader.h" #include "Renderer.h" @@ -284,7 +285,7 @@ void CModelRData::FinishRender(u32 streamflags) // Try to use RenderModels instead wherever possible. // Must be bracketed by calls to CModelRData::SetupRender/FinishRender void CModelRData::RenderStreams(u32 streamflags, int tmus) -{ +{ CModelDefPtr mdldef=m_Model->GetModelDef(); if (streamflags & STREAM_UV0) @@ -299,7 +300,7 @@ void CModelRData::RenderStreams(u32 streamflags, int tmus) } u8* base = m_DynamicArray.Bind(); - size_t stride = m_DynamicArray.GetStride(); + GLsizei stride = (GLsizei)m_DynamicArray.GetStride(); glVertexPointer(3, GL_FLOAT, stride, base + m_Position.offset); if (streamflags & STREAM_COLOR) @@ -432,7 +433,7 @@ void CModelRData::RenderModels(u32 streamflags, u32 flags) CModelDefPtr mdldef = modeldata->GetModel()->GetModelDef(); u8* base = modeldata->m_DynamicArray.Bind(); - size_t stride = modeldata->m_DynamicArray.GetStride(); + GLsizei stride = (GLsizei)modeldata->m_DynamicArray.GetStride(); glVertexPointer(3, GL_FLOAT, stride, base + modeldata->m_Position.offset); diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index a5f3ffb32a..00edd348a8 100755 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -43,6 +43,7 @@ #include "lib/res/file/file.h" #include "lib/res/graphics/tex.h" #include "lib/res/graphics/ogl_tex.h" +#include "lib/res/file/vfs.h" #include "timer.h" #include "renderer/RenderPathVertexShader.h" @@ -74,13 +75,13 @@ CRenderer::CRenderer() m_ActiveTextures[i]=0; } + // water m_RenderWater = true; m_WaterHeight = 5.0f; m_WaterColor = CColor(0.3f, 0.35f, 0.7f, 1.0f); m_WaterFullDepth = 4.0f; m_WaterMaxAlpha = 0.85f; m_WaterAlphaOffset = -0.05f; - m_SWaterTrans=0; m_TWaterTrans=0; m_SWaterSpeed=0.0015f; @@ -89,20 +90,6 @@ CRenderer::CRenderer() m_TWaterScrollCounter=0; m_WaterCurrentTex=0; - for (int x=0; x<60; x++) - { - char waterName[1000]; - sprintf(waterName, "art/textures/terrain/types/water/animation2/water%02d.dds", x+1); - m_WaterTexture[x]=ogl_tex_load(waterName); - if (m_WaterTexture[x] <= 0) - { - LOG(ERROR, LOG_CATEGORY, "LoadTexture failed on \"%s\"", waterName); - ogl_tex_free(m_WaterTexture[x]); - } - else - ogl_tex_upload(m_WaterTexture[x]); - } - ONCE( ScriptingInit(); ); } @@ -112,6 +99,9 @@ CRenderer::~CRenderer() { delete m_VertexShader; m_VertexShader = 0; + + UnloadAlphaMaps(); + UnloadWaterTextures(); } @@ -737,6 +727,7 @@ void CRenderer::RenderShadowMap() glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); + oglSquelchError(GL_INVALID_ENUM); // Set the proper LOD bias glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, m_Options.m_LodBias); @@ -1377,7 +1368,7 @@ int CRenderer::LoadAlphaMaps() { (void)pp_append_file(&pp, fnames[i]); textures[i] = ogl_tex_load(pp.path); - WARN_ERR(textures[i]); + RETURN_ERR(textures[i]); // get its size and make sure they are all equal. // (the packing algo assumes this) @@ -1452,10 +1443,10 @@ int CRenderer::LoadAlphaMaps() m_hCompositeAlphaMap = ogl_tex_wrap(&t, "(alpha map composite)"); (void)ogl_tex_set_filter(m_hCompositeAlphaMap, GL_LINEAR); (void)ogl_tex_set_wrap (m_hCompositeAlphaMap, GL_CLAMP_TO_EDGE); - (void)ogl_tex_upload(m_hCompositeAlphaMap, 0, 0, GL_INTENSITY); + int ret = ogl_tex_upload(m_hCompositeAlphaMap, 0, 0, GL_INTENSITY); delete[] data; - return 0; + return ret; } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1466,6 +1457,45 @@ void CRenderer::UnloadAlphaMaps() } + + +int CRenderer::LoadWaterTextures() +{ + int i; + + // initialize to 0 in case something fails below + // (we then abort the loop, but don't want undefined values in here) + for (i = 0; i < ARRAY_SIZE(m_WaterTexture); i++) + m_WaterTexture[i] = 0; + + for (i = 0; i < ARRAY_SIZE(m_WaterTexture); i++) + { + char waterName[VFS_MAX_PATH]; + // TODO: add a member variable and setter for this. (can't make this + // a parameter because this function is called via delay-load code) + const char* water_type = "animation2"; + snprintf(waterName, ARRAY_SIZE(waterName), "art/textures/terrain/types/water/%s/water%02d.dds", water_type, i+1); + Handle ht = ogl_tex_load(waterName); + if (ht <= 0) + { + LOG(ERROR, LOG_CATEGORY, "LoadWaterTextures failed on \"%s\"", waterName); + return ht; + } + m_WaterTexture[i]=ht; + RETURN_ERR(ogl_tex_upload(ht)); + } + + return 0; +} + + +void CRenderer::UnloadWaterTextures() +{ + for (int i = 0; i < ARRAY_SIZE(m_WaterTexture); i++) + ogl_tex_free(m_WaterTexture[i]); +} + + /////////////////////////////////////////////////////////////////////////////////////////////////// // Scripting Interface diff --git a/source/renderer/Renderer.h b/source/renderer/Renderer.h index e19c4c5c71..29f3e20bcd 100755 --- a/source/renderer/Renderer.h +++ b/source/renderer/Renderer.h @@ -246,11 +246,18 @@ public: // query transparency of given texture bool IsTextureTransparent(CTexture* texture); - // load the default set of alphamaps; return false if any alphamap fails to load, true otherwise + // load the default set of alphamaps. + // return a negative error code if anything along the way fails. + // called via delay-load mechanism. int LoadAlphaMaps(); - void UnloadAlphaMaps(); + // load textures for the active water type. + // return a negative error code if anything along the way fails. + // called via delay-load mechanism. + int LoadWaterTextures(); + void UnloadWaterTextures(); + // return stats accumulated for current frame const Stats& GetStats() { return m_Stats; } diff --git a/source/renderer/VertexArray.cpp b/source/renderer/VertexArray.cpp index 76291dbda9..2f1208a6a0 100644 --- a/source/renderer/VertexArray.cpp +++ b/source/renderer/VertexArray.cpp @@ -151,13 +151,19 @@ void VertexArray::Layout() continue; size_t attrSize = 0; - - switch(attr->type) { - case GL_UNSIGNED_BYTE: attrSize = sizeof(GLubyte); break; - case GL_FLOAT: attrSize = sizeof(GLfloat); break; - default: debug_warn("Bad AttributeInfo::Type"); break; + switch(attr->type) + { + case GL_UNSIGNED_BYTE: + attrSize = sizeof(GLubyte); + break; + case GL_FLOAT: + attrSize = sizeof(GLfloat); + break; + default: + attrSize = 0; + debug_warn("Bad AttributeInfo::Type"); break; } - + attrSize *= attr->elems; attr->offset = m_Stride;