Ticket #1429: bumpy4.diff
File bumpy4.diff, 177.7 KB (added by , 12 years ago) |
---|
-
source/ps/Game.cpp
283 283 g_GUI->SendEventToAll("SimulationUpdate"); 284 284 } 285 285 286 GetView()->GetLOSTexture().MakeDirty(); 286 //GetView()->GetLOSTexture().MakeDirty(); 287 GetView()->GetLOSTexture().MakeDirty(); 288 //GetScene().GetLOSTexture().InterpolateLOS(); 287 289 } 290 291 GetView()->GetLOSTexture().m_LosTexTimer = deltaSimTime; 288 292 } 289 293 290 294 if (doInterpolate) -
source/graphics/Material.h
38 38 39 39 void SetDiffuseTexture(const CTexturePtr& texture); 40 40 const CTexturePtr& GetDiffuseTexture() const { return m_DiffuseTexture; } 41 42 void SetNormalTexture(const CTexturePtr& texture); 43 const CTexturePtr& GetNormalTexture() const { return m_NormalTexture; } 44 45 void SetSpecularTexture(const CTexturePtr& texture); 46 const CTexturePtr& GetSpecularTexture() const { return m_SpecularTexture; } 41 47 42 48 void SetShaderEffect(const CStr& effect); 43 49 CStrIntern GetShaderEffect() const { return m_ShaderEffect; } … … 50 56 51 57 private: 52 58 CTexturePtr m_DiffuseTexture; 59 CTexturePtr m_NormalTexture; 60 CTexturePtr m_SpecularTexture; 53 61 CStrIntern m_ShaderEffect; 54 62 CShaderDefines m_ShaderDefines; 55 63 CShaderUniforms m_StaticUniforms; -
source/graphics/LOSTexture.cpp
20 20 #include "LOSTexture.h" 21 21 22 22 #include "graphics/Terrain.h" 23 #include "graphics/ShaderManager.h" 23 24 #include "lib/bits.h" 25 #include "ps/CLogger.h" 24 26 #include "ps/Game.h" 25 27 #include "ps/Profile.h" 26 28 #include "renderer/Renderer.h" … … 48 50 static const size_t g_BlurSize = 7; 49 51 50 52 CLOSTexture::CLOSTexture(CSimulation2& simulation) : 51 m_Simulation(simulation), m_Dirty(true), m_Texture(0), m_ MapSize(0), m_TextureSize(0)53 m_Simulation(simulation), m_Dirty(true), m_Texture(0), m_smoothFbo(0), m_MapSize(0), m_TextureSize(0), m_LosTexTimer(0.0), whichTex(true) 52 54 { 55 pglGenFramebuffersEXT(1, &m_smoothFbo); 56 m_smoothShader = g_Renderer.GetShaderManager().LoadEffect("los_interp"); 53 57 } 54 58 55 59 CLOSTexture::~CLOSTexture() … … 61 65 void CLOSTexture::DeleteTexture() 62 66 { 63 67 glDeleteTextures(1, &m_Texture); 64 m_Texture = 0; 68 glDeleteTextures(1, &m_TextureSmooth1); 69 glDeleteTextures(1, &m_TextureSmooth2); 70 m_Texture = 0; 65 71 } 66 72 67 73 void CLOSTexture::MakeDirty() … … 80 86 g_Renderer.BindTexture(unit, m_Texture); 81 87 } 82 88 89 GLuint CLOSTexture::GetTextureSmooth() 90 { 91 return whichTex ? m_TextureSmooth1 : m_TextureSmooth2; 92 } 93 94 void CLOSTexture::InterpolateLOS() 95 { 96 if (m_Dirty) 97 { 98 RecomputeTexture(0); 99 m_Dirty = false; 100 } 101 102 GLint originalFBO; 103 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &originalFBO); 104 105 //if (!m_smoothFbo) 106 107 108 //if (!m_smoothShader) 109 110 pglBindFramebufferEXT(GL_FRAMEBUFFER, m_smoothFbo); 111 pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 112 whichTex ? m_TextureSmooth2 : m_TextureSmooth1, 0); 113 114 GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); 115 if (status != GL_FRAMEBUFFER_COMPLETE_EXT) 116 { 117 LOGWARNING(L"Framebuffer object incomplete: 0x%04X", status); 118 } 119 120 121 /*glActiveTexture(GL_TEXTURE0); 122 glBindTexture(GL_TEXTURE_2D, m_Texture); 123 124 glBegin(GL_QUADS); 125 glColor4f(1.f, 1.f, 1.f, 0.5f); 126 glTexCoord2f(1.0, 1.0); glVertex2f(1,1); 127 glTexCoord2f(0.0, 1.0); glVertex2f(-1,1); 128 glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1); 129 glTexCoord2f(1.0, 0.0); glVertex2f(1,-1); 130 glEnd();*/ 131 132 m_smoothShader->BeginPass(); 133 CShaderProgramPtr shader = m_smoothShader->GetShader(); 134 135 shader->Bind(); 136 137 //shader->BindTexture("smoothTex", stencilTex); 138 shader->BindTexture("losTex1", m_Texture); 139 shader->BindTexture("losTex2", whichTex ? m_TextureSmooth1 : m_TextureSmooth2); 140 141 //std::cout << m_LosTexTimer * 1 << std::endl; 142 shader->Uniform("delta", CVector3D(m_LosTexTimer * 4, 0, 0)); 143 //m_LosTexTimer = 0; 144 145 glEnable(GL_BLEND); 146 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 147 148 glPushAttrib(GL_VIEWPORT_BIT); 149 glViewport(0, 0, m_TextureSize, m_TextureSize); 150 151 glBegin(GL_QUADS); 152 glColor4f(1.f, 1.f, 1.f, 1.f); 153 glTexCoord2f(1.0, 1.0); glVertex2f(1,1); 154 glTexCoord2f(0.0, 1.0); glVertex2f(-1,1); 155 glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1); 156 glTexCoord2f(1.0, 0.0); glVertex2f(1,-1); 157 glEnd(); 158 159 glPopAttrib(); 160 161 162 shader->Unbind(); 163 164 m_smoothShader->EndPass(); 165 166 pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); 167 168 169 //glDisable(GL_BLEND); 170 171 pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, originalFBO); 172 173 whichTex = !whichTex; 174 175 //return m_TextureSmooth; 176 } 177 178 83 179 GLuint CLOSTexture::GetTexture() 84 180 { 85 181 if (m_Dirty) … … 114 210 m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize + g_BlurSize - 1); 115 211 116 212 glGenTextures(1, &m_Texture); 117 g_Renderer.BindTexture(unit, m_Texture); 213 glGenTextures(1, &m_TextureSmooth1); 214 glGenTextures(1, &m_TextureSmooth2); 215 118 216 119 217 // Initialise texture with SoD colour, for the areas we don't 120 218 // overwrite with glTexSubImage2D later 121 219 u8* texData = new u8[m_TextureSize * m_TextureSize]; 122 220 memset(texData, 0x00, m_TextureSize * m_TextureSize); 221 222 g_Renderer.BindTexture(unit, m_TextureSmooth1); 123 223 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_TextureSize, m_TextureSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texData); 124 delete[] texData;125 126 224 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 127 225 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 128 226 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 129 227 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 228 229 g_Renderer.BindTexture(unit, m_TextureSmooth2); 230 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_TextureSize, m_TextureSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texData); 231 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 232 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 233 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 234 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 235 236 g_Renderer.BindTexture(unit, m_Texture); 237 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_TextureSize, m_TextureSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texData); 238 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 239 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 240 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 241 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 242 243 delete[] texData; 130 244 131 245 { 132 246 // Texture matrix: We want to map -
source/graphics/TerrainTextureManager.cpp
143 143 // multiple extensions. 144 144 if(!tex_is_known_extension(pathnames[i])) 145 145 continue; 146 147 // if this is a texture file, ensure that its basename does not 148 // end in "_norm" or "_spec", as those are not stand-alone texture maps 149 const Path base = pathnames[i].Basename(); 150 const size_t underscore = base.string().find_last_of('_'); 151 if(underscore != VfsPath::String::npos) 152 { 153 const Path p = base.string().substr(underscore); 154 if (p == L"_norm" || p == L"_spec") 155 continue; 156 } 146 157 147 158 VfsPath pathnameXML = pathnames[i].ChangeExtension(L".xml"); 148 159 CTerrainPropertiesPtr myprops; -
source/graphics/TerrainProperties.cpp
103 103 ATTR(movementclass); 104 104 ATTR(angle); 105 105 ATTR(size); 106 ATTR(normalmap); 107 ATTR(specularmap); 106 108 #undef ELMT 107 109 #undef ATTR 108 110 … … 154 156 { 155 157 m_MovementClass = attr.Value; 156 158 } 159 else if (attr.Name == attr_normalmap) 160 { 161 m_NormalMap = attr.Value; 162 } 163 else if (attr.Name == attr_specularmap) 164 { 165 m_SpecularMap = attr.Value; 166 } 157 167 } 158 168 } 159 169 -
source/graphics/ObjectEntry.h
47 47 CObjectBase* m_Base; 48 48 49 49 VfsPath m_TextureName; 50 VfsPath m_NormalName; 51 VfsPath m_SpecularName; 50 52 // model name 51 53 VfsPath m_ModelName; 52 54 // colour (used when doing alpha-channel colouring, but not doing player-colour) -
source/graphics/mikktspace.h
1 /** \file mikktspace/mikktspace.h 2 * \ingroup mikktspace 3 */ 4 /** 5 * Copyright (C) 2011 by Morten S. Mikkelsen 6 * 7 * This software is provided 'as-is', without any express or implied 8 * warranty. In no event will the authors be held liable for any damages 9 * arising from the use of this software. 10 * 11 * Permission is granted to anyone to use this software for any purpose, 12 * including commercial applications, and to alter it and redistribute it 13 * freely, subject to the following restrictions: 14 * 15 * 1. The origin of this software must not be misrepresented; you must not 16 * claim that you wrote the original software. If you use this software 17 * in a product, an acknowledgment in the product documentation would be 18 * appreciated but is not required. 19 * 2. Altered source versions must be plainly marked as such, and must not be 20 * misrepresented as being the original software. 21 * 3. This notice may not be removed or altered from any source distribution. 22 */ 23 24 #ifndef __MIKKTSPACE_H__ 25 #define __MIKKTSPACE_H__ 26 27 28 #ifdef __cplusplus 29 extern "C" { 30 #endif 31 32 /* Author: Morten S. Mikkelsen 33 * Version: 1.0 34 * 35 * The files mikktspace.h and mikktspace.c are designed to be 36 * stand-alone files and it is important that they are kept this way. 37 * Not having dependencies on structures/classes/libraries specific 38 * to the program, in which they are used, allows them to be copied 39 * and used as is into any tool, program or plugin. 40 * The code is designed to consistently generate the same 41 * tangent spaces, for a given mesh, in any tool in which it is used. 42 * This is done by performing an internal welding step and subsequently an order-independent evaluation 43 * of tangent space for meshes consisting of triangles and quads. 44 * This means faces can be received in any order and the same is true for 45 * the order of vertices of each face. The generated result will not be affected 46 * by such reordering. Additionally, whether degenerate (vertices or texture coordinates) 47 * primitives are present or not will not affect the generated results either. 48 * Once tangent space calculation is done the vertices of degenerate primitives will simply 49 * inherit tangent space from neighboring non degenerate primitives. 50 * The analysis behind this implementation can be found in my master's thesis 51 * which is available for download --> http://image.diku.dk/projects/media/morten.mikkelsen.08.pdf 52 * Note that though the tangent spaces at the vertices are generated in an order-independent way, 53 * by this implementation, the interpolated tangent space is still affected by which diagonal is 54 * chosen to split each quad. A sensible solution is to have your tools pipeline always 55 * split quads by the shortest diagonal. This choice is order-independent and works with mirroring. 56 * If these have the same length then compare the diagonals defined by the texture coordinates. 57 * XNormal which is a tool for baking normal maps allows you to write your own tangent space plugin 58 * and also quad triangulator plugin. 59 */ 60 61 62 typedef int tbool; 63 typedef struct SMikkTSpaceContext SMikkTSpaceContext; 64 65 typedef struct 66 { 67 // Returns the number of faces (triangles/quads) on the mesh to be processed. 68 int (*m_getNumFaces)(const SMikkTSpaceContext * pContext); 69 70 // Returns the number of vertices on face number iFace 71 // iFace is a number in the range {0, 1, ..., getNumFaces()-1} 72 int (*m_getNumVerticesOfFace)(const SMikkTSpaceContext * pContext, const int iFace); 73 74 // returns the position/normal/texcoord of the referenced face of vertex number iVert. 75 // iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads. 76 void (*m_getPosition)(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert); 77 void (*m_getNormal)(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert); 78 void (*m_getTexCoord)(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert); 79 80 // either (or both) of the two setTSpace callbacks can be set. 81 // The call-back m_setTSpaceBasic() is sufficient for basic normal mapping. 82 83 // This function is used to return the tangent and fSign to the application. 84 // fvTangent is a unit length vector. 85 // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. 86 // bitangent = fSign * cross(vN, tangent); 87 // Note that the results are returned unindexed. It is possible to generate a new index list 88 // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. 89 // DO NOT! use an already existing index list. 90 void (*m_setTSpaceBasic)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert); 91 92 // This function is used to return tangent space results to the application. 93 // fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are their 94 // true magnitudes which can be used for relief mapping effects. 95 // fvBiTangent is the "real" bitangent and thus may not be perpendicular to fvTangent. 96 // However, both are perpendicular to the vertex normal. 97 // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. 98 // fSign = bIsOrientationPreserving ? 1.0f : (-1.0f); 99 // bitangent = fSign * cross(vN, tangent); 100 // Note that the results are returned unindexed. It is possible to generate a new index list 101 // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. 102 // DO NOT! use an already existing index list. 103 void (*m_setTSpace)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT, 104 const tbool bIsOrientationPreserving, const int iFace, const int iVert); 105 } SMikkTSpaceInterface; 106 107 struct SMikkTSpaceContext 108 { 109 SMikkTSpaceInterface * m_pInterface; // initialized with callback functions 110 void * m_pUserData; // pointer to client side mesh data etc. (passed as the first parameter with every interface call) 111 }; 112 113 // these are both thread safe! 114 tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext); // Default (recommended) fAngularThreshold is 180 degrees (which means threshold disabled) 115 tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold); 116 117 118 // To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the 119 // normal map sampler must use the exact inverse of the pixel shader transformation. 120 // The most efficient transformation we can possibly do in the pixel shader is 121 // achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN. 122 // pixel shader (fast transform out) 123 // vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); 124 // where vNt is the tangent space normal. The normal map sampler must likewise use the 125 // interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader. 126 // sampler does (exact inverse of pixel shader): 127 // float3 row0 = cross(vB, vN); 128 // float3 row1 = cross(vN, vT); 129 // float3 row2 = cross(vT, vB); 130 // float fSign = dot(vT, row0)<0 ? -1 : 1; 131 // vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) ); 132 // where vNout is the sampled normal in some chosen 3D space. 133 // 134 // Should you choose to reconstruct the bitangent in the pixel shader instead 135 // of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also. 136 // Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of 137 // quads as your renderer then problems will occur since the interpolated tangent spaces will differ 138 // eventhough the vertex level tangent spaces match. This can be solved either by triangulating before 139 // sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier. 140 // However, this must be used both by the sampler and your tools/rendering pipeline. 141 142 #ifdef __cplusplus 143 } 144 #endif 145 146 #endif -
source/graphics/weldmesh.cpp
1 #include "precompiled.h" 2 3 /** 4 * Copyright (C) 2011 by Morten S. Mikkelsen 5 * 6 * This software is provided 'as-is', without any express or implied 7 * warranty. In no event will the authors be held liable for any damages 8 * arising from the use of this software. 9 * 10 * Permission is granted to anyone to use this software for any purpose, 11 * including commercial applications, and to alter it and redistribute it 12 * freely, subject to the following restrictions: 13 * 14 * 1. The origin of this software must not be misrepresented; you must not 15 * claim that you wrote the original software. If you use this software 16 * in a product, an acknowledgment in the product documentation would be 17 * appreciated but is not required. 18 * 2. Altered source versions must be plainly marked as such, and must not be 19 * misrepresented as being the original software. 20 * 3. This notice may not be removed or altered from any source distribution. 21 */ 22 23 24 #include "weldmesh.h" 25 #include <string.h> 26 #include <assert.h> 27 28 #ifdef __APPLE__ 29 #include <stdlib.h> /* OSX gets its malloc stuff through here */ 30 #else 31 #include <malloc.h> 32 #endif 33 34 static void MergeVertsFast(int * piCurNrUniqueVertices, int * piRemapTable, float * pfVertexDataOut, int * piVertexIDs, 35 const float pfVertexDataIn[], const int iNrVerticesIn, const int iFloatsPerVert, 36 const int iL_in, const int iR_in, const int iChannelNum); 37 38 int WeldMesh(int * piRemapTable, float * pfVertexDataOut, 39 const float pfVertexDataIn[], const int iNrVerticesIn, const int iFloatsPerVert) 40 { 41 int iUniqueVertices = 0, i=0; 42 int * piVertexIDs = NULL; 43 if(iNrVerticesIn<=0) return 0; 44 45 46 iUniqueVertices = 0; 47 piVertexIDs = (int *) malloc(sizeof(int)*iNrVerticesIn); 48 if(piVertexIDs!=NULL) 49 { 50 for(i=0; i<iNrVerticesIn; i++) 51 { 52 piRemapTable[i] = -1; 53 piVertexIDs[i] = i; 54 } 55 56 MergeVertsFast(&iUniqueVertices, piRemapTable, pfVertexDataOut, piVertexIDs, 57 pfVertexDataIn, iNrVerticesIn, iFloatsPerVert, 0, iNrVerticesIn-1, 0); 58 59 free(piVertexIDs); 60 61 // debug check 62 for(i=0; i<iUniqueVertices; i++) 63 assert(piRemapTable[i]>=0); 64 } 65 66 return iUniqueVertices; 67 } 68 69 70 71 72 73 static void MergeVertsFast(int * piCurNrUniqueVertices, int * piRemapTable, float * pfVertexDataOut, int * piVertexIDs, 74 const float pfVertexDataIn[], const int iNrVerticesIn, const int iFloatsPerVert, 75 const int iL_in, const int iR_in, const int iChannelNum) 76 { 77 const int iCount = iR_in-iL_in+1; 78 int l=0; 79 float fMin, fMax, fAvg; 80 assert(iCount>0); 81 // make bbox 82 fMin = pfVertexDataIn[ piVertexIDs[iL_in]*iFloatsPerVert + iChannelNum]; fMax = fMin; 83 for(l=(iL_in+1); l<=iR_in; l++) 84 { 85 const int index = piVertexIDs[l]*iFloatsPerVert + iChannelNum; 86 const float fVal = pfVertexDataIn[index]; 87 if(fMin>fVal) fMin=fVal; 88 else if(fMax<fVal) fMax=fVal; 89 } 90 91 // terminate recursion when the separation/average value 92 // is no longer strictly between fMin and fMax values. 93 fAvg = 0.5f*(fMax + fMin); 94 if(fAvg<=fMin || fAvg>=fMax || iCount==1) 95 { 96 if((iChannelNum+1) == iFloatsPerVert || iCount==1) // we are done, weld by hand 97 { 98 int iUniqueNewVertices = 0; 99 float * pfNewUniVertsOut = &pfVertexDataOut[ piCurNrUniqueVertices[0]*iFloatsPerVert ]; 100 101 for(l=iL_in; l<=iR_in; l++) 102 { 103 const int index = piVertexIDs[l]*iFloatsPerVert; 104 105 int iFound = 0; // didn't find copy yet. 106 int l2=0; 107 while(l2<iUniqueNewVertices && iFound==0) 108 { 109 const int index2 = l2*iFloatsPerVert; 110 111 int iAllSame = 1; 112 int c=0; 113 while(iAllSame!=0 && c<iFloatsPerVert) 114 { 115 iAllSame &= (pfVertexDataIn[index+c] == pfNewUniVertsOut[index2+c] ? 1 : 0); 116 ++c; 117 } 118 119 iFound = iAllSame; 120 if(iFound==0) ++l2; 121 } 122 123 // generate new entry 124 if(iFound==0) 125 { 126 memcpy(pfNewUniVertsOut+iUniqueNewVertices*iFloatsPerVert, pfVertexDataIn+index, sizeof(float)*iFloatsPerVert); 127 ++iUniqueNewVertices; 128 } 129 130 assert(piRemapTable[piVertexIDs[l]] == -1); // has not yet been assigned 131 piRemapTable[piVertexIDs[l]] = piCurNrUniqueVertices[0] + l2; 132 } 133 134 piCurNrUniqueVertices[0] += iUniqueNewVertices; 135 } 136 else 137 { 138 MergeVertsFast(piCurNrUniqueVertices, piRemapTable, pfVertexDataOut, piVertexIDs, 139 pfVertexDataIn, iNrVerticesIn, iFloatsPerVert, 140 iL_in, iR_in, iChannelNum+1); 141 } 142 } 143 else 144 { 145 int iL=iL_in, iR=iR_in, index; 146 147 // seperate (by fSep) all points between iL_in and iR_in in pTmpVert[] 148 while(iL < iR) 149 { 150 int iReadyLeftSwap = 0; 151 int iReadyRightSwap = 0; 152 while(iReadyLeftSwap==0 && iL<iR) 153 { 154 assert(iL>=iL_in && iL<=iR_in); 155 index = piVertexIDs[iL]*iFloatsPerVert+iChannelNum; 156 iReadyLeftSwap = !(pfVertexDataIn[index]<fAvg) ? 1 : 0; 157 if(iReadyLeftSwap==0) ++iL; 158 } 159 while(iReadyRightSwap==0 && iL<iR) 160 { 161 assert(iR>=iL_in && iR<=iR_in); 162 index = piVertexIDs[iR]*iFloatsPerVert+iChannelNum; 163 iReadyRightSwap = pfVertexDataIn[index]<fAvg ? 1 : 0; 164 if(iReadyRightSwap==0) --iR; 165 } 166 assert( (iL<iR) || (iReadyLeftSwap==0 || iReadyRightSwap==0)); 167 168 if(iReadyLeftSwap!=0 && iReadyRightSwap!=0) 169 { 170 int iID=0; 171 assert(iL<iR); 172 iID = piVertexIDs[iL]; 173 piVertexIDs[iL] = piVertexIDs[iR]; 174 piVertexIDs[iR] = iID; 175 ++iL; --iR; 176 } 177 } 178 179 assert(iL==(iR+1) || (iL==iR)); 180 if(iL==iR) 181 { 182 const int index = piVertexIDs[iR]*iFloatsPerVert+iChannelNum; 183 const int iReadyRightSwap = pfVertexDataIn[index]<fAvg ? 1 : 0; 184 if(iReadyRightSwap!=0) ++iL; 185 else --iR; 186 } 187 188 // recurse 189 if(iL_in <= iR) 190 MergeVertsFast(piCurNrUniqueVertices, piRemapTable, pfVertexDataOut, piVertexIDs, 191 pfVertexDataIn, iNrVerticesIn, iFloatsPerVert, iL_in, iR, iChannelNum); // weld all left of fSep 192 if(iL <= iR_in) 193 MergeVertsFast(piCurNrUniqueVertices, piRemapTable, pfVertexDataOut, piVertexIDs, 194 pfVertexDataIn, iNrVerticesIn, iFloatsPerVert, iL, iR_in, iChannelNum); // weld all right of (or equal to) fSep 195 } 196 } 197 No newline at end of file -
source/graphics/TerrainTextureEntry.h
47 47 CTerrainPropertiesPtr m_pProperties; 48 48 49 49 CTexturePtr m_Texture; 50 CTexturePtr m_Normal; 51 CTexturePtr m_Specular; 50 52 51 53 CMatrix3D m_TextureMatrix; 52 54 … … 79 81 return m_Texture; 80 82 } 81 83 84 const CTexturePtr& GetNormal() { 85 return m_Normal; 86 } 87 88 const CTexturePtr& GetSpecular() { 89 return m_Specular; 90 } 91 82 92 // Returns a matrix of the form [c 0 -s 0; -s 0 -c 0; 0 0 0 0; 0 0 0 1] 83 93 // mapping world-space (x,y,z,1) coordinates onto (u,v,0,1) texcoords 84 94 const float* GetTextureMatrix(); -
source/graphics/LOSTexture.h
18 18 #include "lib/ogl.h" 19 19 20 20 #include "maths/Matrix3D.h" 21 22 #include "graphics/ShaderManager.h" 23 21 24 #include "simulation2/components/ICmpRangeManager.h" 22 25 23 26 class CSimulation2; … … 55 58 * The texture is in 8-bit ALPHA format. 56 59 */ 57 60 GLuint GetTexture(); 61 62 void InterpolateLOS(); 63 GLuint GetTextureSmooth(); 58 64 59 65 /** 60 66 * Returns a matrix to map (x,y,z) world coordinates onto (u,v) LOS texture … … 69 75 * This must only be called after BindTexture. 70 76 */ 71 77 const float* GetMinimapTextureMatrix(); 78 79 double m_LosTexTimer; 72 80 73 81 private: 74 82 void DeleteTexture(); … … 83 91 bool m_Dirty; 84 92 85 93 GLuint m_Texture; 94 GLuint m_TextureSmooth1, m_TextureSmooth2; 95 96 bool whichTex; 97 98 GLuint m_smoothFbo; 99 CShaderTechniquePtr m_smoothShader; 86 100 87 101 ssize_t m_MapSize; // vertexes per side 88 102 GLsizei m_TextureSize; // texels per side -
source/graphics/mikktspace.cpp
1 #include "precompiled.h" 2 3 /** \file mikktspace/mikktspace.c 4 * \ingroup mikktspace 5 */ 6 /** 7 * Copyright (C) 2011 by Morten S. Mikkelsen 8 * 9 * This software is provided 'as-is', without any express or implied 10 * warranty. In no event will the authors be held liable for any damages 11 * arising from the use of this software. 12 * 13 * Permission is granted to anyone to use this software for any purpose, 14 * including commercial applications, and to alter it and redistribute it 15 * freely, subject to the following restrictions: 16 * 17 * 1. The origin of this software must not be misrepresented; you must not 18 * claim that you wrote the original software. If you use this software 19 * in a product, an acknowledgment in the product documentation would be 20 * appreciated but is not required. 21 * 2. Altered source versions must be plainly marked as such, and must not be 22 * misrepresented as being the original software. 23 * 3. This notice may not be removed or altered from any source distribution. 24 */ 25 26 #include <assert.h> 27 #include <stdio.h> 28 #include <math.h> 29 #include <string.h> 30 #include <float.h> 31 #include <stdlib.h> 32 33 #include "mikktspace.h" 34 35 #define TFALSE 0 36 #define TTRUE 1 37 38 #ifndef M_PI 39 #define M_PI 3.1415926535897932384626433832795 40 #endif 41 42 #define INTERNAL_RND_SORT_SEED 39871946 43 44 // internal structure 45 typedef struct 46 { 47 float x, y, z; 48 } SVec3; 49 50 static tbool veq( const SVec3 v1, const SVec3 v2 ) 51 { 52 return (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z); 53 } 54 55 static SVec3 vadd( const SVec3 v1, const SVec3 v2 ) 56 { 57 SVec3 vRes; 58 59 vRes.x = v1.x + v2.x; 60 vRes.y = v1.y + v2.y; 61 vRes.z = v1.z + v2.z; 62 63 return vRes; 64 } 65 66 67 static SVec3 vsub( const SVec3 v1, const SVec3 v2 ) 68 { 69 SVec3 vRes; 70 71 vRes.x = v1.x - v2.x; 72 vRes.y = v1.y - v2.y; 73 vRes.z = v1.z - v2.z; 74 75 return vRes; 76 } 77 78 static SVec3 vscale(const float fS, const SVec3 v) 79 { 80 SVec3 vRes; 81 82 vRes.x = fS * v.x; 83 vRes.y = fS * v.y; 84 vRes.z = fS * v.z; 85 86 return vRes; 87 } 88 89 static float LengthSquared( const SVec3 v ) 90 { 91 return v.x*v.x + v.y*v.y + v.z*v.z; 92 } 93 94 static float Length( const SVec3 v ) 95 { 96 return sqrtf(LengthSquared(v)); 97 } 98 99 static SVec3 Normalize( const SVec3 v ) 100 { 101 return vscale(1 / Length(v), v); 102 } 103 104 static float vdot( const SVec3 v1, const SVec3 v2) 105 { 106 return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; 107 } 108 109 110 static tbool NotZero(const float fX) 111 { 112 // could possibly use FLT_EPSILON instead 113 return fabsf(fX) > FLT_MIN; 114 } 115 116 static tbool VNotZero(const SVec3 v) 117 { 118 // might change this to an epsilon based test 119 return NotZero(v.x) || NotZero(v.y) || NotZero(v.z); 120 } 121 122 123 124 typedef struct 125 { 126 int iNrFaces; 127 int * pTriMembers; 128 } SSubGroup; 129 130 typedef struct 131 { 132 int iNrFaces; 133 int * pFaceIndices; 134 int iVertexRepresentitive; 135 tbool bOrientPreservering; 136 } SGroup; 137 138 // 139 #define MARK_DEGENERATE 1 140 #define QUAD_ONE_DEGEN_TRI 2 141 #define GROUP_WITH_ANY 4 142 #define ORIENT_PRESERVING 8 143 144 145 146 typedef struct 147 { 148 int FaceNeighbors[3]; 149 SGroup * AssignedGroup[3]; 150 151 // normalized first order face derivatives 152 SVec3 vOs, vOt; 153 float fMagS, fMagT; // original magnitudes 154 155 // determines if the current and the next triangle are a quad. 156 int iOrgFaceNumber; 157 int iFlag, iTSpacesOffs; 158 unsigned char vert_num[4]; 159 } STriInfo; 160 161 typedef struct 162 { 163 SVec3 vOs; 164 float fMagS; 165 SVec3 vOt; 166 float fMagT; 167 int iCounter; // this is to average back into quads. 168 tbool bOrient; 169 } STSpace; 170 171 static int GenerateInitialVerticesIndexList(STriInfo pTriInfos[], int piTriList_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); 172 static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); 173 static void InitTriInfo(STriInfo pTriInfos[], const int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); 174 static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupTrianglesBuffer[], const int piTriListIn[], const int iNrTrianglesIn); 175 static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], const SGroup pGroups[], 176 const int iNrActiveGroups, const int piTriListIn[], const float fThresCos, 177 const SMikkTSpaceContext * pContext); 178 179 static int MakeIndex(const int iFace, const int iVert) 180 { 181 assert(iVert>=0 && iVert<4 && iFace>=0); 182 return (iFace<<2) | (iVert&0x3); 183 } 184 185 static void IndexToData(int * piFace, int * piVert, const int iIndexIn) 186 { 187 piVert[0] = iIndexIn&0x3; 188 piFace[0] = iIndexIn>>2; 189 } 190 191 static STSpace AvgTSpace(const STSpace * pTS0, const STSpace * pTS1) 192 { 193 STSpace ts_res; 194 195 // this if is important. Due to floating point precision 196 // averaging when ts0==ts1 will cause a slight difference 197 // which results in tangent space splits later on 198 if (pTS0->fMagS==pTS1->fMagS && pTS0->fMagT==pTS1->fMagT && 199 veq(pTS0->vOs,pTS1->vOs) && veq(pTS0->vOt, pTS1->vOt)) 200 { 201 ts_res.fMagS = pTS0->fMagS; 202 ts_res.fMagT = pTS0->fMagT; 203 ts_res.vOs = pTS0->vOs; 204 ts_res.vOt = pTS0->vOt; 205 } 206 else 207 { 208 ts_res.fMagS = 0.5f*(pTS0->fMagS+pTS1->fMagS); 209 ts_res.fMagT = 0.5f*(pTS0->fMagT+pTS1->fMagT); 210 ts_res.vOs = vadd(pTS0->vOs,pTS1->vOs); 211 ts_res.vOt = vadd(pTS0->vOt,pTS1->vOt); 212 if ( VNotZero(ts_res.vOs) ) ts_res.vOs = Normalize(ts_res.vOs); 213 if ( VNotZero(ts_res.vOt) ) ts_res.vOt = Normalize(ts_res.vOt); 214 } 215 216 return ts_res; 217 } 218 219 220 221 static SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index); 222 static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index); 223 static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index); 224 225 226 // degen triangles 227 static void DegenPrologue(STriInfo pTriInfos[], int piTriList_out[], const int iNrTrianglesIn, const int iTotTris); 228 static void DegenEpilogue(STSpace psTspace[], STriInfo pTriInfos[], int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn, const int iTotTris); 229 230 231 tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext) 232 { 233 return genTangSpace(pContext, 180.0f); 234 } 235 236 tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold) 237 { 238 // count nr_triangles 239 int * piTriListIn = NULL, * piGroupTrianglesBuffer = NULL; 240 STriInfo * pTriInfos = NULL; 241 SGroup * pGroups = NULL; 242 STSpace * psTspace = NULL; 243 int iNrTrianglesIn = 0, f=0, t=0, i=0; 244 int iNrTSPaces = 0, iTotTris = 0, iDegenTriangles = 0, iNrMaxGroups = 0; 245 int iNrActiveGroups = 0, index = 0; 246 const int iNrFaces = pContext->m_pInterface->m_getNumFaces(pContext); 247 tbool bRes = TFALSE; 248 const float fThresCos = (float) cos((fAngularThreshold*(float)M_PI)/180.0f); 249 250 // verify all call-backs have been set 251 if ( pContext->m_pInterface->m_getNumFaces==NULL || 252 pContext->m_pInterface->m_getNumVerticesOfFace==NULL || 253 pContext->m_pInterface->m_getPosition==NULL || 254 pContext->m_pInterface->m_getNormal==NULL || 255 pContext->m_pInterface->m_getTexCoord==NULL ) 256 return TFALSE; 257 258 // count triangles on supported faces 259 for (f=0; f<iNrFaces; f++) 260 { 261 const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f); 262 if (verts==3) ++iNrTrianglesIn; 263 else if(verts==4) iNrTrianglesIn += 2; 264 } 265 if (iNrTrianglesIn<=0) return TFALSE; 266 267 // allocate memory for an index list 268 piTriListIn = (int *) malloc(sizeof(int)*3*iNrTrianglesIn); 269 pTriInfos = (STriInfo *) malloc(sizeof(STriInfo)*iNrTrianglesIn); 270 if (piTriListIn==NULL || pTriInfos==NULL) 271 { 272 if (piTriListIn!=NULL) free(piTriListIn); 273 if (pTriInfos!=NULL) free(pTriInfos); 274 return TFALSE; 275 } 276 277 // make an initial triangle --> face index list 278 iNrTSPaces = GenerateInitialVerticesIndexList(pTriInfos, piTriListIn, pContext, iNrTrianglesIn); 279 280 // make a welded index list of identical positions and attributes (pos, norm, texc) 281 //printf("gen welded index list begin\n"); 282 GenerateSharedVerticesIndexList(piTriListIn, pContext, iNrTrianglesIn); 283 //printf("gen welded index list end\n"); 284 285 // Mark all degenerate triangles 286 iTotTris = iNrTrianglesIn; 287 iDegenTriangles = 0; 288 for (t=0; t<iTotTris; t++) 289 { 290 const int i0 = piTriListIn[t*3+0]; 291 const int i1 = piTriListIn[t*3+1]; 292 const int i2 = piTriListIn[t*3+2]; 293 const SVec3 p0 = GetPosition(pContext, i0); 294 const SVec3 p1 = GetPosition(pContext, i1); 295 const SVec3 p2 = GetPosition(pContext, i2); 296 if (veq(p0,p1) || veq(p0,p2) || veq(p1,p2)) // degenerate 297 { 298 pTriInfos[t].iFlag |= MARK_DEGENERATE; 299 ++iDegenTriangles; 300 } 301 } 302 iNrTrianglesIn = iTotTris - iDegenTriangles; 303 304 // mark all triangle pairs that belong to a quad with only one 305 // good triangle. These need special treatment in DegenEpilogue(). 306 // Additionally, move all good triangles to the start of 307 // pTriInfos[] and piTriListIn[] without changing order and 308 // put the degenerate triangles last. 309 DegenPrologue(pTriInfos, piTriListIn, iNrTrianglesIn, iTotTris); 310 311 312 // evaluate triangle level attributes and neighbor list 313 //printf("gen neighbors list begin\n"); 314 InitTriInfo(pTriInfos, piTriListIn, pContext, iNrTrianglesIn); 315 //printf("gen neighbors list end\n"); 316 317 318 // based on the 4 rules, identify groups based on connectivity 319 iNrMaxGroups = iNrTrianglesIn*3; 320 pGroups = (SGroup *) malloc(sizeof(SGroup)*iNrMaxGroups); 321 piGroupTrianglesBuffer = (int *) malloc(sizeof(int)*iNrTrianglesIn*3); 322 if (pGroups==NULL || piGroupTrianglesBuffer==NULL) 323 { 324 if (pGroups!=NULL) free(pGroups); 325 if (piGroupTrianglesBuffer!=NULL) free(piGroupTrianglesBuffer); 326 free(piTriListIn); 327 free(pTriInfos); 328 return TFALSE; 329 } 330 //printf("gen 4rule groups begin\n"); 331 iNrActiveGroups = 332 Build4RuleGroups(pTriInfos, pGroups, piGroupTrianglesBuffer, piTriListIn, iNrTrianglesIn); 333 //printf("gen 4rule groups end\n"); 334 335 // 336 337 psTspace = (STSpace *) malloc(sizeof(STSpace)*iNrTSPaces); 338 if (psTspace==NULL) 339 { 340 free(piTriListIn); 341 free(pTriInfos); 342 free(pGroups); 343 free(piGroupTrianglesBuffer); 344 return TFALSE; 345 } 346 memset(psTspace, 0, sizeof(STSpace)*iNrTSPaces); 347 for (t=0; t<iNrTSPaces; t++) 348 { 349 psTspace[t].vOs.x=1.0f; psTspace[t].vOs.y=0.0f; psTspace[t].vOs.z=0.0f; psTspace[t].fMagS = 1.0f; 350 psTspace[t].vOt.x=0.0f; psTspace[t].vOt.y=1.0f; psTspace[t].vOt.z=0.0f; psTspace[t].fMagT = 1.0f; 351 } 352 353 // make tspaces, each group is split up into subgroups if necessary 354 // based on fAngularThreshold. Finally a tangent space is made for 355 // every resulting subgroup 356 //printf("gen tspaces begin\n"); 357 bRes = GenerateTSpaces(psTspace, pTriInfos, pGroups, iNrActiveGroups, piTriListIn, fThresCos, pContext); 358 //printf("gen tspaces end\n"); 359 360 // clean up 361 free(pGroups); 362 free(piGroupTrianglesBuffer); 363 364 if (!bRes) // if an allocation in GenerateTSpaces() failed 365 { 366 // clean up and return false 367 free(pTriInfos); free(piTriListIn); free(psTspace); 368 return TFALSE; 369 } 370 371 372 // degenerate quads with one good triangle will be fixed by copying a space from 373 // the good triangle to the coinciding vertex. 374 // all other degenerate triangles will just copy a space from any good triangle 375 // with the same welded index in piTriListIn[]. 376 DegenEpilogue(psTspace, pTriInfos, piTriListIn, pContext, iNrTrianglesIn, iTotTris); 377 378 free(pTriInfos); free(piTriListIn); 379 380 index = 0; 381 for (f=0; f<iNrFaces; f++) 382 { 383 const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f); 384 if (verts!=3 && verts!=4) continue; 385 386 387 // I've decided to let degenerate triangles and group-with-anythings 388 // vary between left/right hand coordinate systems at the vertices. 389 // All healthy triangles on the other hand are built to always be either or. 390 391 /*// force the coordinate system orientation to be uniform for every face. 392 // (this is already the case for good triangles but not for 393 // degenerate ones and those with bGroupWithAnything==true) 394 bool bOrient = psTspace[index].bOrient; 395 if (psTspace[index].iCounter == 0) // tspace was not derived from a group 396 { 397 // look for a space created in GenerateTSpaces() by iCounter>0 398 bool bNotFound = true; 399 int i=1; 400 while (i<verts && bNotFound) 401 { 402 if (psTspace[index+i].iCounter > 0) bNotFound=false; 403 else ++i; 404 } 405 if (!bNotFound) bOrient = psTspace[index+i].bOrient; 406 }*/ 407 408 // set data 409 for (i=0; i<verts; i++) 410 { 411 const STSpace * pTSpace = &psTspace[index]; 412 float tang[] = {pTSpace->vOs.x, pTSpace->vOs.y, pTSpace->vOs.z}; 413 float bitang[] = {pTSpace->vOt.x, pTSpace->vOt.y, pTSpace->vOt.z}; 414 if (pContext->m_pInterface->m_setTSpace!=NULL) 415 pContext->m_pInterface->m_setTSpace(pContext, tang, bitang, pTSpace->fMagS, pTSpace->fMagT, pTSpace->bOrient, f, i); 416 if (pContext->m_pInterface->m_setTSpaceBasic!=NULL) 417 pContext->m_pInterface->m_setTSpaceBasic(pContext, tang, pTSpace->bOrient==TTRUE ? 1.0f : (-1.0f), f, i); 418 419 ++index; 420 } 421 } 422 423 free(psTspace); 424 425 426 return TTRUE; 427 } 428 429 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 430 431 typedef struct 432 { 433 float vert[3]; 434 int index; 435 } STmpVert; 436 437 const int g_iCells = 2048; 438 439 #ifdef _MSC_VER 440 #define NOINLINE __declspec(noinline) 441 #else 442 #define NOINLINE __attribute__ ((noinline)) 443 #endif 444 445 // it is IMPORTANT that this function is called to evaluate the hash since 446 // inlining could potentially reorder instructions and generate different 447 // results for the same effective input value fVal. 448 NOINLINE int FindGridCell(const float fMin, const float fMax, const float fVal) 449 { 450 const float fIndex = g_iCells * ((fVal-fMin)/(fMax-fMin)); 451 const int iIndex = fIndex<0?0:((int)fIndex); 452 return iIndex<g_iCells?iIndex:(g_iCells-1); 453 } 454 455 static void MergeVertsFast(int piTriList_in_and_out[], STmpVert pTmpVert[], const SMikkTSpaceContext * pContext, const int iL_in, const int iR_in); 456 static void MergeVertsSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int pTable[], const int iEntries); 457 static void GenerateSharedVerticesIndexListSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); 458 459 static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn) 460 { 461 462 // Generate bounding box 463 int * piHashTable=NULL, * piHashCount=NULL, * piHashOffsets=NULL, * piHashCount2=NULL; 464 STmpVert * pTmpVert = NULL; 465 int i=0, iChannel=0, k=0, e=0; 466 int iMaxCount=0; 467 SVec3 vMin = GetPosition(pContext, 0), vMax = vMin, vDim; 468 float fMin, fMax; 469 for (i=1; i<(iNrTrianglesIn*3); i++) 470 { 471 const int index = piTriList_in_and_out[i]; 472 473 const SVec3 vP = GetPosition(pContext, index); 474 if (vMin.x > vP.x) vMin.x = vP.x; 475 else if(vMax.x < vP.x) vMax.x = vP.x; 476 if (vMin.y > vP.y) vMin.y = vP.y; 477 else if(vMax.y < vP.y) vMax.y = vP.y; 478 if (vMin.z > vP.z) vMin.z = vP.z; 479 else if(vMax.z < vP.z) vMax.z = vP.z; 480 } 481 482 vDim = vsub(vMax,vMin); 483 iChannel = 0; 484 fMin = vMin.x; fMax=vMax.x; 485 if (vDim.y>vDim.x && vDim.y>vDim.z) 486 { 487 iChannel=1; 488 fMin = vMin.y, fMax=vMax.y; 489 } 490 else if(vDim.z>vDim.x) 491 { 492 iChannel=2; 493 fMin = vMin.z, fMax=vMax.z; 494 } 495 496 // make allocations 497 piHashTable = (int *) malloc(sizeof(int)*iNrTrianglesIn*3); 498 piHashCount = (int *) malloc(sizeof(int)*g_iCells); 499 piHashOffsets = (int *) malloc(sizeof(int)*g_iCells); 500 piHashCount2 = (int *) malloc(sizeof(int)*g_iCells); 501 502 if (piHashTable==NULL || piHashCount==NULL || piHashOffsets==NULL || piHashCount2==NULL) 503 { 504 if (piHashTable!=NULL) free(piHashTable); 505 if (piHashCount!=NULL) free(piHashCount); 506 if (piHashOffsets!=NULL) free(piHashOffsets); 507 if (piHashCount2!=NULL) free(piHashCount2); 508 GenerateSharedVerticesIndexListSlow(piTriList_in_and_out, pContext, iNrTrianglesIn); 509 return; 510 } 511 memset(piHashCount, 0, sizeof(int)*g_iCells); 512 memset(piHashCount2, 0, sizeof(int)*g_iCells); 513 514 // count amount of elements in each cell unit 515 for (i=0; i<(iNrTrianglesIn*3); i++) 516 { 517 const int index = piTriList_in_and_out[i]; 518 const SVec3 vP = GetPosition(pContext, index); 519 const float fVal = iChannel==0 ? vP.x : (iChannel==1 ? vP.y : vP.z); 520 const int iCell = FindGridCell(fMin, fMax, fVal); 521 ++piHashCount[iCell]; 522 } 523 524 // evaluate start index of each cell. 525 piHashOffsets[0]=0; 526 for (k=1; k<g_iCells; k++) 527 piHashOffsets[k]=piHashOffsets[k-1]+piHashCount[k-1]; 528 529 // insert vertices 530 for (i=0; i<(iNrTrianglesIn*3); i++) 531 { 532 const int index = piTriList_in_and_out[i]; 533 const SVec3 vP = GetPosition(pContext, index); 534 const float fVal = iChannel==0 ? vP.x : (iChannel==1 ? vP.y : vP.z); 535 const int iCell = FindGridCell(fMin, fMax, fVal); 536 int * pTable = NULL; 537 538 assert(piHashCount2[iCell]<piHashCount[iCell]); 539 pTable = &piHashTable[piHashOffsets[iCell]]; 540 pTable[piHashCount2[iCell]] = i; // vertex i has been inserted. 541 ++piHashCount2[iCell]; 542 } 543 for (k=0; k<g_iCells; k++) 544 assert(piHashCount2[k] == piHashCount[k]); // verify the count 545 free(piHashCount2); 546 547 // find maximum amount of entries in any hash entry 548 iMaxCount = piHashCount[0]; 549 for (k=1; k<g_iCells; k++) 550 if (iMaxCount<piHashCount[k]) 551 iMaxCount=piHashCount[k]; 552 pTmpVert = (STmpVert *) malloc(sizeof(STmpVert)*iMaxCount); 553 554 555 // complete the merge 556 for (k=0; k<g_iCells; k++) 557 { 558 // extract table of cell k and amount of entries in it 559 int * pTable = &piHashTable[piHashOffsets[k]]; 560 const int iEntries = piHashCount[k]; 561 if (iEntries < 2) continue; 562 563 if (pTmpVert!=NULL) 564 { 565 for (e=0; e<iEntries; e++) 566 { 567 int i = pTable[e]; 568 const SVec3 vP = GetPosition(pContext, piTriList_in_and_out[i]); 569 pTmpVert[e].vert[0] = vP.x; pTmpVert[e].vert[1] = vP.y; 570 pTmpVert[e].vert[2] = vP.z; pTmpVert[e].index = i; 571 } 572 MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, 0, iEntries-1); 573 } 574 else 575 MergeVertsSlow(piTriList_in_and_out, pContext, pTable, iEntries); 576 } 577 578 if (pTmpVert!=NULL) { free(pTmpVert); } 579 free(piHashTable); 580 free(piHashCount); 581 free(piHashOffsets); 582 } 583 584 static void MergeVertsFast(int piTriList_in_and_out[], STmpVert pTmpVert[], const SMikkTSpaceContext * pContext, const int iL_in, const int iR_in) 585 { 586 // make bbox 587 int c=0, l=0, channel=0; 588 float fvMin[3], fvMax[3]; 589 float dx=0, dy=0, dz=0, fSep=0; 590 for (c=0; c<3; c++) 591 { fvMin[c]=pTmpVert[iL_in].vert[c]; fvMax[c]=fvMin[c]; } 592 for (l=(iL_in+1); l<=iR_in; l++) 593 for (c=0; c<3; c++) 594 if (fvMin[c]>pTmpVert[l].vert[c]) fvMin[c]=pTmpVert[l].vert[c]; 595 else if(fvMax[c]<pTmpVert[l].vert[c]) fvMax[c]=pTmpVert[l].vert[c]; 596 597 dx = fvMax[0]-fvMin[0]; 598 dy = fvMax[1]-fvMin[1]; 599 dz = fvMax[2]-fvMin[2]; 600 601 channel = 0; 602 if (dy>dx && dy>dz) channel=1; 603 else if(dz>dx) channel=2; 604 605 fSep = 0.5f*(fvMax[channel]+fvMin[channel]); 606 607 // terminate recursion when the separation/average value 608 // is no longer strictly between fMin and fMax values. 609 if (fSep>=fvMax[channel] || fSep<=fvMin[channel]) 610 { 611 // complete the weld 612 for (l=iL_in; l<=iR_in; l++) 613 { 614 int i = pTmpVert[l].index; 615 const int index = piTriList_in_and_out[i]; 616 const SVec3 vP = GetPosition(pContext, index); 617 const SVec3 vN = GetNormal(pContext, index); 618 const SVec3 vT = GetTexCoord(pContext, index); 619 620 tbool bNotFound = TTRUE; 621 int l2=iL_in, i2rec=-1; 622 while (l2<l && bNotFound) 623 { 624 const int i2 = pTmpVert[l2].index; 625 const int index2 = piTriList_in_and_out[i2]; 626 const SVec3 vP2 = GetPosition(pContext, index2); 627 const SVec3 vN2 = GetNormal(pContext, index2); 628 const SVec3 vT2 = GetTexCoord(pContext, index2); 629 i2rec=i2; 630 631 //if(vP==vP2 && vN==vN2 && vT==vT2) 632 if (vP.x==vP2.x && vP.y==vP2.y && vP.z==vP2.z && 633 vN.x==vN2.x && vN.y==vN2.y && vN.z==vN2.z && 634 vT.x==vT2.x && vT.y==vT2.y && vT.z==vT2.z) 635 bNotFound = TFALSE; 636 else 637 ++l2; 638 } 639 640 // merge if previously found 641 if (!bNotFound) 642 piTriList_in_and_out[i] = piTriList_in_and_out[i2rec]; 643 } 644 } 645 else 646 { 647 int iL=iL_in, iR=iR_in; 648 assert((iR_in-iL_in)>0); // at least 2 entries 649 650 // separate (by fSep) all points between iL_in and iR_in in pTmpVert[] 651 while (iL < iR) 652 { 653 tbool bReadyLeftSwap = TFALSE, bReadyRightSwap = TFALSE; 654 while ((!bReadyLeftSwap) && iL<iR) 655 { 656 assert(iL>=iL_in && iL<=iR_in); 657 bReadyLeftSwap = !(pTmpVert[iL].vert[channel]<fSep); 658 if (!bReadyLeftSwap) ++iL; 659 } 660 while ((!bReadyRightSwap) && iL<iR) 661 { 662 assert(iR>=iL_in && iR<=iR_in); 663 bReadyRightSwap = pTmpVert[iR].vert[channel]<fSep; 664 if (!bReadyRightSwap) --iR; 665 } 666 assert( (iL<iR) || !(bReadyLeftSwap && bReadyRightSwap) ); 667 668 if (bReadyLeftSwap && bReadyRightSwap) 669 { 670 const STmpVert sTmp = pTmpVert[iL]; 671 assert(iL<iR); 672 pTmpVert[iL] = pTmpVert[iR]; 673 pTmpVert[iR] = sTmp; 674 ++iL; --iR; 675 } 676 } 677 678 assert(iL==(iR+1) || (iL==iR)); 679 if (iL==iR) 680 { 681 const tbool bReadyRightSwap = pTmpVert[iR].vert[channel]<fSep; 682 if (bReadyRightSwap) ++iL; 683 else --iR; 684 } 685 686 // only need to weld when there is more than 1 instance of the (x,y,z) 687 if (iL_in < iR) 688 MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, iL_in, iR); // weld all left of fSep 689 if (iL < iR_in) 690 MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, iL, iR_in); // weld all right of (or equal to) fSep 691 } 692 } 693 694 static void MergeVertsSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int pTable[], const int iEntries) 695 { 696 // this can be optimized further using a tree structure or more hashing. 697 int e=0; 698 for (e=0; e<iEntries; e++) 699 { 700 int i = pTable[e]; 701 const int index = piTriList_in_and_out[i]; 702 const SVec3 vP = GetPosition(pContext, index); 703 const SVec3 vN = GetNormal(pContext, index); 704 const SVec3 vT = GetTexCoord(pContext, index); 705 706 tbool bNotFound = TTRUE; 707 int e2=0, i2rec=-1; 708 while (e2<e && bNotFound) 709 { 710 const int i2 = pTable[e2]; 711 const int index2 = piTriList_in_and_out[i2]; 712 const SVec3 vP2 = GetPosition(pContext, index2); 713 const SVec3 vN2 = GetNormal(pContext, index2); 714 const SVec3 vT2 = GetTexCoord(pContext, index2); 715 i2rec = i2; 716 717 if (veq(vP,vP2) && veq(vN,vN2) && veq(vT,vT2)) 718 bNotFound = TFALSE; 719 else 720 ++e2; 721 } 722 723 // merge if previously found 724 if (!bNotFound) 725 piTriList_in_and_out[i] = piTriList_in_and_out[i2rec]; 726 } 727 } 728 729 static void GenerateSharedVerticesIndexListSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn) 730 { 731 int iNumUniqueVerts = 0, t=0, i=0; 732 for (t=0; t<iNrTrianglesIn; t++) 733 { 734 for (i=0; i<3; i++) 735 { 736 const int offs = t*3 + i; 737 const int index = piTriList_in_and_out[offs]; 738 739 const SVec3 vP = GetPosition(pContext, index); 740 const SVec3 vN = GetNormal(pContext, index); 741 const SVec3 vT = GetTexCoord(pContext, index); 742 743 tbool bFound = TFALSE; 744 int t2=0, index2rec=-1; 745 while (!bFound && t2<=t) 746 { 747 int j=0; 748 while (!bFound && j<3) 749 { 750 const int index2 = piTriList_in_and_out[t2*3 + j]; 751 const SVec3 vP2 = GetPosition(pContext, index2); 752 const SVec3 vN2 = GetNormal(pContext, index2); 753 const SVec3 vT2 = GetTexCoord(pContext, index2); 754 755 if (veq(vP,vP2) && veq(vN,vN2) && veq(vT,vT2)) 756 bFound = TTRUE; 757 else 758 ++j; 759 } 760 if (!bFound) ++t2; 761 } 762 763 assert(bFound); 764 // if we found our own 765 if (index2rec == index) { ++iNumUniqueVerts; } 766 767 piTriList_in_and_out[offs] = index2rec; 768 } 769 } 770 } 771 772 static int GenerateInitialVerticesIndexList(STriInfo pTriInfos[], int piTriList_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn) 773 { 774 int iTSpacesOffs = 0, f=0, t=0; 775 int iDstTriIndex = 0; 776 for (f=0; f<pContext->m_pInterface->m_getNumFaces(pContext); f++) 777 { 778 const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f); 779 if (verts!=3 && verts!=4) continue; 780 781 pTriInfos[iDstTriIndex].iOrgFaceNumber = f; 782 pTriInfos[iDstTriIndex].iTSpacesOffs = iTSpacesOffs; 783 784 if (verts==3) 785 { 786 unsigned char * pVerts = pTriInfos[iDstTriIndex].vert_num; 787 pVerts[0]=0; pVerts[1]=1; pVerts[2]=2; 788 piTriList_out[iDstTriIndex*3+0] = MakeIndex(f, 0); 789 piTriList_out[iDstTriIndex*3+1] = MakeIndex(f, 1); 790 piTriList_out[iDstTriIndex*3+2] = MakeIndex(f, 2); 791 ++iDstTriIndex; // next 792 } 793 else 794 { 795 { 796 pTriInfos[iDstTriIndex+1].iOrgFaceNumber = f; 797 pTriInfos[iDstTriIndex+1].iTSpacesOffs = iTSpacesOffs; 798 } 799 800 { 801 // need an order independent way to evaluate 802 // tspace on quads. This is done by splitting 803 // along the shortest diagonal. 804 const int i0 = MakeIndex(f, 0); 805 const int i1 = MakeIndex(f, 1); 806 const int i2 = MakeIndex(f, 2); 807 const int i3 = MakeIndex(f, 3); 808 const SVec3 T0 = GetTexCoord(pContext, i0); 809 const SVec3 T1 = GetTexCoord(pContext, i1); 810 const SVec3 T2 = GetTexCoord(pContext, i2); 811 const SVec3 T3 = GetTexCoord(pContext, i3); 812 const float distSQ_02 = LengthSquared(vsub(T2,T0)); 813 const float distSQ_13 = LengthSquared(vsub(T3,T1)); 814 tbool bQuadDiagIs_02; 815 if (distSQ_02<distSQ_13) 816 bQuadDiagIs_02 = TTRUE; 817 else if(distSQ_13<distSQ_02) 818 bQuadDiagIs_02 = TFALSE; 819 else 820 { 821 const SVec3 P0 = GetPosition(pContext, i0); 822 const SVec3 P1 = GetPosition(pContext, i1); 823 const SVec3 P2 = GetPosition(pContext, i2); 824 const SVec3 P3 = GetPosition(pContext, i3); 825 const float distSQ_02 = LengthSquared(vsub(P2,P0)); 826 const float distSQ_13 = LengthSquared(vsub(P3,P1)); 827 828 bQuadDiagIs_02 = distSQ_13<distSQ_02 ? TFALSE : TTRUE; 829 } 830 831 if (bQuadDiagIs_02) 832 { 833 { 834 unsigned char * pVerts_A = pTriInfos[iDstTriIndex].vert_num; 835 pVerts_A[0]=0; pVerts_A[1]=1; pVerts_A[2]=2; 836 } 837 piTriList_out[iDstTriIndex*3+0] = i0; 838 piTriList_out[iDstTriIndex*3+1] = i1; 839 piTriList_out[iDstTriIndex*3+2] = i2; 840 ++iDstTriIndex; // next 841 { 842 unsigned char * pVerts_B = pTriInfos[iDstTriIndex].vert_num; 843 pVerts_B[0]=0; pVerts_B[1]=2; pVerts_B[2]=3; 844 } 845 piTriList_out[iDstTriIndex*3+0] = i0; 846 piTriList_out[iDstTriIndex*3+1] = i2; 847 piTriList_out[iDstTriIndex*3+2] = i3; 848 ++iDstTriIndex; // next 849 } 850 else 851 { 852 { 853 unsigned char * pVerts_A = pTriInfos[iDstTriIndex].vert_num; 854 pVerts_A[0]=0; pVerts_A[1]=1; pVerts_A[2]=3; 855 } 856 piTriList_out[iDstTriIndex*3+0] = i0; 857 piTriList_out[iDstTriIndex*3+1] = i1; 858 piTriList_out[iDstTriIndex*3+2] = i3; 859 ++iDstTriIndex; // next 860 { 861 unsigned char * pVerts_B = pTriInfos[iDstTriIndex].vert_num; 862 pVerts_B[0]=1; pVerts_B[1]=2; pVerts_B[2]=3; 863 } 864 piTriList_out[iDstTriIndex*3+0] = i1; 865 piTriList_out[iDstTriIndex*3+1] = i2; 866 piTriList_out[iDstTriIndex*3+2] = i3; 867 ++iDstTriIndex; // next 868 } 869 } 870 } 871 872 iTSpacesOffs += verts; 873 assert(iDstTriIndex<=iNrTrianglesIn); 874 } 875 876 for (t=0; t<iNrTrianglesIn; t++) 877 pTriInfos[t].iFlag = 0; 878 879 // return total amount of tspaces 880 return iTSpacesOffs; 881 } 882 883 static SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index) 884 { 885 int iF, iI; 886 SVec3 res; float pos[3]; 887 IndexToData(&iF, &iI, index); 888 pContext->m_pInterface->m_getPosition(pContext, pos, iF, iI); 889 res.x=pos[0]; res.y=pos[1]; res.z=pos[2]; 890 return res; 891 } 892 893 static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index) 894 { 895 int iF, iI; 896 SVec3 res; float norm[3]; 897 IndexToData(&iF, &iI, index); 898 pContext->m_pInterface->m_getNormal(pContext, norm, iF, iI); 899 res.x=norm[0]; res.y=norm[1]; res.z=norm[2]; 900 return res; 901 } 902 903 static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index) 904 { 905 int iF, iI; 906 SVec3 res; float texc[2]; 907 IndexToData(&iF, &iI, index); 908 pContext->m_pInterface->m_getTexCoord(pContext, texc, iF, iI); 909 res.x=texc[0]; res.y=texc[1]; res.z=1.0f; 910 return res; 911 } 912 913 ///////////////////////////////////////////////////////////////////////////////////////////////////// 914 ///////////////////////////////////////////////////////////////////////////////////////////////////// 915 916 typedef union 917 { 918 struct 919 { 920 int i0, i1, f; 921 }; 922 int array[3]; 923 } SEdge; 924 925 static void BuildNeighborsFast(STriInfo pTriInfos[], SEdge * pEdges, const int piTriListIn[], const int iNrTrianglesIn); 926 static void BuildNeighborsSlow(STriInfo pTriInfos[], const int piTriListIn[], const int iNrTrianglesIn); 927 928 // returns the texture area times 2 929 static float CalcTexArea(const SMikkTSpaceContext * pContext, const int indices[]) 930 { 931 const SVec3 t1 = GetTexCoord(pContext, indices[0]); 932 const SVec3 t2 = GetTexCoord(pContext, indices[1]); 933 const SVec3 t3 = GetTexCoord(pContext, indices[2]); 934 935 const float t21x = t2.x-t1.x; 936 const float t21y = t2.y-t1.y; 937 const float t31x = t3.x-t1.x; 938 const float t31y = t3.y-t1.y; 939 940 const float fSignedAreaSTx2 = t21x*t31y - t21y*t31x; 941 942 return fSignedAreaSTx2<0 ? (-fSignedAreaSTx2) : fSignedAreaSTx2; 943 } 944 945 static void InitTriInfo(STriInfo pTriInfos[], const int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn) 946 { 947 int f=0, i=0, t=0; 948 // pTriInfos[f].iFlag is cleared in GenerateInitialVerticesIndexList() which is called before this function. 949 950 // generate neighbor info list 951 for (f=0; f<iNrTrianglesIn; f++) 952 for (i=0; i<3; i++) 953 { 954 pTriInfos[f].FaceNeighbors[i] = -1; 955 pTriInfos[f].AssignedGroup[i] = NULL; 956 957 pTriInfos[f].vOs.x=0.0f; pTriInfos[f].vOs.y=0.0f; pTriInfos[f].vOs.z=0.0f; 958 pTriInfos[f].vOt.x=0.0f; pTriInfos[f].vOt.y=0.0f; pTriInfos[f].vOt.z=0.0f; 959 pTriInfos[f].fMagS = 0; 960 pTriInfos[f].fMagT = 0; 961 962 // assumed bad 963 pTriInfos[f].iFlag |= GROUP_WITH_ANY; 964 } 965 966 // evaluate first order derivatives 967 for (f=0; f<iNrTrianglesIn; f++) 968 { 969 // initial values 970 const SVec3 v1 = GetPosition(pContext, piTriListIn[f*3+0]); 971 const SVec3 v2 = GetPosition(pContext, piTriListIn[f*3+1]); 972 const SVec3 v3 = GetPosition(pContext, piTriListIn[f*3+2]); 973 const SVec3 t1 = GetTexCoord(pContext, piTriListIn[f*3+0]); 974 const SVec3 t2 = GetTexCoord(pContext, piTriListIn[f*3+1]); 975 const SVec3 t3 = GetTexCoord(pContext, piTriListIn[f*3+2]); 976 977 const float t21x = t2.x-t1.x; 978 const float t21y = t2.y-t1.y; 979 const float t31x = t3.x-t1.x; 980 const float t31y = t3.y-t1.y; 981 const SVec3 d1 = vsub(v2,v1); 982 const SVec3 d2 = vsub(v3,v1); 983 984 const float fSignedAreaSTx2 = t21x*t31y - t21y*t31x; 985 //assert(fSignedAreaSTx2!=0); 986 SVec3 vOs = vsub(vscale(t31y,d1), vscale(t21y,d2)); // eq 18 987 SVec3 vOt = vadd(vscale(-t31x,d1), vscale(t21x,d2)); // eq 19 988 989 pTriInfos[f].iFlag |= (fSignedAreaSTx2>0 ? ORIENT_PRESERVING : 0); 990 991 if ( NotZero(fSignedAreaSTx2) ) 992 { 993 const float fAbsArea = fabsf(fSignedAreaSTx2); 994 const float fLenOs = Length(vOs); 995 const float fLenOt = Length(vOt); 996 const float fS = (pTriInfos[f].iFlag&ORIENT_PRESERVING)==0 ? (-1.0f) : 1.0f; 997 if ( NotZero(fLenOs) ) pTriInfos[f].vOs = vscale(fS/fLenOs, vOs); 998 if ( NotZero(fLenOt) ) pTriInfos[f].vOt = vscale(fS/fLenOt, vOt); 999 1000 // evaluate magnitudes prior to normalization of vOs and vOt 1001 pTriInfos[f].fMagS = fLenOs / fAbsArea; 1002 pTriInfos[f].fMagT = fLenOt / fAbsArea; 1003 1004 // if this is a good triangle 1005 if ( NotZero(pTriInfos[f].fMagS) && NotZero(pTriInfos[f].fMagT)) 1006 pTriInfos[f].iFlag &= (~GROUP_WITH_ANY); 1007 } 1008 } 1009 1010 // force otherwise healthy quads to a fixed orientation 1011 while (t<(iNrTrianglesIn-1)) 1012 { 1013 const int iFO_a = pTriInfos[t].iOrgFaceNumber; 1014 const int iFO_b = pTriInfos[t+1].iOrgFaceNumber; 1015 if (iFO_a==iFO_b) // this is a quad 1016 { 1017 const tbool bIsDeg_a = (pTriInfos[t].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; 1018 const tbool bIsDeg_b = (pTriInfos[t+1].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; 1019 1020 // bad triangles should already have been removed by 1021 // DegenPrologue(), but just in case check bIsDeg_a and bIsDeg_a are false 1022 if ((bIsDeg_a||bIsDeg_b)==TFALSE) 1023 { 1024 const tbool bOrientA = (pTriInfos[t].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; 1025 const tbool bOrientB = (pTriInfos[t+1].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; 1026 // if this happens the quad has extremely bad mapping!! 1027 if (bOrientA!=bOrientB) 1028 { 1029 //printf("found quad with bad mapping\n"); 1030 tbool bChooseOrientFirstTri = TFALSE; 1031 if ((pTriInfos[t+1].iFlag&GROUP_WITH_ANY)!=0) bChooseOrientFirstTri = TTRUE; 1032 else if( CalcTexArea(pContext, &piTriListIn[t*3+0]) >= CalcTexArea(pContext, &piTriListIn[(t+1)*3+0]) ) 1033 bChooseOrientFirstTri = TTRUE; 1034 1035 // force match 1036 { 1037 const int t0 = bChooseOrientFirstTri ? t : (t+1); 1038 const int t1 = bChooseOrientFirstTri ? (t+1) : t; 1039 pTriInfos[t1].iFlag &= (~ORIENT_PRESERVING); // clear first 1040 pTriInfos[t1].iFlag |= (pTriInfos[t0].iFlag&ORIENT_PRESERVING); // copy bit 1041 } 1042 } 1043 } 1044 t += 2; 1045 } 1046 else 1047 ++t; 1048 } 1049 1050 // match up edge pairs 1051 { 1052 SEdge * pEdges = (SEdge *) malloc(sizeof(SEdge)*iNrTrianglesIn*3); 1053 if (pEdges==NULL) 1054 BuildNeighborsSlow(pTriInfos, piTriListIn, iNrTrianglesIn); 1055 else 1056 { 1057 BuildNeighborsFast(pTriInfos, pEdges, piTriListIn, iNrTrianglesIn); 1058 1059 free(pEdges); 1060 } 1061 } 1062 } 1063 1064 ///////////////////////////////////////////////////////////////////////////////////////////////////// 1065 ///////////////////////////////////////////////////////////////////////////////////////////////////// 1066 1067 static tbool AssignRecur(const int piTriListIn[], STriInfo psTriInfos[], const int iMyTriIndex, SGroup * pGroup); 1068 static void AddTriToGroup(SGroup * pGroup, const int iTriIndex); 1069 1070 static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupTrianglesBuffer[], const int piTriListIn[], const int iNrTrianglesIn) 1071 { 1072 const int iNrMaxGroups = iNrTrianglesIn*3; 1073 int iNrActiveGroups = 0; 1074 int iOffset = 0, f=0, i=0; 1075 for (f=0; f<iNrTrianglesIn; f++) 1076 { 1077 for (i=0; i<3; i++) 1078 { 1079 // if not assigned to a group 1080 if ((pTriInfos[f].iFlag&GROUP_WITH_ANY)==0 && pTriInfos[f].AssignedGroup[i]==NULL) 1081 { 1082 tbool bOrPre; 1083 int neigh_indexL, neigh_indexR; 1084 const int vert_index = piTriListIn[f*3+i]; 1085 assert(iNrActiveGroups<iNrMaxGroups); 1086 pTriInfos[f].AssignedGroup[i] = &pGroups[iNrActiveGroups]; 1087 pTriInfos[f].AssignedGroup[i]->iVertexRepresentitive = vert_index; 1088 pTriInfos[f].AssignedGroup[i]->bOrientPreservering = (pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0; 1089 pTriInfos[f].AssignedGroup[i]->iNrFaces = 0; 1090 pTriInfos[f].AssignedGroup[i]->pFaceIndices = &piGroupTrianglesBuffer[iOffset]; 1091 ++iNrActiveGroups; 1092 1093 AddTriToGroup(pTriInfos[f].AssignedGroup[i], f); 1094 bOrPre = (pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; 1095 neigh_indexL = pTriInfos[f].FaceNeighbors[i]; 1096 neigh_indexR = pTriInfos[f].FaceNeighbors[i>0?(i-1):2]; 1097 if (neigh_indexL>=0) // neighbor 1098 { 1099 const tbool bAnswer = 1100 AssignRecur(piTriListIn, pTriInfos, neigh_indexL, 1101 pTriInfos[f].AssignedGroup[i] ); 1102 1103 const tbool bOrPre2 = (pTriInfos[neigh_indexL].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; 1104 const tbool bDiff = bOrPre!=bOrPre2 ? TTRUE : TFALSE; 1105 assert(bAnswer || bDiff); 1106 } 1107 if (neigh_indexR>=0) // neighbor 1108 { 1109 const tbool bAnswer = 1110 AssignRecur(piTriListIn, pTriInfos, neigh_indexR, 1111 pTriInfos[f].AssignedGroup[i] ); 1112 1113 const tbool bOrPre2 = (pTriInfos[neigh_indexR].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; 1114 const tbool bDiff = bOrPre!=bOrPre2 ? TTRUE : TFALSE; 1115 assert(bAnswer || bDiff); 1116 } 1117 1118 // update offset 1119 iOffset += pTriInfos[f].AssignedGroup[i]->iNrFaces; 1120 // since the groups are disjoint a triangle can never 1121 // belong to more than 3 groups. Subsequently something 1122 // is completely screwed if this assertion ever hits. 1123 assert(iOffset <= iNrMaxGroups); 1124 } 1125 } 1126 } 1127 1128 return iNrActiveGroups; 1129 } 1130 1131 static void AddTriToGroup(SGroup * pGroup, const int iTriIndex) 1132 { 1133 pGroup->pFaceIndices[pGroup->iNrFaces] = iTriIndex; 1134 ++pGroup->iNrFaces; 1135 } 1136 1137 static tbool AssignRecur(const int piTriListIn[], STriInfo psTriInfos[], 1138 const int iMyTriIndex, SGroup * pGroup) 1139 { 1140 STriInfo * pMyTriInfo = &psTriInfos[iMyTriIndex]; 1141 1142 // track down vertex 1143 const int iVertRep = pGroup->iVertexRepresentitive; 1144 const int * pVerts = &piTriListIn[3*iMyTriIndex+0]; 1145 int i=-1; 1146 if (pVerts[0]==iVertRep) i=0; 1147 else if(pVerts[1]==iVertRep) i=1; 1148 else if(pVerts[2]==iVertRep) i=2; 1149 assert(i>=0 && i<3); 1150 1151 // early out 1152 if (pMyTriInfo->AssignedGroup[i] == pGroup) return TTRUE; 1153 else if(pMyTriInfo->AssignedGroup[i]!=NULL) return TFALSE; 1154 if ((pMyTriInfo->iFlag&GROUP_WITH_ANY)!=0) 1155 { 1156 // first to group with a group-with-anything triangle 1157 // determines it's orientation. 1158 // This is the only existing order dependency in the code!! 1159 if ( pMyTriInfo->AssignedGroup[0] == NULL && 1160 pMyTriInfo->AssignedGroup[1] == NULL && 1161 pMyTriInfo->AssignedGroup[2] == NULL ) 1162 { 1163 pMyTriInfo->iFlag &= (~ORIENT_PRESERVING); 1164 pMyTriInfo->iFlag |= (pGroup->bOrientPreservering ? ORIENT_PRESERVING : 0); 1165 } 1166 } 1167 { 1168 const tbool bOrient = (pMyTriInfo->iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; 1169 if (bOrient != pGroup->bOrientPreservering) return TFALSE; 1170 } 1171 1172 AddTriToGroup(pGroup, iMyTriIndex); 1173 pMyTriInfo->AssignedGroup[i] = pGroup; 1174 1175 { 1176 const int neigh_indexL = pMyTriInfo->FaceNeighbors[i]; 1177 const int neigh_indexR = pMyTriInfo->FaceNeighbors[i>0?(i-1):2]; 1178 if (neigh_indexL>=0) 1179 AssignRecur(piTriListIn, psTriInfos, neigh_indexL, pGroup); 1180 if (neigh_indexR>=0) 1181 AssignRecur(piTriListIn, psTriInfos, neigh_indexR, pGroup); 1182 } 1183 1184 1185 1186 return TTRUE; 1187 } 1188 1189 ///////////////////////////////////////////////////////////////////////////////////////////////////// 1190 ///////////////////////////////////////////////////////////////////////////////////////////////////// 1191 1192 static tbool CompareSubGroups(const SSubGroup * pg1, const SSubGroup * pg2); 1193 static void QuickSort(int* pSortBuffer, int iLeft, int iRight, unsigned int uSeed); 1194 static STSpace EvalTspace(int face_indices[], const int iFaces, const int piTriListIn[], const STriInfo pTriInfos[], const SMikkTSpaceContext * pContext, const int iVertexRepresentitive); 1195 1196 static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], const SGroup pGroups[], 1197 const int iNrActiveGroups, const int piTriListIn[], const float fThresCos, 1198 const SMikkTSpaceContext * pContext) 1199 { 1200 STSpace * pSubGroupTspace = NULL; 1201 SSubGroup * pUniSubGroups = NULL; 1202 int * pTmpMembers = NULL; 1203 int iMaxNrFaces=0, iUniqueTspaces=0, g=0, i=0; 1204 for (g=0; g<iNrActiveGroups; g++) 1205 if (iMaxNrFaces < pGroups[g].iNrFaces) 1206 iMaxNrFaces = pGroups[g].iNrFaces; 1207 1208 if (iMaxNrFaces == 0) return TTRUE; 1209 1210 // make initial allocations 1211 pSubGroupTspace = (STSpace *) malloc(sizeof(STSpace)*iMaxNrFaces); 1212 pUniSubGroups = (SSubGroup *) malloc(sizeof(SSubGroup)*iMaxNrFaces); 1213 pTmpMembers = (int *) malloc(sizeof(int)*iMaxNrFaces); 1214 if (pSubGroupTspace==NULL || pUniSubGroups==NULL || pTmpMembers==NULL) 1215 { 1216 if (pSubGroupTspace!=NULL) free(pSubGroupTspace); 1217 if (pUniSubGroups!=NULL) free(pUniSubGroups); 1218 if (pTmpMembers!=NULL) free(pTmpMembers); 1219 return TFALSE; 1220 } 1221 1222 1223 iUniqueTspaces = 0; 1224 for (g=0; g<iNrActiveGroups; g++) 1225 { 1226 const SGroup * pGroup = &pGroups[g]; 1227 int iUniqueSubGroups = 0, s=0; 1228 1229 for (i=0; i<pGroup->iNrFaces; i++) // triangles 1230 { 1231 const int f = pGroup->pFaceIndices[i]; // triangle number 1232 int index=-1, iVertIndex=-1, iOF_1=-1, iMembers=0, j=0, l=0; 1233 SSubGroup tmp_group; 1234 tbool bFound; 1235 SVec3 n, vOs, vOt; 1236 if (pTriInfos[f].AssignedGroup[0]==pGroup) index=0; 1237 else if(pTriInfos[f].AssignedGroup[1]==pGroup) index=1; 1238 else if(pTriInfos[f].AssignedGroup[2]==pGroup) index=2; 1239 assert(index>=0 && index<3); 1240 1241 iVertIndex = piTriListIn[f*3+index]; 1242 assert(iVertIndex==pGroup->iVertexRepresentitive); 1243 1244 // is normalized already 1245 n = GetNormal(pContext, iVertIndex); 1246 1247 // project 1248 vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n)); 1249 vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n)); 1250 if ( VNotZero(vOs) ) vOs = Normalize(vOs); 1251 if ( VNotZero(vOt) ) vOt = Normalize(vOt); 1252 1253 // original face number 1254 iOF_1 = pTriInfos[f].iOrgFaceNumber; 1255 1256 iMembers = 0; 1257 for (j=0; j<pGroup->iNrFaces; j++) 1258 { 1259 const int t = pGroup->pFaceIndices[j]; // triangle number 1260 const int iOF_2 = pTriInfos[t].iOrgFaceNumber; 1261 1262 // project 1263 SVec3 vOs2 = vsub(pTriInfos[t].vOs, vscale(vdot(n,pTriInfos[t].vOs), n)); 1264 SVec3 vOt2 = vsub(pTriInfos[t].vOt, vscale(vdot(n,pTriInfos[t].vOt), n)); 1265 if ( VNotZero(vOs2) ) vOs2 = Normalize(vOs2); 1266 if ( VNotZero(vOt2) ) vOt2 = Normalize(vOt2); 1267 1268 { 1269 const tbool bAny = ( (pTriInfos[f].iFlag | pTriInfos[t].iFlag) & GROUP_WITH_ANY )!=0 ? TTRUE : TFALSE; 1270 // make sure triangles which belong to the same quad are joined. 1271 const tbool bSameOrgFace = iOF_1==iOF_2 ? TTRUE : TFALSE; 1272 1273 const float fCosS = vdot(vOs,vOs2); 1274 const float fCosT = vdot(vOt,vOt2); 1275 1276 assert(f!=t || bSameOrgFace); // sanity check 1277 if (bAny || bSameOrgFace || (fCosS>fThresCos && fCosT>fThresCos)) 1278 pTmpMembers[iMembers++] = t; 1279 } 1280 } 1281 1282 // sort pTmpMembers 1283 tmp_group.iNrFaces = iMembers; 1284 tmp_group.pTriMembers = pTmpMembers; 1285 if (iMembers>1) 1286 { 1287 unsigned int uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed? 1288 QuickSort(pTmpMembers, 0, iMembers-1, uSeed); 1289 } 1290 1291 // look for an existing match 1292 bFound = TFALSE; 1293 l=0; 1294 while (l<iUniqueSubGroups && !bFound) 1295 { 1296 bFound = CompareSubGroups(&tmp_group, &pUniSubGroups[l]); 1297 if (!bFound) ++l; 1298 } 1299 1300 // assign tangent space index 1301 assert(bFound || l==iUniqueSubGroups); 1302 //piTempTangIndices[f*3+index] = iUniqueTspaces+l; 1303 1304 // if no match was found we allocate a new subgroup 1305 if (!bFound) 1306 { 1307 // insert new subgroup 1308 int * pIndices = (int *) malloc(sizeof(int)*iMembers); 1309 if (pIndices==NULL) 1310 { 1311 // clean up and return false 1312 int s=0; 1313 for (s=0; s<iUniqueSubGroups; s++) 1314 free(pUniSubGroups[s].pTriMembers); 1315 free(pUniSubGroups); 1316 free(pTmpMembers); 1317 free(pSubGroupTspace); 1318 return TFALSE; 1319 } 1320 pUniSubGroups[iUniqueSubGroups].iNrFaces = iMembers; 1321 pUniSubGroups[iUniqueSubGroups].pTriMembers = pIndices; 1322 memcpy(pIndices, tmp_group.pTriMembers, iMembers*sizeof(int)); 1323 pSubGroupTspace[iUniqueSubGroups] = 1324 EvalTspace(tmp_group.pTriMembers, iMembers, piTriListIn, pTriInfos, pContext, pGroup->iVertexRepresentitive); 1325 ++iUniqueSubGroups; 1326 } 1327 1328 // output tspace 1329 { 1330 const int iOffs = pTriInfos[f].iTSpacesOffs; 1331 const int iVert = pTriInfos[f].vert_num[index]; 1332 STSpace * pTS_out = &psTspace[iOffs+iVert]; 1333 assert(pTS_out->iCounter<2); 1334 assert(((pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0) == pGroup->bOrientPreservering); 1335 if (pTS_out->iCounter==1) 1336 { 1337 *pTS_out = AvgTSpace(pTS_out, &pSubGroupTspace[l]); 1338 pTS_out->iCounter = 2; // update counter 1339 pTS_out->bOrient = pGroup->bOrientPreservering; 1340 } 1341 else 1342 { 1343 assert(pTS_out->iCounter==0); 1344 *pTS_out = pSubGroupTspace[l]; 1345 pTS_out->iCounter = 1; // update counter 1346 pTS_out->bOrient = pGroup->bOrientPreservering; 1347 } 1348 } 1349 } 1350 1351 // clean up and offset iUniqueTspaces 1352 for (s=0; s<iUniqueSubGroups; s++) 1353 free(pUniSubGroups[s].pTriMembers); 1354 iUniqueTspaces += iUniqueSubGroups; 1355 } 1356 1357 // clean up 1358 free(pUniSubGroups); 1359 free(pTmpMembers); 1360 free(pSubGroupTspace); 1361 1362 return TTRUE; 1363 } 1364 1365 static STSpace EvalTspace(int face_indices[], const int iFaces, const int piTriListIn[], const STriInfo pTriInfos[], 1366 const SMikkTSpaceContext * pContext, const int iVertexRepresentitive) 1367 { 1368 STSpace res; 1369 float fAngleSum = 0; 1370 int face=0; 1371 res.vOs.x=0.0f; res.vOs.y=0.0f; res.vOs.z=0.0f; 1372 res.vOt.x=0.0f; res.vOt.y=0.0f; res.vOt.z=0.0f; 1373 res.fMagS = 0; res.fMagT = 0; 1374 1375 for (face=0; face<iFaces; face++) 1376 { 1377 const int f = face_indices[face]; 1378 1379 // only valid triangles get to add their contribution 1380 if ( (pTriInfos[f].iFlag&GROUP_WITH_ANY)==0 ) 1381 { 1382 SVec3 n, vOs, vOt, p0, p1, p2, v1, v2; 1383 float fCos, fAngle, fMagS, fMagT; 1384 int i=-1, index=-1, i0=-1, i1=-1, i2=-1; 1385 if (piTriListIn[3*f+0]==iVertexRepresentitive) i=0; 1386 else if(piTriListIn[3*f+1]==iVertexRepresentitive) i=1; 1387 else if(piTriListIn[3*f+2]==iVertexRepresentitive) i=2; 1388 assert(i>=0 && i<3); 1389 1390 // project 1391 index = piTriListIn[3*f+i]; 1392 n = GetNormal(pContext, index); 1393 vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n)); 1394 vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n)); 1395 if ( VNotZero(vOs) ) vOs = Normalize(vOs); 1396 if ( VNotZero(vOt) ) vOt = Normalize(vOt); 1397 1398 i2 = piTriListIn[3*f + (i<2?(i+1):0)]; 1399 i1 = piTriListIn[3*f + i]; 1400 i0 = piTriListIn[3*f + (i>0?(i-1):2)]; 1401 1402 p0 = GetPosition(pContext, i0); 1403 p1 = GetPosition(pContext, i1); 1404 p2 = GetPosition(pContext, i2); 1405 v1 = vsub(p0,p1); 1406 v2 = vsub(p2,p1); 1407 1408 // project 1409 v1 = vsub(v1, vscale(vdot(n,v1),n)); if( VNotZero(v1) ) v1 = Normalize(v1); 1410 v2 = vsub(v2, vscale(vdot(n,v2),n)); if( VNotZero(v2) ) v2 = Normalize(v2); 1411 1412 // weight contribution by the angle 1413 // between the two edge vectors 1414 fCos = vdot(v1,v2); fCos=fCos>1?1:(fCos<(-1) ? (-1) : fCos); 1415 fAngle = (float) acos(fCos); 1416 fMagS = pTriInfos[f].fMagS; 1417 fMagT = pTriInfos[f].fMagT; 1418 1419 res.vOs=vadd(res.vOs, vscale(fAngle,vOs)); 1420 res.vOt=vadd(res.vOt,vscale(fAngle,vOt)); 1421 res.fMagS+=(fAngle*fMagS); 1422 res.fMagT+=(fAngle*fMagT); 1423 fAngleSum += fAngle; 1424 } 1425 } 1426 1427 // normalize 1428 if ( VNotZero(res.vOs) ) res.vOs = Normalize(res.vOs); 1429 if ( VNotZero(res.vOt) ) res.vOt = Normalize(res.vOt); 1430 if (fAngleSum>0) 1431 { 1432 res.fMagS /= fAngleSum; 1433 res.fMagT /= fAngleSum; 1434 } 1435 1436 return res; 1437 } 1438 1439 static tbool CompareSubGroups(const SSubGroup * pg1, const SSubGroup * pg2) 1440 { 1441 tbool bStillSame=TTRUE; 1442 int i=0; 1443 if (pg1->iNrFaces!=pg2->iNrFaces) return TFALSE; 1444 while (i<pg1->iNrFaces && bStillSame) 1445 { 1446 bStillSame = pg1->pTriMembers[i]==pg2->pTriMembers[i] ? TTRUE : TFALSE; 1447 if (bStillSame) ++i; 1448 } 1449 return bStillSame; 1450 } 1451 1452 static void QuickSort(int* pSortBuffer, int iLeft, int iRight, unsigned int uSeed) 1453 { 1454 int iL, iR, n, index, iMid, iTmp; 1455 1456 // Random 1457 unsigned int t=uSeed&31; 1458 t=(uSeed<<t)|(uSeed>>(32-t)); 1459 uSeed=uSeed+t+3; 1460 // Random end 1461 1462 iL=iLeft; iR=iRight; 1463 n = (iR-iL)+1; 1464 assert(n>=0); 1465 index = (int) (uSeed%n); 1466 1467 iMid=pSortBuffer[index + iL]; 1468 1469 1470 do 1471 { 1472 while (pSortBuffer[iL] < iMid) 1473 ++iL; 1474 while (pSortBuffer[iR] > iMid) 1475 --iR; 1476 1477 if (iL <= iR) 1478 { 1479 iTmp = pSortBuffer[iL]; 1480 pSortBuffer[iL] = pSortBuffer[iR]; 1481 pSortBuffer[iR] = iTmp; 1482 ++iL; --iR; 1483 } 1484 } 1485 while (iL <= iR); 1486 1487 if (iLeft < iR) 1488 QuickSort(pSortBuffer, iLeft, iR, uSeed); 1489 if (iL < iRight) 1490 QuickSort(pSortBuffer, iL, iRight, uSeed); 1491 } 1492 1493 ///////////////////////////////////////////////////////////////////////////////////////////// 1494 ///////////////////////////////////////////////////////////////////////////////////////////// 1495 1496 static void QuickSortEdges(SEdge * pSortBuffer, int iLeft, int iRight, const int channel, unsigned int uSeed); 1497 static void GetEdge(int * i0_out, int * i1_out, int * edgenum_out, const int indices[], const int i0_in, const int i1_in); 1498 1499 static void BuildNeighborsFast(STriInfo pTriInfos[], SEdge * pEdges, const int piTriListIn[], const int iNrTrianglesIn) 1500 { 1501 // build array of edges 1502 unsigned int uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed? 1503 int iEntries=0, iCurStartIndex=-1, f=0, i=0; 1504 for (f=0; f<iNrTrianglesIn; f++) 1505 for (i=0; i<3; i++) 1506 { 1507 const int i0 = piTriListIn[f*3+i]; 1508 const int i1 = piTriListIn[f*3+(i<2?(i+1):0)]; 1509 pEdges[f*3+i].i0 = i0 < i1 ? i0 : i1; // put minimum index in i0 1510 pEdges[f*3+i].i1 = !(i0 < i1) ? i0 : i1; // put maximum index in i1 1511 pEdges[f*3+i].f = f; // record face number 1512 } 1513 1514 // sort over all edges by i0, this is the pricy one. 1515 QuickSortEdges(pEdges, 0, iNrTrianglesIn*3-1, 0, uSeed); // sort channel 0 which is i0 1516 1517 // sub sort over i1, should be fast. 1518 // could replace this with a 64 bit int sort over (i0,i1) 1519 // with i0 as msb in the quicksort call above. 1520 iEntries = iNrTrianglesIn*3; 1521 iCurStartIndex = 0; 1522 for (i=1; i<iEntries; i++) 1523 { 1524 if (pEdges[iCurStartIndex].i0 != pEdges[i].i0) 1525 { 1526 const int iL = iCurStartIndex; 1527 const int iR = i-1; 1528 //const int iElems = i-iL; 1529 iCurStartIndex = i; 1530 QuickSortEdges(pEdges, iL, iR, 1, uSeed); // sort channel 1 which is i1 1531 } 1532 } 1533 1534 // sub sort over f, which should be fast. 1535 // this step is to remain compliant with BuildNeighborsSlow() when 1536 // more than 2 triangles use the same edge (such as a butterfly topology). 1537 iCurStartIndex = 0; 1538 for (i=1; i<iEntries; i++) 1539 { 1540 if (pEdges[iCurStartIndex].i0 != pEdges[i].i0 || pEdges[iCurStartIndex].i1 != pEdges[i].i1) 1541 { 1542 const int iL = iCurStartIndex; 1543 const int iR = i-1; 1544 //const int iElems = i-iL; 1545 iCurStartIndex = i; 1546 QuickSortEdges(pEdges, iL, iR, 2, uSeed); // sort channel 2 which is f 1547 } 1548 } 1549 1550 // pair up, adjacent triangles 1551 for (i=0; i<iEntries; i++) 1552 { 1553 const int i0=pEdges[i].i0; 1554 const int i1=pEdges[i].i1; 1555 const int f = pEdges[i].f; 1556 tbool bUnassigned_A; 1557 1558 int i0_A, i1_A; 1559 int edgenum_A, edgenum_B=0; // 0,1 or 2 1560 GetEdge(&i0_A, &i1_A, &edgenum_A, &piTriListIn[f*3], i0, i1); // resolve index ordering and edge_num 1561 bUnassigned_A = pTriInfos[f].FaceNeighbors[edgenum_A] == -1 ? TTRUE : TFALSE; 1562 1563 if (bUnassigned_A) 1564 { 1565 // get true index ordering 1566 int j=i+1, t; 1567 tbool bNotFound = TTRUE; 1568 while (j<iEntries && i0==pEdges[j].i0 && i1==pEdges[j].i1 && bNotFound) 1569 { 1570 tbool bUnassigned_B; 1571 int i0_B, i1_B; 1572 t = pEdges[j].f; 1573 // flip i0_B and i1_B 1574 GetEdge(&i1_B, &i0_B, &edgenum_B, &piTriListIn[t*3], pEdges[j].i0, pEdges[j].i1); // resolve index ordering and edge_num 1575 //assert(!(i0_A==i1_B && i1_A==i0_B)); 1576 bUnassigned_B = pTriInfos[t].FaceNeighbors[edgenum_B]==-1 ? TTRUE : TFALSE; 1577 if (i0_A==i0_B && i1_A==i1_B && bUnassigned_B) 1578 bNotFound = TFALSE; 1579 else 1580 ++j; 1581 } 1582 1583 if (!bNotFound) 1584 { 1585 int t = pEdges[j].f; 1586 pTriInfos[f].FaceNeighbors[edgenum_A] = t; 1587 //assert(pTriInfos[t].FaceNeighbors[edgenum_B]==-1); 1588 pTriInfos[t].FaceNeighbors[edgenum_B] = f; 1589 } 1590 } 1591 } 1592 } 1593 1594 static void BuildNeighborsSlow(STriInfo pTriInfos[], const int piTriListIn[], const int iNrTrianglesIn) 1595 { 1596 int f=0, i=0; 1597 for (f=0; f<iNrTrianglesIn; f++) 1598 { 1599 for (i=0; i<3; i++) 1600 { 1601 // if unassigned 1602 if (pTriInfos[f].FaceNeighbors[i] == -1) 1603 { 1604 const int i0_A = piTriListIn[f*3+i]; 1605 const int i1_A = piTriListIn[f*3+(i<2?(i+1):0)]; 1606 1607 // search for a neighbor 1608 tbool bFound = TFALSE; 1609 int t=0, j=0; 1610 while (!bFound && t<iNrTrianglesIn) 1611 { 1612 if (t!=f) 1613 { 1614 j=0; 1615 while (!bFound && j<3) 1616 { 1617 // in rev order 1618 const int i1_B = piTriListIn[t*3+j]; 1619 const int i0_B = piTriListIn[t*3+(j<2?(j+1):0)]; 1620 //assert(!(i0_A==i1_B && i1_A==i0_B)); 1621 if (i0_A==i0_B && i1_A==i1_B) 1622 bFound = TTRUE; 1623 else 1624 ++j; 1625 } 1626 } 1627 1628 if (!bFound) ++t; 1629 } 1630 1631 // assign neighbors 1632 if (bFound) 1633 { 1634 pTriInfos[f].FaceNeighbors[i] = t; 1635 //assert(pTriInfos[t].FaceNeighbors[j]==-1); 1636 pTriInfos[t].FaceNeighbors[j] = f; 1637 } 1638 } 1639 } 1640 } 1641 } 1642 1643 static void QuickSortEdges(SEdge * pSortBuffer, int iLeft, int iRight, const int channel, unsigned int uSeed) 1644 { 1645 unsigned int t; 1646 int iL, iR, n, index, iMid; 1647 1648 // early out 1649 SEdge sTmp; 1650 const int iElems = iRight-iLeft+1; 1651 if (iElems<2) return; 1652 else if(iElems==2) 1653 { 1654 if (pSortBuffer[iLeft].array[channel] > pSortBuffer[iRight].array[channel]) 1655 { 1656 sTmp = pSortBuffer[iLeft]; 1657 pSortBuffer[iLeft] = pSortBuffer[iRight]; 1658 pSortBuffer[iRight] = sTmp; 1659 } 1660 return; 1661 } 1662 1663 // Random 1664 t=uSeed&31; 1665 t=(uSeed<<t)|(uSeed>>(32-t)); 1666 uSeed=uSeed+t+3; 1667 // Random end 1668 1669 iL=iLeft, iR=iRight; 1670 n = (iR-iL)+1; 1671 assert(n>=0); 1672 index = (int) (uSeed%n); 1673 1674 iMid=pSortBuffer[index + iL].array[channel]; 1675 1676 do 1677 { 1678 while (pSortBuffer[iL].array[channel] < iMid) 1679 ++iL; 1680 while (pSortBuffer[iR].array[channel] > iMid) 1681 --iR; 1682 1683 if (iL <= iR) 1684 { 1685 sTmp = pSortBuffer[iL]; 1686 pSortBuffer[iL] = pSortBuffer[iR]; 1687 pSortBuffer[iR] = sTmp; 1688 ++iL; --iR; 1689 } 1690 } 1691 while (iL <= iR); 1692 1693 if (iLeft < iR) 1694 QuickSortEdges(pSortBuffer, iLeft, iR, channel, uSeed); 1695 if (iL < iRight) 1696 QuickSortEdges(pSortBuffer, iL, iRight, channel, uSeed); 1697 } 1698 1699 // resolve ordering and edge number 1700 static void GetEdge(int * i0_out, int * i1_out, int * edgenum_out, const int indices[], const int i0_in, const int i1_in) 1701 { 1702 *edgenum_out = -1; 1703 1704 // test if first index is on the edge 1705 if (indices[0]==i0_in || indices[0]==i1_in) 1706 { 1707 // test if second index is on the edge 1708 if (indices[1]==i0_in || indices[1]==i1_in) 1709 { 1710 edgenum_out[0]=0; // first edge 1711 i0_out[0]=indices[0]; 1712 i1_out[0]=indices[1]; 1713 } 1714 else 1715 { 1716 edgenum_out[0]=2; // third edge 1717 i0_out[0]=indices[2]; 1718 i1_out[0]=indices[0]; 1719 } 1720 } 1721 else 1722 { 1723 // only second and third index is on the edge 1724 edgenum_out[0]=1; // second edge 1725 i0_out[0]=indices[1]; 1726 i1_out[0]=indices[2]; 1727 } 1728 } 1729 1730 1731 ///////////////////////////////////////////////////////////////////////////////////////////// 1732 /////////////////////////////////// Degenerate triangles //////////////////////////////////// 1733 1734 static void DegenPrologue(STriInfo pTriInfos[], int piTriList_out[], const int iNrTrianglesIn, const int iTotTris) 1735 { 1736 int iNextGoodTriangleSearchIndex=-1; 1737 tbool bStillFindingGoodOnes; 1738 1739 // locate quads with only one good triangle 1740 int t=0; 1741 while (t<(iTotTris-1)) 1742 { 1743 const int iFO_a = pTriInfos[t].iOrgFaceNumber; 1744 const int iFO_b = pTriInfos[t+1].iOrgFaceNumber; 1745 if (iFO_a==iFO_b) // this is a quad 1746 { 1747 const tbool bIsDeg_a = (pTriInfos[t].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; 1748 const tbool bIsDeg_b = (pTriInfos[t+1].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; 1749 if ((bIsDeg_a^bIsDeg_b)!=0) 1750 { 1751 pTriInfos[t].iFlag |= QUAD_ONE_DEGEN_TRI; 1752 pTriInfos[t+1].iFlag |= QUAD_ONE_DEGEN_TRI; 1753 } 1754 t += 2; 1755 } 1756 else 1757 ++t; 1758 } 1759 1760 // reorder list so all degen triangles are moved to the back 1761 // without reordering the good triangles 1762 iNextGoodTriangleSearchIndex = 1; 1763 t=0; 1764 bStillFindingGoodOnes = TTRUE; 1765 while (t<iNrTrianglesIn && bStillFindingGoodOnes) 1766 { 1767 const tbool bIsGood = (pTriInfos[t].iFlag&MARK_DEGENERATE)==0 ? TTRUE : TFALSE; 1768 if (bIsGood) 1769 { 1770 if (iNextGoodTriangleSearchIndex < (t+2)) 1771 iNextGoodTriangleSearchIndex = t+2; 1772 } 1773 else 1774 { 1775 int t0, t1; 1776 // search for the first good triangle. 1777 tbool bJustADegenerate = TTRUE; 1778 while (bJustADegenerate && iNextGoodTriangleSearchIndex<iTotTris) 1779 { 1780 const tbool bIsGood = (pTriInfos[iNextGoodTriangleSearchIndex].iFlag&MARK_DEGENERATE)==0 ? TTRUE : TFALSE; 1781 if (bIsGood) bJustADegenerate=TFALSE; 1782 else ++iNextGoodTriangleSearchIndex; 1783 } 1784 1785 t0 = t; 1786 t1 = iNextGoodTriangleSearchIndex; 1787 ++iNextGoodTriangleSearchIndex; 1788 assert(iNextGoodTriangleSearchIndex > (t+1)); 1789 1790 // swap triangle t0 and t1 1791 if (!bJustADegenerate) 1792 { 1793 int i=0; 1794 for (i=0; i<3; i++) 1795 { 1796 const int index = piTriList_out[t0*3+i]; 1797 piTriList_out[t0*3+i] = piTriList_out[t1*3+i]; 1798 piTriList_out[t1*3+i] = index; 1799 } 1800 { 1801 const STriInfo tri_info = pTriInfos[t0]; 1802 pTriInfos[t0] = pTriInfos[t1]; 1803 pTriInfos[t1] = tri_info; 1804 } 1805 } 1806 else 1807 bStillFindingGoodOnes = TFALSE; // this is not supposed to happen 1808 } 1809 1810 if (bStillFindingGoodOnes) ++t; 1811 } 1812 1813 assert(bStillFindingGoodOnes); // code will still work. 1814 assert(iNrTrianglesIn == t); 1815 } 1816 1817 static void DegenEpilogue(STSpace psTspace[], STriInfo pTriInfos[], int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn, const int iTotTris) 1818 { 1819 int t=0, i=0; 1820 // deal with degenerate triangles 1821 // punishment for degenerate triangles is O(N^2) 1822 for (t=iNrTrianglesIn; t<iTotTris; t++) 1823 { 1824 // degenerate triangles on a quad with one good triangle are skipped 1825 // here but processed in the next loop 1826 const tbool bSkip = (pTriInfos[t].iFlag&QUAD_ONE_DEGEN_TRI)!=0 ? TTRUE : TFALSE; 1827 1828 if (!bSkip) 1829 { 1830 for (i=0; i<3; i++) 1831 { 1832 const int index1 = piTriListIn[t*3+i]; 1833 // search through the good triangles 1834 tbool bNotFound = TTRUE; 1835 int j=0; 1836 while (bNotFound && j<(3*iNrTrianglesIn)) 1837 { 1838 const int index2 = piTriListIn[j]; 1839 if (index1==index2) bNotFound=TFALSE; 1840 else ++j; 1841 } 1842 1843 if (!bNotFound) 1844 { 1845 const int iTri = j/3; 1846 const int iVert = j%3; 1847 const int iSrcVert=pTriInfos[iTri].vert_num[iVert]; 1848 const int iSrcOffs=pTriInfos[iTri].iTSpacesOffs; 1849 const int iDstVert=pTriInfos[t].vert_num[i]; 1850 const int iDstOffs=pTriInfos[t].iTSpacesOffs; 1851 1852 // copy tspace 1853 psTspace[iDstOffs+iDstVert] = psTspace[iSrcOffs+iSrcVert]; 1854 } 1855 } 1856 } 1857 } 1858 1859 // deal with degenerate quads with one good triangle 1860 for (t=0; t<iNrTrianglesIn; t++) 1861 { 1862 // this triangle belongs to a quad where the 1863 // other triangle is degenerate 1864 if ( (pTriInfos[t].iFlag&QUAD_ONE_DEGEN_TRI)!=0 ) 1865 { 1866 SVec3 vDstP; 1867 int iOrgF=-1, i=0; 1868 tbool bNotFound; 1869 unsigned char * pV = pTriInfos[t].vert_num; 1870 int iFlag = (1<<pV[0]) | (1<<pV[1]) | (1<<pV[2]); 1871 int iMissingIndex = 0; 1872 if ((iFlag&2)==0) iMissingIndex=1; 1873 else if((iFlag&4)==0) iMissingIndex=2; 1874 else if((iFlag&8)==0) iMissingIndex=3; 1875 1876 iOrgF = pTriInfos[t].iOrgFaceNumber; 1877 vDstP = GetPosition(pContext, MakeIndex(iOrgF, iMissingIndex)); 1878 bNotFound = TTRUE; 1879 i=0; 1880 while (bNotFound && i<3) 1881 { 1882 const int iVert = pV[i]; 1883 const SVec3 vSrcP = GetPosition(pContext, MakeIndex(iOrgF, iVert)); 1884 if (veq(vSrcP, vDstP)==TTRUE) 1885 { 1886 const int iOffs = pTriInfos[t].iTSpacesOffs; 1887 psTspace[iOffs+iMissingIndex] = psTspace[iOffs+iVert]; 1888 bNotFound=TFALSE; 1889 } 1890 else 1891 ++i; 1892 } 1893 assert(!bNotFound); 1894 } 1895 } 1896 } -
source/graphics/ObjectBase.h
80 80 int m_Frequency; 81 81 VfsPath m_ModelFilename; 82 82 VfsPath m_TextureFilename; 83 VfsPath m_NormalFilename; 84 VfsPath m_SpecularFilename; 83 85 Decal m_Decal; 84 86 VfsPath m_Particles; 85 87 CStr m_Color; … … 91 93 struct Variation 92 94 { 93 95 VfsPath texture; 96 VfsPath normal; 97 VfsPath specular; 94 98 VfsPath model; 95 99 Decal decal; 96 100 VfsPath particles; -
source/graphics/TerrainTextureEntry.cpp
44 44 // TODO: anisotropy should probably be user-configurable, but we want it to be 45 45 // at least 2 for terrain else the ground looks very blurry when you tilt the 46 46 // camera upwards 47 texture.SetMaxAnisotropy(2.0f); 47 texture.SetMaxAnisotropy(2.0f); 48 48 49 49 if (CRenderer::IsInitialised()) 50 50 m_Texture = g_Renderer.GetTextureManager().CreateTexture(texture); … … 71 71 (*it)->AddTerrain(this); 72 72 73 73 m_Tag = utf8_from_wstring(path.Basename().string()); 74 75 if (m_pProperties->HasNormalMap()) 76 { 77 //std::wcout << m_pProperties->GetNormalMap().string() << std::endl; 78 CTextureProperties normal(m_pProperties->GetNormalMap()); 79 normal.SetWrap(GL_REPEAT); 80 normal.SetMaxAnisotropy(2.0f); 81 if (CRenderer::IsInitialised()) 82 m_Normal = g_Renderer.GetTextureManager().CreateTexture(normal); 83 } 84 85 if (m_pProperties->HasSpecularMap()) 86 { 87 CTextureProperties specular(m_pProperties->GetSpecularMap()); 88 specular.SetWrap(GL_REPEAT); 89 specular.SetMaxAnisotropy(2.0f); 90 if (CRenderer::IsInitialised()) 91 m_Specular = g_Renderer.GetTextureManager().CreateTexture(specular); 92 } 74 93 } 75 94 76 95 CTerrainTextureEntry::~CTerrainTextureEntry() -
source/graphics/weldmesh.h
1 /** 2 * Copyright (C) 2011 by Morten S. Mikkelsen 3 * 4 * This software is provided 'as-is', without any express or implied 5 * warranty. In no event will the authors be held liable for any damages 6 * arising from the use of this software. 7 * 8 * Permission is granted to anyone to use this software for any purpose, 9 * including commercial applications, and to alter it and redistribute it 10 * freely, subject to the following restrictions: 11 * 12 * 1. The origin of this software must not be misrepresented; you must not 13 * claim that you wrote the original software. If you use this software 14 * in a product, an acknowledgment in the product documentation would be 15 * appreciated but is not required. 16 * 2. Altered source versions must be plainly marked as such, and must not be 17 * misrepresented as being the original software. 18 * 3. This notice may not be removed or altered from any source distribution. 19 */ 20 21 22 #ifndef __WELDMESH_H__ 23 #define __WELDMESH_H__ 24 25 26 #ifdef __cplusplus 27 extern "C" { 28 #endif 29 30 // piRemapTable must be initialized and point to an area in memory 31 // with the byte size: iNrVerticesIn * sizeof(int). 32 // pfVertexDataOut must be initialized and point to an area in memory 33 // with the byte size: iNrVerticesIn * iFloatsPerVert * sizeof(float). 34 // At the end of the WeldMesh() call the array pfVertexDataOut will contain 35 // unique vertices only. Each entry in piRemapTable contains the index to 36 // the new location of the vertex in pfVertexDataOut in units of iFloatsPerVert. 37 // Note that this code is suitable for welding both unindexed meshes but also 38 // indexed meshes which need to have duplicates removed. In the latter case 39 // one simply uses the remap table to convert the old index list to the new vertex array. 40 // Finally, the return value is the number of unique vertices found. 41 int WeldMesh(int * piRemapTable, float * pfVertexDataOut, 42 const float pfVertexDataIn[], const int iNrVerticesIn, const int iFloatsPerVert); 43 44 #ifdef __cplusplus 45 } 46 #endif 47 48 49 #endif 50 No newline at end of file -
source/graphics/Material.cpp
32 32 m_DiffuseTexture = texture; 33 33 } 34 34 35 void CMaterial::SetNormalTexture(const CTexturePtr& texture) 36 { 37 m_NormalTexture = texture; 38 } 39 40 void CMaterial::SetSpecularTexture(const CTexturePtr& texture) 41 { 42 m_SpecularTexture = texture; 43 } 44 35 45 void CMaterial::SetShaderEffect(const CStr& effect) 36 46 { 37 47 m_ShaderEffect = CStrIntern(effect); -
source/graphics/ObjectBase.cpp
62 62 EL(prop); 63 63 EL(mesh); 64 64 EL(texture); 65 EL(normal); 66 EL(specular); 65 67 EL(colour); 66 68 EL(decal); 67 69 EL(particles); … … 151 153 { 152 154 currentVariant->m_TextureFilename = VfsPath("art/textures/skins") / option.GetText().FromUTF8(); 153 155 } 156 else if (option_name == el_normal) 157 { 158 currentVariant->m_NormalFilename = VfsPath("art/textures/skins") / option.GetText().FromUTF8(); 159 } 160 else if (option_name == el_specular) 161 { 162 currentVariant->m_SpecularFilename = VfsPath("art/textures/skins") / option.GetText().FromUTF8(); 163 } 154 164 else if (option_name == el_decal) 155 165 { 156 166 XMBAttributeList attrs = option.GetAttributes(); … … 399 409 if (! var.m_TextureFilename.empty()) 400 410 variation.texture = var.m_TextureFilename; 401 411 412 if (! var.m_NormalFilename.empty()) 413 variation.normal = var.m_NormalFilename; 414 415 if (! var.m_SpecularFilename.empty()) 416 variation.specular = var.m_SpecularFilename; 417 402 418 if (! var.m_ModelFilename.empty()) 403 419 variation.model = var.m_ModelFilename; 404 420 -
source/graphics/TerrainProperties.h
66 66 GroupVector m_Groups; 67 67 68 68 void LoadXml(XMBElement node, CXeromyces *pFile, const VfsPath& pathname); 69 70 VfsPath m_NormalMap; 71 72 VfsPath m_SpecularMap; 69 73 70 74 public: 71 75 CTerrainProperties(CTerrainPropertiesPtr parent); … … 111 115 { 112 116 return m_Groups; 113 117 } 118 119 const VfsPath &GetNormalMap() const 120 { 121 return m_NormalMap; 122 } 123 124 const VfsPath &GetSpecularMap() const 125 { 126 return m_SpecularMap; 127 } 128 129 bool HasNormalMap() 130 { 131 return !GetNormalMap().empty(); 132 } 133 134 bool HasSpecularMap() 135 { 136 return !GetSpecularMap().empty(); 137 } 114 138 }; 115 139 116 140 #endif -
source/graphics/ObjectEntry.cpp
61 61 // Copy the chosen data onto this model: 62 62 63 63 m_TextureName = variation.texture; 64 m_NormalName = variation.normal; 65 m_SpecularName = variation.specular; 64 66 m_ModelName = variation.model; 65 67 66 68 if (! variation.color.empty()) … … 128 130 texture->Prefetch(); // if we've loaded this model we're probably going to render it soon, so prefetch its texture 129 131 model->GetMaterial().SetDiffuseTexture(texture); 130 132 133 CTextureProperties normalProps(m_NormalName); 134 normalProps.SetWrap(GL_CLAMP_TO_EDGE); 135 CTexturePtr normal = g_Renderer.GetTextureManager().CreateTexture(normalProps); 136 //normal->Prefetch(); // if we've loaded this model we're probably going to render it soon, so prefetch its texture 137 model->GetMaterial().SetNormalTexture(normal); 138 139 CTextureProperties specularProps(m_SpecularName); 140 specularProps.SetWrap(GL_CLAMP_TO_EDGE); 141 CTexturePtr specular = g_Renderer.GetTextureManager().CreateTexture(specularProps); 142 //specular->Prefetch(); // if we've loaded this model we're probably going to render it soon, so prefetch its texture 143 model->GetMaterial().SetSpecularTexture(specular); 144 131 145 // calculate initial object space bounds, based on vertex positions 132 146 model->CalcStaticObjectBounds(); 133 147 -
source/lib/external_libraries/glext_funcs.h
181 181 FUNC(void, glFramebufferRenderbufferEXT, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)) 182 182 FUNC(void, glGetFramebufferAttachmentParameterivEXT, (GLenum target, GLenum attachment, GLenum pname, GLint *params)) 183 183 FUNC(void, glGenerateMipmapEXT, (GLenum target)) 184 FUNC(void, glBlitFramebufferEXT, (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)) 185 FUNC(void, glDrawBuffers, (GLsizei n, const GLenum *bufs)) 184 186 187 185 188 // GL_ARB_vertex_program, GL_ARB_fragment_program 186 189 FUNC(void, glProgramStringARB, (GLenum target, GLenum format, GLsizei len, const GLvoid *string)) 187 190 FUNC(void, glBindProgramARB, (GLenum target, GLuint program)) -
source/renderer/PostprocManager.h
1 #ifndef INCLUDED_POSTPROCMANAGER 2 #define INCLUDED_POSTPROCMANAGER 3 4 class PostprocManager 5 { 6 public: 7 8 GLuint pingFbo, pongFbo; 9 GLuint colourTex1, colourTex2; 10 GLuint depthTex, stencilTex; 11 GLuint losTex; 12 13 bool whichBuffer; 14 15 std::vector<std::vector<CShaderTechniquePtr> > renderStages; 16 17 int width, height; 18 19 bool isInitialised; 20 21 PostprocManager(); 22 ~PostprocManager(); 23 24 void Initialize(); 25 26 void Cleanup(); 27 28 void RecreateBuffers(); 29 30 void LoadEffect(const char* name, int stage); 31 32 void ApplyEffect(CShaderTechniquePtr &shaderTech1); 33 void ApplyPostproc(int stage); 34 void ApplyLos(); 35 36 void CaptureRenderOutput(); 37 38 void PostprocStage1(); 39 void PostprocStage2(); 40 41 void ReleaseRenderOutput(); 42 43 44 45 46 }; 47 48 49 #endif //INCLUDED_POSTPROCMANAGER -
source/renderer/PatchRData.h
72 72 CVector3D m_Position; 73 73 // diffuse color from sunlight 74 74 SColor4ub m_DiffuseColor; 75 CVector3D m_Normal; 75 76 }; 76 cassert(sizeof(SBaseVertex) == 16);77 cassert(sizeof(SBaseVertex) == 28); 77 78 78 79 struct SSideVertex { 79 80 // vertex position … … 91 92 // vertex uvs for alpha texture 92 93 float m_AlphaUVs[2]; 93 94 // add some padding since VBOs prefer power-of-two sizes 94 u32 m_Padding[2]; 95 //u32 m_Padding[2]; 96 CVector3D m_Normal; 95 97 }; 96 cassert(sizeof(SBlendVertex) == 3 2);98 cassert(sizeof(SBlendVertex) == 36); 97 99 98 100 // Mixed Fancy/Simple water vertex description data structure 99 101 struct SWaterVertex { -
source/renderer/RenderModifiers.h
73 73 */ 74 74 virtual void PrepareTexture(const CShaderProgramPtr& shader, CTexture& texture) = 0; 75 75 76 virtual void PrepareNormal(const CShaderProgramPtr& shader, CTexture& normal) = 0; 77 78 virtual void PrepareSpecular(const CShaderProgramPtr& shader, CTexture& specular) = 0; 79 76 80 /** 77 81 * PrepareModel: Called before rendering the given model. 78 82 * … … 134 138 // Implementation 135 139 void BeginPass(const CShaderProgramPtr& shader); 136 140 void PrepareTexture(const CShaderProgramPtr& shader, CTexture& texture); 141 void PrepareNormal(const CShaderProgramPtr& shader, CTexture& normal); 142 void PrepareSpecular(const CShaderProgramPtr& shader, CTexture& specular); 137 143 void PrepareModel(const CShaderProgramPtr& shader, CModel* model); 138 144 139 145 private: … … 141 147 CShaderProgram::Binding m_BindingShadingColor; 142 148 CShaderProgram::Binding m_BindingPlayerColor; 143 149 CShaderProgram::Binding m_BindingBaseTex; 150 CShaderProgram::Binding m_BindingNormTex; 151 CShaderProgram::Binding m_BindingSpecTex; 144 152 }; 145 153 146 154 #endif // INCLUDED_RENDERMODIFIERS -
source/renderer/ModelRenderer.cpp
35 35 #include "renderer/ModelVertexRenderer.h" 36 36 #include "renderer/Renderer.h" 37 37 #include "renderer/RenderModifiers.h" 38 #include "renderer/MikktspaceWrap.h" 38 39 39 40 #include <boost/weak_ptr.hpp> 40 41 … … 57 58 #endif 58 59 } 59 60 61 void ModelRenderer::GenTangents(const CModelDefPtr& mdef, std::vector<float>& newVertices) 62 { 63 MikkTSpace ms(mdef, newVertices); 64 65 ms.generate(); 66 } 67 60 68 // Helper function to copy object-space position and normal vectors into arrays. 61 69 void ModelRenderer::CopyPositionAndNormals( 62 70 const CModelDefPtr& mdef, … … 557 565 m->vertexRenderer->BeginPass(streamflags); 558 566 559 567 CTexture* currentTex = NULL; 568 CTexture* currentNorm = NULL; 569 CTexture* currentSpec = NULL; 560 570 CModelDef* currentModeldef = NULL; 561 571 CShaderUniforms currentStaticUniforms; 562 572 // (Texture needs to be rebound after binding a new shader, so we … … 581 591 modifier->PrepareTexture(shader, *currentTex); 582 592 } 583 593 594 CTexture* newNorm = model->GetMaterial().GetNormalTexture().get(); 595 if (newNorm != currentNorm) 596 { 597 currentNorm = newNorm; 598 modifier->PrepareNormal(shader, *currentNorm); 599 } 600 601 CTexture* newSpec = model->GetMaterial().GetSpecularTexture().get(); 602 if (newSpec != currentSpec) 603 { 604 currentSpec = newSpec; 605 modifier->PrepareSpecular(shader, *currentSpec); 606 } 607 584 608 // Bind modeldef when it changes 585 609 CModelDef* newModeldef = model->GetModelDef().get(); 586 610 if (newModeldef != currentModeldef) -
source/renderer/MikktspaceWrap.h
1 #ifndef INCLUDED_MIKKWRAP 2 #define INCLUDED_MIKKWRAP 3 4 5 #include <graphics/mikktspace.h> 6 7 class MikkTSpace 8 { 9 10 public: 11 12 MikkTSpace(const CModelDefPtr& m, std::vector<float>& v); 13 14 void generate(); 15 16 private: 17 18 SMikkTSpaceInterface interface; 19 SMikkTSpaceContext context; 20 21 const CModelDefPtr& model; 22 23 std::vector<float>& newVertices; 24 25 26 // Returns the number of faces (triangles/quads) on the mesh to be processed. 27 static int getNumFaces(const SMikkTSpaceContext *pContext); 28 29 30 // Returns the number of vertices on face number iFace 31 // iFace is a number in the range {0, 1, ..., getNumFaces()-1} 32 static int getNumVerticesOfFace(const SMikkTSpaceContext *pContext, const int iFace); 33 34 35 // returns the position/normal/texcoord of the referenced face of vertex number iVert. 36 // iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads. 37 static void getPosition(const SMikkTSpaceContext *pContext, 38 float fvPosOut[], const int iFace, const int iVert); 39 40 static void getNormal(const SMikkTSpaceContext *pContext, 41 float fvNormOut[], const int iFace, const int iVert); 42 43 static void getTexCoord(const SMikkTSpaceContext *pContext, 44 float fvTexcOut[], const int iFace, const int iVert); 45 46 47 // either (or both) of the two setTSpace callbacks can be set. 48 // The call-back m_setTSpaceBasic() is sufficient for basic normal mapping. 49 50 // This function is used to return the tangent and fSign to the application. 51 // fvTangent is a unit length vector. 52 // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. 53 // bitangent = fSign * cross(vN, tangent); 54 // Note that the results are returned unindexed. It is possible to generate a new index list 55 // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. 56 // DO NOT! use an already existing index list. 57 //void setTSpaceBasic(const MikkTSpace *parent, const SMikkTSpaceContext *pContext, 58 // const float fvTangent[], const float fSign, const int iFace, const int iVert); 59 60 61 // This function is used to return tangent space results to the application. 62 // fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are their 63 // true magnitudes which can be used for relief mapping effects. 64 // fvBiTangent is the "real" bitangent and thus may not be perpendicular to fvTangent. 65 // However, both are perpendicular to the vertex normal. 66 // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. 67 // fSign = bIsOrientationPreserving ? 1.0f : (-1.0f); 68 // bitangent = fSign * cross(vN, tangent); 69 // Note that the results are returned unindexed. It is possible to generate a new index list 70 // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. 71 // DO NOT! use an already existing index list. 72 static void setTSpace(const SMikkTSpaceContext * pContext, const float fvTangent[], 73 const float fvBiTangent[], const float fMagS, const float fMagT, 74 const tbool bIsOrientationPreserving, const int iFace, const int iVert); 75 76 77 }; 78 79 80 #endif // INCLUDED_MIKKWRAP 81 No newline at end of file -
source/renderer/PostprocManager.cpp
1 #include "precompiled.h" 2 3 #include "lib/ogl.h" 4 #include "maths/MathUtil.h" 5 6 #include "gui/GUIutil.h" 7 #include "lib/bits.h" 8 #include "ps/CLogger.h" 9 10 #include "graphics/ShaderManager.h" 11 #include "renderer/Renderer.h" 12 13 #include "renderer/PostprocManager.h" 14 15 16 PostprocManager::PostprocManager() 17 { 18 isInitialised = false; 19 pingFbo = 0; 20 pongFbo = 0; 21 colourTex1 = 0; 22 colourTex2 = 0; 23 depthTex = 0; 24 stencilTex = 0; 25 losTex = 0; 26 whichBuffer = true; 27 } 28 29 30 PostprocManager::~PostprocManager() 31 { 32 Cleanup(); 33 } 34 35 void PostprocManager::Initialize() 36 { 37 RecreateBuffers(); 38 isInitialised = true; 39 40 renderStages = std::vector<std::vector<CShaderTechniquePtr> >(5); 41 42 LoadEffect("ssao", 1); 43 44 45 LoadEffect("fog", 1); 46 LoadEffect("hdr", 1); 47 LoadEffect("bloom", 1); 48 49 LoadEffect("los", 4); 50 } 51 52 void PostprocManager::Cleanup() 53 { 54 if (isInitialised) 55 { 56 if (pingFbo) pglDeleteFramebuffersEXT(1, &pingFbo); 57 if (pongFbo) pglDeleteFramebuffersEXT(1, &pongFbo); 58 if (colourTex1) glDeleteTextures(1, &colourTex1); 59 if (colourTex2) glDeleteTextures(1, &colourTex2); 60 if (depthTex) glDeleteTextures(1, &depthTex); 61 if (losTex) glDeleteTextures(1, &losTex); 62 } 63 } 64 65 66 void PostprocManager::RecreateBuffers() 67 { 68 Cleanup(); 69 70 71 width = g_Renderer.GetWidth(); 72 height = g_Renderer.GetHeight(); 73 74 75 glGenTextures(1, (GLuint*)&colourTex1); 76 glBindTexture(GL_TEXTURE_2D, colourTex1); 77 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, 78 GL_UNSIGNED_BYTE, 0); 79 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 80 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 81 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 82 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 83 84 85 glGenTextures(1, (GLuint*)&colourTex2); 86 glBindTexture(GL_TEXTURE_2D, colourTex2); 87 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, 88 GL_UNSIGNED_BYTE, 0); 89 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 90 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 91 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 92 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 93 94 95 glGenTextures(1, (GLuint*)&depthTex); 96 glBindTexture(GL_TEXTURE_2D, depthTex); 97 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, width, height, 98 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE,NULL); 99 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, 100 GL_NONE); 101 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 102 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 103 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 104 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 105 106 107 glGenTextures(1, (GLuint*)&stencilTex); 108 glBindTexture(GL_TEXTURE_2D, stencilTex); 109 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 110 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8,NULL); 111 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, 112 GL_NONE); 113 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 114 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 115 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 116 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 117 118 119 glGenTextures(1, (GLuint*)&losTex); 120 glBindTexture(GL_TEXTURE_2D, losTex); 121 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE16, width, height, 122 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0); 123 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 124 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 125 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 126 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 127 128 /*glGenTextures(1, (GLuint*)&lumaTex); 129 glBindTexture(GL_TEXTURE_2D, lumaTex); 130 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE16, width, height, 131 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0); 132 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 133 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 134 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 135 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);*/ 136 137 glBindTexture(GL_TEXTURE_2D, 0); 138 139 pglGenFramebuffersEXT(1, &pingFbo); 140 pglBindFramebufferEXT(GL_FRAMEBUFFER, pingFbo); 141 pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colourTex1, 0); 142 pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, losTex, 0); 143 //pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, lumaTex, 0); 144 pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, stencilTex, 0); 145 146 GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); 147 if (status != GL_FRAMEBUFFER_COMPLETE_EXT) 148 { 149 LOGWARNING(L"Framebuffer object incomplete (A): 0x%04X", status); 150 } 151 152 pglGenFramebuffersEXT(1, &pongFbo); 153 pglBindFramebufferEXT(GL_FRAMEBUFFER, pongFbo); 154 pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colourTex2, 0); 155 pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, losTex, 0); 156 //pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, lumaTex, 0); 157 pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, stencilTex, 0); 158 159 status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); 160 if (status != GL_FRAMEBUFFER_COMPLETE_EXT) 161 { 162 LOGWARNING(L"Framebuffer object incomplete (B): 0x%04X", status); 163 } 164 165 166 pglBindFramebufferEXT(GL_FRAMEBUFFER, 0); 167 } 168 169 170 void PostprocManager::CaptureRenderOutput() 171 { 172 /*glBindTexture(GL_TEXTURE_2D, colourTex1); 173 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, width, height, 0); 174 glBindTexture(GL_TEXTURE_2D, depthTex); 175 glCopyTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT, 0, 0, width, height, 0);*/ 176 //glBindTexture(GL_TEXTURE_2D, lumaTex); 177 //glCopyTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE16, 0, 0, width, height, 0); 178 179 180 // clear both FBOs and leave pingFbo selected for rendering; 181 // whichBuffer stays true at this point 182 pglBindFramebufferEXT(GL_FRAMEBUFFER, pongFbo); 183 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 184 185 GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; 186 pglDrawBuffers(2, buffers); 187 188 pglBindFramebufferEXT(GL_FRAMEBUFFER, pingFbo); 189 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 190 pglDrawBuffers(2, buffers); 191 //glClear(GL_COLOR_BUFFER_BIT); 192 193 whichBuffer = true; 194 } 195 196 197 void PostprocManager::ReleaseRenderOutput() 198 { 199 ApplyLos(); 200 201 pglBindFramebufferEXT(GL_FRAMEBUFFER, 0); 202 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 203 204 // we blit to screen from the previous buffer active 205 if (whichBuffer) 206 pglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, pingFbo); 207 else 208 pglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, pongFbo); 209 210 pglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); 211 pglBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height, 212 GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); 213 pglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); 214 215 216 217 pglBindFramebufferEXT(GL_FRAMEBUFFER, 0); 218 219 } 220 221 void PostprocManager::LoadEffect(const char* name, int stage) 222 { 223 CShaderTechniquePtr shaderTech1 = g_Renderer.GetShaderManager().LoadEffect(name); 224 225 renderStages[stage].push_back(shaderTech1); 226 227 } 228 229 void PostprocManager::ApplyEffect(CShaderTechniquePtr &shaderTech1) 230 { 231 ///CaptureRenderOutput(); 232 233 // select the other FBO for rendering 234 if (!whichBuffer) 235 pglBindFramebufferEXT(GL_FRAMEBUFFER, pingFbo); 236 else 237 pglBindFramebufferEXT(GL_FRAMEBUFFER, pongFbo); 238 239 240 241 glDisable(GL_DEPTH_TEST); 242 glDepthMask(GL_FALSE); 243 244 shaderTech1->BeginPass(); 245 CShaderProgramPtr shader = shaderTech1->GetShader(); 246 247 shader->Bind(); 248 249 // use the textures from the current FBO as input to the shader 250 if (whichBuffer) 251 shader->BindTexture("bgl_RenderedTexture", colourTex1); 252 else 253 shader->BindTexture("bgl_RenderedTexture", colourTex2); 254 255 shader->BindTexture("bgl_DepthTexture", stencilTex); 256 257 //shader->BindTexture("losTexPersp", losTex); 258 259 shader->Uniform("bgl_RenderedTextureWidth", width); 260 shader->Uniform("bgl_RenderedTextureHeight", height); 261 262 glBegin(GL_QUADS); 263 glColor4f(1.f, 1.f, 1.f, 1.f); 264 glTexCoord2f(1.0, 1.0); glVertex2f(1,1); 265 glTexCoord2f(0.0, 1.0); glVertex2f(-1,1); 266 glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1); 267 glTexCoord2f(1.0, 0.0); glVertex2f(1,-1); 268 glEnd(); 269 270 shader->Unbind(); 271 272 shaderTech1->EndPass(); 273 274 glDepthMask(GL_TRUE); 275 glEnable(GL_DEPTH_TEST); 276 277 whichBuffer = !whichBuffer; 278 } 279 280 281 282 void PostprocManager::ApplyPostproc(int stage) 283 { 284 if (!isInitialised) 285 return; 286 287 pglBindFramebufferEXT(GL_FRAMEBUFFER, pongFbo); 288 pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, 0, 0); 289 290 GLenum buffers[] = { GL_COLOR_ATTACHMENT0 }; 291 pglDrawBuffers(1, buffers); 292 293 pglBindFramebufferEXT(GL_FRAMEBUFFER, pingFbo); 294 pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, 0, 0); 295 pglDrawBuffers(1, buffers); 296 297 298 pglBindFramebufferEXT(GL_FRAMEBUFFER, pongFbo); 299 pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); 300 301 pglBindFramebufferEXT(GL_FRAMEBUFFER, pingFbo); 302 pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); 303 304 std::vector<CShaderTechniquePtr> &effects = renderStages[stage]; 305 306 //std::cout << "EFFECT!!! " << effects.size() << std::endl; 307 308 for (size_t i = 0; i < effects.size(); i++) 309 { 310 ApplyEffect(effects[i]); 311 } 312 313 pglBindFramebufferEXT(GL_FRAMEBUFFER, pongFbo); 314 pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, stencilTex, 0); 315 316 pglBindFramebufferEXT(GL_FRAMEBUFFER, pingFbo); 317 pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, stencilTex, 0); 318 } 319 320 321 void PostprocManager::ApplyLos() 322 { 323 324 325 CShaderTechniquePtr &shaderTech1 = renderStages[4][0]; 326 327 //CShaderProgramPtr shader = shaderTech1->GetShader(); 328 329 330 //ApplyEffect(shaderTech1); 331 332 333 334 if (!whichBuffer) 335 pglBindFramebufferEXT(GL_FRAMEBUFFER, pingFbo); 336 else 337 pglBindFramebufferEXT(GL_FRAMEBUFFER, pongFbo); 338 339 340 341 glDisable(GL_DEPTH_TEST); 342 glDepthMask(GL_FALSE); 343 344 shaderTech1->BeginPass(); 345 CShaderProgramPtr shader = shaderTech1->GetShader(); 346 347 shader->Bind(); 348 349 // use the textures from the current FBO as input to the shader 350 if (whichBuffer) 351 shader->BindTexture("bgl_RenderedTexture", colourTex1); 352 else 353 shader->BindTexture("bgl_RenderedTexture", colourTex2); 354 355 //shader->BindTexture("bgl_DepthTexture", stencilTex); 356 357 shader->BindTexture("losTexPersp", losTex); 358 359 shader->Uniform("bgl_RenderedTextureWidth", width); 360 shader->Uniform("bgl_RenderedTextureHeight", height); 361 362 glBegin(GL_QUADS); 363 glColor4f(1.f, 1.f, 1.f, 1.f); 364 glTexCoord2f(1.0, 1.0); glVertex2f(1,1); 365 glTexCoord2f(0.0, 1.0); glVertex2f(-1,1); 366 glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1); 367 glTexCoord2f(1.0, 0.0); glVertex2f(1,-1); 368 glEnd(); 369 370 shader->Unbind(); 371 372 shaderTech1->EndPass(); 373 374 glDepthMask(GL_TRUE); 375 glEnable(GL_DEPTH_TEST); 376 377 whichBuffer = !whichBuffer; 378 379 pglBindFramebufferEXT(GL_FRAMEBUFFER, pongFbo); 380 pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, losTex, 0); 381 382 pglBindFramebufferEXT(GL_FRAMEBUFFER, pingFbo); 383 pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, losTex, 0); 384 385 } -
source/renderer/InstancingModelRenderer.cpp
31 31 #include "graphics/LightEnv.h" 32 32 #include "graphics/Model.h" 33 33 #include "graphics/ModelDef.h" 34 #include "graphics/weldmesh.h" 34 35 35 36 #include "renderer/InstancingModelRenderer.h" 36 37 #include "renderer/Renderer.h" … … 49 50 /// Position, normals and UV are all static 50 51 VertexArray::Attribute m_Position; 51 52 VertexArray::Attribute m_Normal; 53 VertexArray::Attribute m_Tangent; 52 54 VertexArray::Attribute m_UV; 53 55 VertexArray::Attribute m_BlendJoints; // valid iff gpuSkinning == true 54 56 VertexArray::Attribute m_BlendWeights; // valid iff gpuSkinning == true … … 76 78 m_UV.type = GL_FLOAT; 77 79 m_UV.elems = 2; 78 80 m_Array.AddAttribute(&m_UV); 81 82 m_Tangent.type = GL_FLOAT; 83 m_Tangent.elems = 4; 84 m_Array.AddAttribute(&m_Tangent); 79 85 80 86 if (gpuSkinning) 81 87 { … … 87 93 m_BlendWeights.elems = 4; 88 94 m_Array.AddAttribute(&m_BlendWeights); 89 95 } 96 90 97 91 m_Array.SetNumVertices(numVertices); 98 std::vector<float> newVertices; 99 100 SModelVertex* vertices = mdef->GetVertices(); 101 102 ModelRenderer::GenTangents(mdef, newVertices); 103 104 int numVertexAttrs = 3 + 3 + 2 + 4; 105 106 int vert = newVertices.size() / numVertexAttrs; 107 108 std::vector<int> remapTable(vert); 109 std::vector<float> vertexDataIn(vert * numVertexAttrs); 110 std::vector<float> vertexDataOut(vert * numVertexAttrs); 111 112 vertexDataIn = newVertices; 113 114 int numVertices2 = WeldMesh(&remapTable[0], &vertexDataOut[0], 115 &vertexDataIn[0], vert, numVertexAttrs); 116 117 m_Array.SetNumVertices(numVertices2); 92 118 m_Array.Layout(); 93 119 94 120 VertexArrayIterator<CVector3D> Position = m_Position.GetIterator<CVector3D>(); 95 121 VertexArrayIterator<CVector3D> Normal = m_Normal.GetIterator<CVector3D>(); 96 122 VertexArrayIterator<float[2]> UVit = m_UV.GetIterator<float[2]>(); 123 VertexArrayIterator<CVector4D> Tangent = m_Tangent.GetIterator<CVector4D>(); 97 124 98 ModelRenderer::CopyPositionAndNormals(mdef, Position, Normal); 99 ModelRenderer::BuildUV(mdef, UVit); 125 for (int i = 0; i < numVertices2; i++) 126 { 127 int p = remapTable[i]; 128 129 int q = numVertexAttrs * i; 130 131 Position[i] = CVector3D(vertexDataOut[q + 0], vertexDataOut[q + 1], vertexDataOut[q + 2]); 132 133 Normal[i] = CVector3D(vertexDataOut[q + 3], vertexDataOut[q + 4], vertexDataOut[q + 5]); 134 135 UVit[i][0] = vertexDataOut[q + 6]; 136 UVit[i][1] = vertexDataOut[q + 7]; 137 138 Tangent[i] = CVector4D(vertexDataOut[q + 8], vertexDataOut[q + 9], vertexDataOut[q + 10], 139 vertexDataOut[q + 11]); 140 } 100 141 101 142 if (gpuSkinning) 102 143 { … … 118 159 119 160 m_IndexArray.SetNumVertices(mdef->GetNumFaces()*3); 120 161 m_IndexArray.Layout(); 121 ModelRenderer::BuildIndices(mdef, m_IndexArray.GetIterator()); 162 163 VertexArrayIterator<u16> Indices = m_IndexArray.GetIterator(); 164 165 size_t idxidx = 0; 166 SModelFace* faces = mdef->GetFaces(); 167 168 for (size_t j = 0; j < mdef->GetNumFaces(); ++j) { 169 Indices[idxidx++]=remapTable[j * 3 + 0]; 170 Indices[idxidx++]=remapTable[j * 3 + 1]; 171 Indices[idxidx++]=remapTable[j * 3 + 2]; 172 } 173 174 175 122 176 m_IndexArray.Upload(); 123 177 m_IndexArray.FreeBackingStore(); 124 178 } … … 211 265 if (streamflags & STREAM_UV0) 212 266 shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, stride, base + m->imodeldef->m_UV.offset); 213 267 268 shader->VertexAttribPointer("a_tangent", 4, GL_FLOAT, GL_TRUE, stride, base + m->imodeldef->m_Tangent.offset); 269 214 270 // GPU skinning requires extra attributes to compute positions/normals 215 271 if (m->gpuSkinning) 216 272 { -
source/renderer/Renderer.cpp
44 44 #include "ps/Loader.h" 45 45 #include "ps/ProfileViewer.h" 46 46 #include "graphics/Camera.h" 47 #include "graphics/LOSTexture.h" 47 48 #include "graphics/GameView.h" 48 49 #include "graphics/LightEnv.h" 49 50 #include "graphics/MaterialManager.h" … … 66 67 #include "renderer/TerrainRenderer.h" 67 68 #include "renderer/VertexBufferManager.h" 68 69 #include "renderer/WaterManager.h" 70 #include "renderer/PostprocManager.h" 69 71 70 72 71 73 /////////////////////////////////////////////////////////////////////////////////// … … 271 273 272 274 /// Shadow map 273 275 ShadowMap shadow; 276 277 PostprocManager postprocManager; 274 278 275 279 /// Various model renderers 276 280 struct Models … … 631 635 // Let component renderers perform one-time initialization after graphics capabilities and 632 636 // the shader path have been determined. 633 637 m->overlayRenderer.Initialize(); 638 639 m->postprocManager.Initialize(); 634 640 635 641 return true; 636 642 } … … 639 645 void CRenderer::Resize(int width,int height) 640 646 { 641 647 // need to recreate the shadow map object to resize the shadow texture 642 m->shadow.RecreateTexture(); 648 m->shadow.RecreateTexture(); 643 649 644 650 m_Width = width; 645 651 m_Height = height; 652 653 m->postprocManager.RecreateBuffers(); 646 654 } 647 655 648 656 ////////////////////////////////////////////////////////////////////////////////////////// … … 705 713 // SetRenderPath: Select the preferred render path. 706 714 // This may only be called before Open(), because the layout of vertex arrays and other 707 715 // data may depend on the chosen render path. 708 void CRenderer::SetRenderPath(RenderPath rp) 716 void CRenderer::SetRenderPath(RenderPath rp) 709 717 { 710 718 if (!m->IsOpen) 711 719 { … … 769 777 ////////////////////////////////////////////////////////////////////////////////////////// 770 778 // BeginFrame: signal frame start 771 779 void CRenderer::BeginFrame() 772 { 780 { 773 781 PROFILE("begin frame"); 774 782 775 783 // zero out all the per-frame stats … … 1351 1359 // RenderSubmissions: force rendering of any batched objects 1352 1360 void CRenderer::RenderSubmissions() 1353 1361 { 1354 PROFILE3("render submissions"); 1362 GetScene().GetLOSTexture().InterpolateLOS(); 1363 1364 if (GetRenderPath() == RP_SHADER) 1365 m->postprocManager.CaptureRenderOutput(); 1366 1367 PROFILE3("render submissions"); 1355 1368 1356 1369 CShaderDefines context = m->globalContext; 1357 1370 … … 1380 1393 if (m_Caps.m_Shadows && m_Options.m_Shadows && GetRenderPath() == RP_SHADER) 1381 1394 { 1382 1395 RenderShadowMap(context); 1383 } 1396 } 1384 1397 1385 1398 { 1386 1399 PROFILE3_GPU("clear buffers"); … … 1415 1428 } 1416 1429 } 1417 1430 } 1431 1418 1432 1433 RenderModels(context); 1434 ogl_WarnIfError(); 1435 1436 //if (GetRenderPath() == RP_SHADER) 1437 // m->postprocManager.ApplyPostproc(0); 1438 1419 1439 // render submitted patches and models 1420 1440 RenderPatches(context); 1421 1441 ogl_WarnIfError(); … … 1428 1448 m->overlayRenderer.RenderOverlaysBeforeWater(); 1429 1449 ogl_WarnIfError(); 1430 1450 1431 RenderModels(context);1432 ogl_WarnIfError();1433 1434 1451 // render water 1435 1452 if (m_WaterManager->m_RenderWater && g_Game && waterScissor.GetVolume() > 0) 1436 1453 { … … 1455 1472 // render debug-related terrain overlays 1456 1473 ITerrainOverlay::RenderOverlaysAfterWater(); 1457 1474 ogl_WarnIfError(); 1475 1476 if (GetRenderPath() == RP_SHADER) 1477 m->postprocManager.ApplyPostproc(1); 1458 1478 1459 1479 // render some other overlays after water (so they can be displayed on top of water) 1460 1480 m->overlayRenderer.RenderOverlaysAfterWater(); 1461 1481 ogl_WarnIfError(); 1462 1482 1463 1483 // particles are transparent so render after water 1464 1484 if (m_Options.m_Particles) 1465 1485 { 1466 1486 RenderParticles(); 1467 1487 ogl_WarnIfError(); 1468 } 1488 } 1469 1489 1470 1490 if (m_Options.m_Silhouettes) 1471 1491 { … … 1490 1510 // render overlays that should appear on top of all other objects 1491 1511 m->overlayRenderer.RenderForegroundOverlays(m_ViewCamera); 1492 1512 ogl_WarnIfError(); 1513 1514 if (GetRenderPath() == RP_SHADER) 1515 m->postprocManager.ReleaseRenderOutput(); 1493 1516 } 1494 1517 1495 1518 /////////////////////////////////////////////////////////////////////////////////////////////////// -
source/renderer/PatchRData.cpp
367 367 368 368 terrain->CalcPosition(gx, gz, dst.m_Position); 369 369 terrain->CalcNormal(gx, gz, normal); 370 dst.m_Normal = normal; 370 371 dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal); 371 372 dst.m_AlphaUVs[0] = vtx[0].m_AlphaUVs[0]; 372 373 dst.m_AlphaUVs[1] = vtx[0].m_AlphaUVs[1]; … … 374 375 375 376 terrain->CalcPosition(gx + 1, gz, dst.m_Position); 376 377 terrain->CalcNormal(gx + 1, gz, normal); 378 dst.m_Normal = normal; 377 379 dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal); 378 380 dst.m_AlphaUVs[0] = vtx[1].m_AlphaUVs[0]; 379 381 dst.m_AlphaUVs[1] = vtx[1].m_AlphaUVs[1]; … … 381 383 382 384 terrain->CalcPosition(gx + 1, gz + 1, dst.m_Position); 383 385 terrain->CalcNormal(gx + 1, gz + 1, normal); 386 dst.m_Normal = normal; 384 387 dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal); 385 388 dst.m_AlphaUVs[0] = vtx[2].m_AlphaUVs[0]; 386 389 dst.m_AlphaUVs[1] = vtx[2].m_AlphaUVs[1]; … … 388 391 389 392 terrain->CalcPosition(gx, gz + 1, dst.m_Position); 390 393 terrain->CalcNormal(gx, gz + 1, normal); 394 dst.m_Normal = normal; 391 395 dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal); 392 396 dst.m_AlphaUVs[0] = vtx[3].m_AlphaUVs[0]; 393 397 dst.m_AlphaUVs[1] = vtx[3].m_AlphaUVs[1]; … … 546 550 // for all vertices, it need not be stored in the vertex structure) 547 551 CVector3D normal; 548 552 terrain->CalcNormal(ix,iz,normal); 553 554 vertices[v].m_Normal = normal; 549 555 550 556 vertices[v].m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal); 551 557 } … … 747 753 if (itt->first) 748 754 { 749 755 shader->BindTexture("baseTex", itt->first->GetTexture()); 756 757 shader->Uniform("hasNormalMap", itt->first->GetNormal() ? CVector3D(1,0,0) : CVector3D(0,0,0)); 758 shader->Uniform("hasSpecularMap", itt->first->GetSpecular() ? CVector3D(1,0,0) : CVector3D(0,0,0)); 759 760 if (itt->first->GetNormal()) 761 shader->BindTexture("normTex", itt->first->GetNormal()); 762 763 if (itt->first->GetSpecular()) 764 shader->BindTexture("specTex", itt->first->GetSpecular()); 750 765 751 766 #if !CONFIG2_GLES 752 767 if (isDummyShader) … … 774 789 SBaseVertex *base = (SBaseVertex *)itv->first->Bind(); 775 790 shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]); 776 791 shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, &base->m_DiffuseColor); 792 shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]); 777 793 shader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, &base->m_Position[0]); 778 794 779 795 shader->AssertPointersBound(); … … 932 948 if (itt->m_Texture) 933 949 { 934 950 shader->BindTexture("baseTex", itt->m_Texture->GetTexture()); 951 952 shader->Uniform("hasNormalMap", itt->m_Texture->GetNormal() ? CVector3D(1,0,0) : CVector3D(0,0,0)); 953 shader->Uniform("hasSpecularMap", itt->m_Texture->GetSpecular() ? CVector3D(1,0,0) : CVector3D(0,0,0)); 954 955 if (itt->m_Texture->GetNormal()) 956 shader->BindTexture("normTex", itt->m_Texture->GetNormal()); 957 958 if (itt->m_Texture->GetSpecular()) 959 shader->BindTexture("specTex", itt->m_Texture->GetSpecular()); 960 935 961 936 962 #if !CONFIG2_GLES 937 963 if (isDummyShader) … … 965 991 966 992 shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]); 967 993 shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, &base->m_DiffuseColor); 994 shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]); 968 995 shader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, &base->m_Position[0]); 969 996 shader->TexCoordPointer(GL_TEXTURE1, 2, GL_FLOAT, stride, &base->m_AlphaUVs[0]); 970 997 } -
source/renderer/RenderModifiers.cpp
95 95 if (shader->GetTextureBinding("losTex").Active()) 96 96 { 97 97 CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture(); 98 shader->BindTexture("losTex", los.GetTexture ());98 shader->BindTexture("losTex", los.GetTextureSmooth()); 99 99 // Don't bother sending the whole matrix, we just need two floats (scale and translation) 100 100 shader->Uniform("losTransform", los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); 101 101 } … … 104 104 m_BindingShadingColor = shader->GetUniformBinding("shadingColor"); 105 105 m_BindingPlayerColor = shader->GetUniformBinding("playerColor"); 106 106 m_BindingBaseTex = shader->GetTextureBinding("baseTex"); 107 m_BindingNormTex = shader->GetTextureBinding("normTex"); 108 m_BindingSpecTex = shader->GetTextureBinding("specTex"); 107 109 } 108 110 109 111 void ShaderRenderModifier::PrepareTexture(const CShaderProgramPtr& shader, CTexture& texture) … … 112 114 shader->BindTexture(m_BindingBaseTex, texture.GetHandle()); 113 115 } 114 116 117 void ShaderRenderModifier::PrepareNormal(const CShaderProgramPtr& shader, CTexture& normal) 118 { 119 if (m_BindingNormTex.Active()) 120 shader->BindTexture(m_BindingNormTex, normal.GetHandle()); 121 } 122 123 void ShaderRenderModifier::PrepareSpecular(const CShaderProgramPtr& shader, CTexture& specular) 124 { 125 if (m_BindingSpecTex.Active()) 126 shader->BindTexture(m_BindingSpecTex, specular.GetHandle()); 127 } 128 115 129 void ShaderRenderModifier::PrepareModel(const CShaderProgramPtr& shader, CModel* model) 116 130 { 117 131 if (m_BindingInstancingTransform.Active()) -
source/renderer/ShadowMap.cpp
83 83 // Copy of renderer's standard view camera, saved between 84 84 // BeginRender and EndRender while we replace it with the shadow camera 85 85 CCamera SavedViewCamera; 86 87 // Save the caller's FBO so it can be restored 88 GLint originalFBO; 86 89 87 90 // Helper functions 88 91 void CalcShadowMatrices(); … … 318 321 pglDeleteFramebuffersEXT(1, &Framebuffer); 319 322 Framebuffer = 0; 320 323 } 324 325 // save the caller's FBO 326 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &originalFBO); 321 327 322 328 pglGenFramebuffersEXT(1, &Framebuffer); 323 329 … … 433 439 434 440 GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); 435 441 436 pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);442 pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, originalFBO); 437 443 438 444 if (status != GL_FRAMEBUFFER_COMPLETE_EXT) 439 445 { … … 451 457 { 452 458 // HACK HACK: this depends in non-obvious ways on the behaviour of the caller 453 459 460 // save caller's FBO 461 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m->originalFBO); 462 454 463 // Calc remaining shadow matrices 455 464 m->CalcShadowMatrices(); 456 465 … … 502 511 503 512 { 504 513 PROFILE("unbind framebuffer"); 505 pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);514 pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m->originalFBO); 506 515 } 507 516 508 517 glViewport(0, 0, g_Renderer.GetWidth(), g_Renderer.GetHeight()); -
source/renderer/MikktspaceWrap.cpp
1 2 #include "precompiled.h" 3 4 #include <boost/bind.hpp> 5 6 #include "graphics/Color.h" 7 #include "graphics/LightEnv.h" 8 #include "graphics/Model.h" 9 #include "graphics/ModelDef.h" 10 #include "graphics/ShaderManager.h" 11 #include "graphics/TextureManager.h" 12 #include <graphics/mikktspace.h> 13 14 #include <renderer/MikktspaceWrap.h> 15 16 17 18 MikkTSpace::MikkTSpace(const CModelDefPtr& m, std::vector<float>& v) : model(m), newVertices(v) 19 { 20 interface.m_getNumFaces = getNumFaces; 21 interface.m_getNumVerticesOfFace = getNumVerticesOfFace; 22 interface.m_getPosition = getPosition; 23 interface.m_getNormal = getNormal; 24 interface.m_getTexCoord = getTexCoord; 25 interface.m_setTSpaceBasic = NULL; 26 interface.m_setTSpace = setTSpace; 27 28 context.m_pInterface = &interface; 29 context.m_pUserData = (void*)this; 30 } 31 32 void MikkTSpace::generate() 33 { 34 genTangSpaceDefault(&context); 35 } 36 37 38 int MikkTSpace::getNumFaces(const SMikkTSpaceContext *pContext) 39 { 40 return ((MikkTSpace*)pContext->m_pUserData)->model->GetNumFaces(); 41 } 42 43 44 int MikkTSpace::getNumVerticesOfFace(const SMikkTSpaceContext *pContext, const int iFace) 45 { 46 return 3; 47 } 48 49 50 void MikkTSpace::getPosition(const SMikkTSpaceContext *pContext, 51 float fvPosOut[], const int iFace, const int iVert) 52 { 53 SModelFace &face = ((MikkTSpace*)pContext->m_pUserData)->model->GetFaces()[iFace]; 54 long i = face.m_Verts[iVert]; 55 const CVector3D &p = ((MikkTSpace*)pContext->m_pUserData)->model->GetVertices()[i].m_Coords; 56 57 fvPosOut[0] = p.X; 58 fvPosOut[1] = p.Y; 59 fvPosOut[2] = p.Z; 60 } 61 62 63 void MikkTSpace::getNormal(const SMikkTSpaceContext *pContext, 64 float fvNormOut[], const int iFace, const int iVert) 65 { 66 SModelFace &face = ((MikkTSpace*)pContext->m_pUserData)->model->GetFaces()[iFace]; 67 long i = face.m_Verts[iVert]; 68 const CVector3D &n = ((MikkTSpace*)pContext->m_pUserData)->model->GetVertices()[i].m_Norm; 69 70 fvNormOut[0] = n.X; 71 fvNormOut[1] = n.Y; 72 fvNormOut[2] = n.Z; 73 } 74 75 76 void MikkTSpace::getTexCoord(const SMikkTSpaceContext *pContext, 77 float fvTexcOut[], const int iFace, const int iVert) 78 { 79 SModelFace &face = ((MikkTSpace*)pContext->m_pUserData)->model->GetFaces()[iFace]; 80 long i = face.m_Verts[iVert]; 81 SModelVertex &v = ((MikkTSpace*)pContext->m_pUserData)->model->GetVertices()[i]; 82 83 fvTexcOut[0] = v.m_U; 84 fvTexcOut[1] = 1.0-v.m_V; 85 } 86 87 88 void MikkTSpace::setTSpace(const SMikkTSpaceContext * pContext, const float fvTangent[], 89 const float fvBiTangent[], const float fMagS, const float fMagT, 90 const tbool bIsOrientationPreserving, const int iFace, const int iVert) 91 { 92 SModelFace &face = ((MikkTSpace*)pContext->m_pUserData)->model->GetFaces()[iFace]; 93 long i = face.m_Verts[iVert]; 94 95 const CVector3D &p = ((MikkTSpace*)pContext->m_pUserData)->model->GetVertices()[i].m_Coords; 96 const CVector3D &n = ((MikkTSpace*)pContext->m_pUserData)->model->GetVertices()[i].m_Norm; 97 const float u = ((MikkTSpace*)pContext->m_pUserData)->model->GetVertices()[i].m_U; 98 const float v = 1.0 - ((MikkTSpace*)pContext->m_pUserData)->model->GetVertices()[i].m_V; 99 100 ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(p.X); 101 ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(p.Y); 102 ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(p.Z); 103 104 ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(n.X); 105 ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(n.Y); 106 ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(n.Z); 107 108 ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(u); 109 ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(v); 110 111 ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(fvTangent[0]); 112 ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(fvTangent[1]); 113 ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(fvTangent[2]); 114 ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(bIsOrientationPreserving > 0.5 ? 1.0f : (-1.0f)); 115 } 116 117 118 -
source/renderer/TerrainRenderer.cpp
477 477 shader->Uniform("sunColor", lightEnv.m_SunColor); 478 478 479 479 CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture(); 480 shader->BindTexture("losTex", los.GetTexture ());480 shader->BindTexture("losTex", los.GetTextureSmooth()); 481 481 shader->Uniform("losTransform", los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); 482 482 483 483 shader->Uniform("ambient", lightEnv.m_TerrainAmbientColor); … … 709 709 m->fancyWaterShader->BindTexture("reflectionMap", WaterMgr->m_ReflectionTexture); 710 710 m->fancyWaterShader->BindTexture("refractionMap", WaterMgr->m_RefractionTexture); 711 711 712 m->fancyWaterShader->BindTexture("losMap", losTexture.GetTexture ());712 m->fancyWaterShader->BindTexture("losMap", losTexture.GetTextureSmooth()); 713 713 714 714 const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); 715 715 m->fancyWaterShader->Uniform("ambient", lightEnv.m_TerrainAmbientColor); -
source/renderer/ModelRenderer.h
253 253 static void BuildIndices( 254 254 const CModelDefPtr& mdef, 255 255 const VertexArrayIterator<u16>& Indices); 256 257 258 static void GenTangents(const CModelDefPtr& mdef, std::vector<float>& newVertices); 256 259 }; 257 260 258 261 -
binaries/data/mods/public/maps/scenarios/Hellenised_Egypt.xml
4 4 <Environment> 5 5 <LightingModel>standard</LightingModel> 6 6 <SkySet>sunny 1</SkySet> 7 <SunColour r="0. 776471" g="0.756863" b="0.67451"/>7 <SunColour r="0.658824" g="0.643137" b="0.572549"/> 8 8 <SunElevation angle="0.877437"/> 9 9 <SunRotation angle="-0.824594"/> 10 <TerrainAmbientColour r="0. 313726" g="0.376471" b="0.521569"/>11 <UnitsAmbientColour r="0. 501961" g="0.501961" b="0.501961"/>10 <TerrainAmbientColour r="0.235294" g="0.282353" b="0.388235"/> 11 <UnitsAmbientColour r="0.4" g="0.4" b="0.4"/> 12 12 <Water> 13 13 <WaterBody> 14 14 <Type>default</Type> … … 24 24 </Water> 25 25 </Environment> 26 26 <Camera> 27 <Position x="3 22.034" y="134.957" z="324.278"/>28 <Rotation angle=" 0"/>27 <Position x="380.081" y="159.73" z="434.628"/> 28 <Rotation angle="-1.41128"/> 29 29 <Declination angle="0.610865"/> 30 30 </Camera> 31 31 <ScriptSettings><![CDATA[ -
binaries/data/mods/public/art/materials/player_trans_norm.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <material> 3 <shader effect="model_norm"/> 4 <define name="USE_PLAYERCOLOR" value="1"/> 5 </material> -
binaries/data/mods/public/art/textures/terrain/types/biome-desert/desert_city_tile_pers_dirt.xml
3 3 <!DOCTYPE Terrains SYSTEM "/art/textures/terrain/types/terrains.dtd"> 4 4 5 5 <Terrains> 6 <Terrain angle="0.0" size="64.0" />6 <Terrain angle="0.0" size="64.0" normalmap="art/textures/terrain/types/biome-desert/desert_city_tile_pers_dirt_norm.png"/> 7 7 </Terrains> -
binaries/data/mods/public/art/textures/terrain/types/snow/snow
1 <?xml version="1.0" encoding="iso-8859-1" standalone="no"?> 2 3 <!DOCTYPE Terrains SYSTEM "/art/textures/terrain/types/terrains.dtd"> 4 5 <Terrains> 6 <Terrain normalmap="art/textures/terrain/types/snow/snow grass 2_norm.png" specularmap="art/textures/terrain/types/snow/snow grass 2_spec.png"/> 7 </Terrains> -
binaries/data/mods/public/art/particles/rain.xml
6 6 7 7 <start_full/> 8 8 9 <constant name="emissionrate" value="300 .0"/>9 <constant name="emissionrate" value="3000.0"/> 10 10 <uniform name="lifetime" min="4.0" max="5.0"/> 11 11 12 12 <uniform name="position.x" min="-50.0" max="50.0"/> -
binaries/data/mods/public/art/actors/structures/romans/civic_centre.xml
15 15 <prop actor="props/units/weapons/arrow_front.xml" attachpoint="projectile"/> 16 16 </props> 17 17 <texture>structural/rome_struct.png</texture> 18 <normal>structural/rome_struct_norm.png</normal> 19 <specular>structural/rome_struct_spec.png</specular> 18 20 </variant> 19 21 </group> 20 22 <group> … … 36 38 </props> 37 39 </variant> 38 40 </group> 39 <material>player_trans .xml</material>41 <material>player_trans_norm.xml</material> 40 42 </actor> -
binaries/data/mods/public/art/actors/structures/romans/triumphal_arch.xml
5 5 <variant frequency="100" name="Roman Triumphal Arch"> 6 6 <mesh>structural/rome_arch.dae</mesh> 7 7 <texture>structural/rome_struct_arch.dds</texture> 8 <normal>structural/rome_struct_arch_norm.png</normal> 9 <specular>structural/rome_struct_arch_spec.png</specular> 8 10 </variant> 9 11 </group> 10 12 <group> … … 17 19 </props> 18 20 </variant> 19 21 </group> 20 <material>player_trans .xml</material>22 <material>player_trans_norm.xml</material> 21 23 </actor> -
binaries/data/mods/public/shaders/effects/model_norm.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <effect> 3 4 <technique> 5 <require context="MODE_SHADOWCAST || MODE_SILHOUETTEOCCLUDER"/> 6 <require shaders="arb"/> 7 <pass shader="arb/model_solid"/> 8 </technique> 9 10 <technique> 11 <require context="MODE_SHADOWCAST || MODE_SILHOUETTEOCCLUDER"/> 12 <require shaders="glsl"/> 13 <pass shader="glsl/model_solid"/> 14 </technique> 15 16 <technique> 17 <require context="MODE_SHADOWCAST || MODE_SILHOUETTEOCCLUDER"/> 18 <require shaders="fixed"/> 19 <define name="USE_PLAYERCOLOR" value="0"/> 20 <define name="USE_OBJECTCOLOR" value="0"/> 21 <pass shader="fixed:model_solid"/> 22 </technique> 23 24 25 <technique> 26 <require context="MODE_SILHOUETTEDISPLAY || MODE_WIREFRAME"/> 27 <require shaders="arb"/> 28 <pass shader="arb/model_solid_player"/> 29 </technique> 30 31 <technique> 32 <require context="MODE_SILHOUETTEDISPLAY || MODE_WIREFRAME"/> 33 <require shaders="glsl"/> 34 <pass shader="glsl/model_solid_player"/> 35 </technique> 36 37 <technique> 38 <require context="MODE_SILHOUETTEDISPLAY || MODE_WIREFRAME"/> 39 <require shaders="fixed"/> 40 <define name="USE_PLAYERCOLOR" value="1"/> 41 <define name="USE_OBJECTCOLOR" value="0"/> 42 <pass shader="fixed:model_solid"/> 43 </technique> 44 45 46 <technique> 47 <require shaders="arb"/> 48 <pass shader="arb/model_common"/> 49 </technique> 50 51 <technique> 52 <require shaders="glsl"/> 53 <pass shader="glsl/model_common_norm"/> 54 </technique> 55 56 <technique> 57 <require context="USE_PLAYERCOLOR || USE_OBJECTCOLOR"/> 58 <require shaders="fixed"/> 59 <pass shader="fixed:model_color"/> 60 </technique> 61 62 <technique> 63 <require shaders="fixed"/> 64 <pass shader="fixed:model"/> 65 </technique> 66 67 </effect> -
binaries/data/mods/public/shaders/effects/los.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <effect> 3 4 <technique> 5 <require shaders="glsl"/> 6 <pass shader="glsl/los"/> 7 </technique> 8 9 </effect> -
binaries/data/mods/public/shaders/effects/ssao.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <effect> 3 4 <technique> 5 <require shaders="glsl"/> 6 <pass shader="glsl/ssao"/> 7 </technique> 8 9 </effect> -
binaries/data/mods/public/shaders/effects/bloom.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <effect> 3 4 <technique> 5 <require shaders="glsl"/> 6 <pass shader="glsl/bloom"/> 7 </technique> 8 9 </effect> -
binaries/data/mods/public/shaders/effects/fog.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <effect> 3 4 <technique> 5 <require shaders="glsl"/> 6 <pass shader="glsl/fog"/> 7 </technique> 8 9 </effect> -
binaries/data/mods/public/shaders/effects/hdr.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <effect> 3 4 <technique> 5 <require shaders="glsl"/> 6 <pass shader="glsl/hdr"/> 7 </technique> 8 9 </effect> -
binaries/data/mods/public/shaders/effects/los_interp.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <effect> 3 4 <technique> 5 <require shaders="glsl"/> 6 <pass shader="glsl/los_interp"/> 7 </technique> 8 9 </effect> -
binaries/data/mods/public/shaders/glsl/terrain_common.fs
1 1 #version 120 2 2 3 3 uniform sampler2D baseTex; 4 uniform sampler2D normTex; 5 uniform sampler2D specTex; 4 6 uniform sampler2D blendTex; 5 7 uniform sampler2D losTex; 6 8 … … 17 19 18 20 uniform vec3 shadingColor; 19 21 uniform vec3 ambient; 22 uniform vec3 sunDir; 20 23 24 uniform vec3 sunColor; 25 26 uniform vec3 hasNormalMap; 27 uniform vec3 hasSpecularMap; 28 21 29 varying vec3 v_lighting; 22 30 varying vec2 v_tex; 23 31 varying vec4 v_shadow; 24 32 varying vec2 v_los; 25 33 varying vec2 v_blend; 34 varying vec3 v_normal; 26 35 36 //varying float depth; 37 38 varying vec3 v_half; 39 27 40 #if USE_SPECULAR 28 41 uniform float specularPower; 29 42 uniform vec3 specularColor; … … 40 53 vec4 size = vec4(offset + 1.0, 2.0 - offset); 41 54 vec4 weight = (vec4(2.0 - 1.0 / size.xy, 1.0 / size.zw - 1.0) + (v_shadow.xy - offset).xyxy) * shadowScale.zwzw; 42 55 return (1.0/9.0)*dot(size.zxzx*size.wwyy, 43 vec4(shadow2D(shadowTex, vec3(weight.zw, v_shadow.z)). a,44 shadow2D(shadowTex, vec3(weight.xw, v_shadow.z)). a,45 shadow2D(shadowTex, vec3(weight.zy, v_shadow.z)). a,46 shadow2D(shadowTex, vec3(weight.xy, v_shadow.z)). a));56 vec4(shadow2D(shadowTex, vec3(weight.zw, v_shadow.z)).r, 57 shadow2D(shadowTex, vec3(weight.xw, v_shadow.z)).r, 58 shadow2D(shadowTex, vec3(weight.zy, v_shadow.z)).r, 59 shadow2D(shadowTex, vec3(weight.xy, v_shadow.z)).r)); 47 60 #else 48 return shadow2D(shadowTex, v_shadow.xyz). a;61 return shadow2D(shadowTex, v_shadow.xyz).r; 49 62 #endif 50 63 #else 51 64 if (v_shadow.z >= 1.0) … … 57 70 #endif 58 71 } 59 72 73 vec3 apply_fog(vec3 colour) 74 { 75 vec3 fogColour = vec3(0.6, 0.6, 0.65); 76 float fogDistance = 300; 77 float fogMax = 0.7; 78 79 float depth = (gl_FragCoord.z / gl_FragCoord.w) / 2 + 0.5; 80 81 float rec = 1.0 / (1.0 - fogDistance); 82 83 float factor = 1.0 - (depth - fogDistance) * rec; 84 85 factor = min(factor, fogMax); 86 87 return mix(colour, fogColour, factor); 88 } 89 60 90 void main() 61 91 { 62 92 #if BLEND 63 93 // Use alpha from blend texture 64 gl_Frag Color.a = 1.0 - texture2D(blendTex, v_blend).a;94 gl_FragData[0].a = 1.0 - texture2D(blendTex, v_blend).a; 65 95 #endif 66 96 67 97 vec4 tex = texture2D(baseTex, v_tex); 68 98 69 99 #if DECAL 70 100 // Use alpha from main texture 71 gl_Frag Color.a = tex.a;101 gl_FragData[0].a = tex.a; 72 102 #endif 73 103 74 104 vec3 texdiffuse = tex.rgb; … … 83 113 vec3 specular = vec3(0.0); 84 114 #endif 85 115 86 vec3 color = (texdiffuse * sundiffuse + specular) * get_shadow() + texdiffuse * ambient; 116 vec3 bump = sundiffuse; 117 if (hasNormalMap.x > 0.5) 118 { 119 vec3 t = vec3(1, 0, 0); 120 t = normalize(t - v_normal * dot(v_normal, t)); 121 vec3 b = cross(v_normal, t); 122 //vec3 b = vec3(0, 0, 1); 123 //b = normalize(b - v_normal * dot(v_normal, b)); 87 124 125 126 mat3 tbn = transpose(mat3(t, b, v_normal)); 127 vec3 ntex = texture2D(normTex, v_tex).rgb * 2.0 - 1.0; 128 vec3 vNout = normalize(ntex * tbn); 129 130 131 bump = vec3(max (dot (-sunDir, vNout), 0.0)) * sunColor; 132 133 vec4 specColour = vec4(1.0); 134 135 if (hasSpecularMap.x > 0.5) 136 { 137 specColour = texture2D(specTex, v_tex); 138 specular = specColour.xyz * sunColor * pow(max(0.0, dot(normalize(vNout), v_half)), 12); 139 } 140 } 141 142 143 //vec3 specular; 144 145 146 147 148 vec3 color = (texdiffuse + specular) * bump * get_shadow() + texdiffuse * ambient; 149 150 151 //color = apply_fog(color); 152 153 88 154 float los = texture2D(losTex, v_los).a; 89 color *= los; 155 ///color *= los; 156 gl_FragData[1].rgb = los; 157 90 158 91 159 #if DECAL 92 160 color *= shadingColor; 93 161 #endif 94 162 95 gl_Frag Color.rgb = color;163 gl_FragData[0].rgb = color; 96 164 } -
binaries/data/mods/public/shaders/glsl/hdr.fs
1 #version 110 2 3 varying vec2 v_tex; 4 5 uniform sampler2D bgl_RenderedTexture; 6 uniform sampler2D bgl_DepthTexture; 7 uniform sampler2D bgl_LuminanceTexture; 8 uniform float bgl_RenderedTextureWidth; 9 uniform float bgl_RenderedTextureHeight; 10 11 #define PI 3.14159265 12 13 float width = bgl_RenderedTextureWidth; //texture width 14 float height = bgl_RenderedTextureHeight; //texture height 15 16 vec2 texCoord = v_tex; 17 vec2 texcoord = v_tex; 18 19 20 float avgL = 0.7; 21 float HDRamount = 0.1; 22 23 void main(void) 24 { 25 //gl_FragColor = texture2D(bgl_RenderedTexture, texcoord); 26 //return; 27 28 float contrast = avgL; 29 float brightness = avgL * HDRamount; 30 31 vec4 value = texture2D(bgl_RenderedTexture, texcoord); 32 33 //value *= 0.5; 34 35 gl_FragColor = (value/contrast)-brightness; 36 } 37 38 -
binaries/data/mods/public/shaders/glsl/los.vs
1 #version 110 2 3 uniform mat4 transform; 4 uniform vec2 losTransform; 5 6 varying vec2 v_tex; 7 8 attribute vec3 a_vertex; 9 attribute vec2 a_uv0; 10 11 12 varying vec2 v_los; 13 14 void main() 15 { 16 gl_Position = gl_Vertex; 17 18 v_los = position.xz * losTransform.x + losTransform.y; 19 20 v_tex = vec2(gl_MultiTexCoord0); 21 } -
binaries/data/mods/public/shaders/glsl/model_common_norm.vs
1 #if USE_GPU_SKINNING 2 // Skinning requires GLSL 1.30 for ivec4 vertex attributes 3 #version 130 4 #else 5 #version 120 6 #endif 7 8 uniform mat4 transform; 9 uniform vec3 cameraPos; 10 uniform vec3 sunDir; 11 uniform vec3 sunColor; 12 uniform vec2 losTransform; 13 uniform mat4 shadowTransform; 14 uniform mat4 instancingTransform; 15 16 //varying vec3 v_lighting; 17 varying vec2 v_tex; 18 varying vec4 v_shadow; 19 varying vec2 v_los; 20 21 //#if USE_SPECULAR 22 varying vec3 v_half; 23 //#endif 24 25 attribute vec3 a_vertex; 26 attribute vec3 a_normal; 27 attribute vec2 a_uv0; 28 29 attribute vec4 a_tangent; 30 31 32 33 #if USE_GPU_SKINNING 34 const int MAX_INFLUENCES = 4; 35 const int MAX_BONES = 64; 36 uniform mat4 skinBlendMatrices[MAX_BONES]; 37 attribute ivec4 a_skinJoints; 38 attribute vec4 a_skinWeights; 39 #endif 40 41 varying vec4 debugx; 42 43 44 45 46 //varying vec3 lightVec; 47 varying vec3 eyeVec; 48 49 varying vec3 v_normal; 50 varying vec4 v_tangent; 51 varying vec3 v_bitangent; 52 53 54 55 //varying float sign; 56 57 58 void main() 59 { 60 #if USE_GPU_SKINNING 61 vec3 p = vec3(0.0); 62 vec3 n = vec3(0.0); 63 for (int i = 0; i < MAX_INFLUENCES; ++i) { 64 int joint = a_skinJoints[i]; 65 if (joint != 0xff) { 66 mat4 m = skinBlendMatrices[joint]; 67 p += vec3(m * vec4(a_vertex, 1.0)) * a_skinWeights[i]; 68 n += vec3(m * vec4(a_normal, 0.0)) * a_skinWeights[i]; 69 } 70 } 71 vec4 position = instancingTransform * vec4(p, 1.0); 72 vec3 normal = mat3(instancingTransform) * normalize(n); 73 #else 74 #if USE_INSTANCING 75 vec4 position = instancingTransform * vec4(a_vertex, 1.0); 76 vec3 normal = mat3(instancingTransform) * a_normal; 77 vec4 tangent = vec4(mat3(instancingTransform) * a_tangent.xyz, a_tangent.w); 78 #else 79 vec4 position = vec4(a_vertex, 1.0); 80 vec3 normal = a_normal; 81 vec4 tangent = a_tangent; 82 #endif 83 #endif 84 85 gl_Position = transform * position; 86 87 88 89 eyeVec = cameraPos.xyz - position.xyz; 90 //lightVec = -sunDir; 91 92 93 94 95 vec3 sunVec = -sunDir; 96 97 v_half = normalize(sunVec + eyeVec); 98 99 100 v_normal = normal; 101 v_tangent = tangent;//.xyz; 102 //sign = tangent.w; 103 v_bitangent = cross(v_normal, v_tangent); 104 105 106 //v_lighting = max(0.0, dot(normal, -sunDir)) * sunColor; 107 v_tex = a_uv0; 108 v_shadow = shadowTransform * position; 109 v_los = position.xz * losTransform.x + losTransform.y; 110 } -
binaries/data/mods/public/shaders/glsl/ssao.vs
1 #version 110 2 3 uniform mat4 transform; 4 5 varying vec2 v_tex; 6 7 attribute vec3 a_vertex; 8 attribute vec2 a_uv0; 9 10 void main() 11 { 12 gl_Position = gl_Vertex; 13 14 v_tex = vec2(gl_MultiTexCoord0); 15 } -
binaries/data/mods/public/shaders/glsl/los.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <program type="glsl"> 3 4 <vertex file="glsl/bloom.vs"> 5 <stream name="pos"/> 6 <stream name="uv0"/> 7 <attrib name="a_vertex" semantics="gl_Vertex"/> 8 <attrib name="a_uv0" semantics="gl_MultiTexCoord0"/> 9 </vertex> 10 11 <fragment file="glsl/los.fs"/> 12 13 </program> -
binaries/data/mods/public/shaders/glsl/terrain_base.xml
6 6 <stream name="color"/> 7 7 <stream name="uv0"/> 8 8 <attrib name="a_vertex" semantics="gl_Vertex"/> 9 <attrib name="a_normal" semantics="gl_Normal"/> 9 10 <attrib name="a_color" semantics="gl_Color"/> 10 11 <attrib name="a_uv0" semantics="gl_MultiTexCoord0"/> 11 12 </vertex> -
binaries/data/mods/public/shaders/glsl/model_common_norm.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <program type="glsl"> 3 4 <vertex file="glsl/model_common_norm.vs"> 5 <stream name="pos"/> 6 <stream name="normal"/> 7 <stream name="uv0"/> 8 <attrib name="a_vertex" semantics="gl_Vertex"/> 9 <attrib name="a_normal" semantics="gl_Normal"/> 10 <attrib name="a_uv0" semantics="gl_MultiTexCoord0"/> 11 <attrib name="a_tangent" semantics="CustomAttribute2"/> 12 </vertex> 13 14 <fragment file="glsl/model_common_norm.fs"/> 15 16 </program> -
binaries/data/mods/public/shaders/glsl/terrain_common.vs
17 17 varying vec4 v_shadow; 18 18 varying vec2 v_los; 19 19 varying vec2 v_blend; 20 varying vec3 v_normal; 21 //varying float depth; 20 22 23 varying vec3 v_half; 24 21 25 #if USE_SPECULAR 22 26 varying vec3 v_normal; 23 27 varying vec3 v_half; 24 28 #endif 25 29 26 30 attribute vec3 a_vertex; 31 attribute vec3 a_normal; 27 32 attribute vec3 a_color; 28 33 attribute vec2 a_uv0; 29 34 attribute vec2 a_uv1; … … 34 39 35 40 gl_Position = transform * position; 36 41 42 //depth = gl_Position.z / gl_Position.w; 43 37 44 v_lighting = a_color * sunColor; 45 46 //v_lighting = dot(-sunDir, a_normal) * sunColor; 47 48 //v_lighting = sunColor; 38 49 39 50 #if DECAL 40 51 v_tex = a_uv0; … … 72 83 v_normal = normal; 73 84 #endif 74 85 86 vec3 eyeVec = cameraPos.xyz - position.xyz; 87 88 89 vec3 sunVec = -sunDir; 90 91 v_half = normalize(sunVec + eyeVec); 92 93 v_normal = a_normal; 94 75 95 v_los = a_vertex.xz * losTransform.x + losTransform.yy; 76 96 } -
binaries/data/mods/public/shaders/glsl/ssao.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <program type="glsl"> 3 4 <vertex file="glsl/ssao.vs"> 5 <stream name="pos"/> 6 <stream name="uv0"/> 7 <attrib name="a_vertex" semantics="gl_Vertex"/> 8 <attrib name="a_uv0" semantics="gl_MultiTexCoord0"/> 9 </vertex> 10 11 <fragment file="glsl/ssao.fs"/> 12 13 </program> -
binaries/data/mods/public/shaders/glsl/hdr.vs
1 #version 110 2 3 uniform mat4 transform; 4 5 varying vec2 v_tex; 6 7 attribute vec3 a_vertex; 8 attribute vec2 a_uv0; 9 10 void main() 11 { 12 gl_Position = gl_Vertex; 13 14 v_tex = vec2(gl_MultiTexCoord0); 15 } -
binaries/data/mods/public/shaders/glsl/bloom.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <program type="glsl"> 3 4 <vertex file="glsl/bloom.vs"> 5 <stream name="pos"/> 6 <stream name="uv0"/> 7 <attrib name="a_vertex" semantics="gl_Vertex"/> 8 <attrib name="a_uv0" semantics="gl_MultiTexCoord0"/> 9 </vertex> 10 11 <fragment file="glsl/bloom.fs"/> 12 13 </program> -
binaries/data/mods/public/shaders/glsl/terrain_blend.xml
10 10 <stream name="uv1"/> 11 11 <attrib name="a_vertex" semantics="gl_Vertex"/> 12 12 <attrib name="a_color" semantics="gl_Color"/> 13 <attrib name="a_normal" semantics="gl_Normal"/> 13 14 <attrib name="a_uv0" semantics="gl_MultiTexCoord0"/> 14 15 <attrib name="a_uv1" semantics="gl_MultiTexCoord1"/> 15 16 </vertex> -
binaries/data/mods/public/shaders/glsl/hdr.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <program type="glsl"> 3 4 <vertex file="glsl/hdr.vs"> 5 <stream name="pos"/> 6 <stream name="uv0"/> 7 <attrib name="a_vertex" semantics="gl_Vertex"/> 8 <attrib name="a_uv0" semantics="gl_MultiTexCoord0"/> 9 </vertex> 10 11 <fragment file="glsl/hdr.fs"/> 12 13 </program> -
binaries/data/mods/public/shaders/glsl/los_interp.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <program type="glsl"> 3 4 <vertex file="glsl/los_interp.vs"> 5 <stream name="pos"/> 6 <stream name="uv0"/> 7 <attrib name="a_vertex" semantics="gl_Vertex"/> 8 <attrib name="a_uv0" semantics="gl_MultiTexCoord0"/> 9 </vertex> 10 11 <fragment file="glsl/los_interp.fs"/> 12 13 </program> -
binaries/data/mods/public/shaders/glsl/bloom.fs
1 #version 110 2 3 varying vec2 v_tex; 4 5 uniform sampler2D bgl_RenderedTexture; 6 uniform sampler2D bgl_DepthTexture; 7 uniform sampler2D bgl_LuminanceTexture; 8 uniform float bgl_RenderedTextureWidth; 9 uniform float bgl_RenderedTextureHeight; 10 11 #define PI 3.14159265 12 13 float width = bgl_RenderedTextureWidth; //texture width 14 float height = bgl_RenderedTextureHeight; //texture height 15 16 vec2 texCoord = v_tex; 17 vec2 texcoord = v_tex; 18 19 20 float BRIGHT_PASS_THRESHOLD = 0.6; 21 float BRIGHT_PASS_OFFSET = 0.6; 22 23 #define blurclamp 0.0015 24 #define bias 0.01 25 26 #define KERNEL_SIZE 3.0 27 28 29 30 vec4 bright(vec2 coo) 31 { 32 vec4 color = texture2D(bgl_RenderedTexture, coo); 33 34 color = max(color - BRIGHT_PASS_THRESHOLD, 0.0); 35 36 return color / (color + BRIGHT_PASS_OFFSET); 37 } 38 39 40 void main(void) 41 { 42 vec2 blur = vec2(clamp( bias, -blurclamp, blurclamp )); 43 44 vec4 col = vec4( 0, 0, 0, 0 ); 45 for ( float x = -KERNEL_SIZE + 1.0; x < KERNEL_SIZE; x += 1.0 ) 46 { 47 for ( float y = -KERNEL_SIZE + 1.0; y < KERNEL_SIZE; y += 1.0 ) 48 { 49 col += bright( texcoord + vec2( blur.x * x, blur.y * y ) ); 50 } 51 } 52 col /= ((KERNEL_SIZE+KERNEL_SIZE)-1.0)*((KERNEL_SIZE+KERNEL_SIZE)-1.0); 53 54 //gl_FragColor = col + texture2D(bgl_RenderedTexture, texcoord); 55 56 //col *= 0.9; 57 gl_FragColor = 1.0 - (1.0 - col) * (1.0 - texture2D(bgl_RenderedTexture, texcoord)); 58 59 } 60 -
binaries/data/mods/public/shaders/glsl/model_common.fs
47 47 vec4 size = vec4(offset + 1.0, 2.0 - offset); 48 48 vec4 weight = (vec4(2.0 - 1.0 / size.xy, 1.0 / size.zw - 1.0) + (v_shadow.xy - offset).xyxy) * shadowScale.zwzw; 49 49 return (1.0/9.0)*dot(size.zxzx*size.wwyy, 50 vec4(shadow2D(shadowTex, vec3(weight.zw, v_shadow.z)). a,51 shadow2D(shadowTex, vec3(weight.xw, v_shadow.z)). a,52 shadow2D(shadowTex, vec3(weight.zy, v_shadow.z)). a,53 shadow2D(shadowTex, vec3(weight.xy, v_shadow.z)). a));50 vec4(shadow2D(shadowTex, vec3(weight.zw, v_shadow.z)).r, 51 shadow2D(shadowTex, vec3(weight.xw, v_shadow.z)).r, 52 shadow2D(shadowTex, vec3(weight.zy, v_shadow.z)).r, 53 shadow2D(shadowTex, vec3(weight.xy, v_shadow.z)).r)); 54 54 #else 55 return shadow2D(shadowTex, v_shadow.xyz). a;55 return shadow2D(shadowTex, v_shadow.xyz).r; 56 56 #endif 57 57 #else 58 58 if (v_shadow.z >= 1.0) … … 64 64 #endif 65 65 } 66 66 67 68 vec3 apply_fog(vec3 colour) 69 { 70 vec3 fogColour = vec3(0.6, 0.6, 0.65); 71 float fogDistance = 300; 72 float fogMax = 0.7; 73 74 float depth = (gl_FragCoord.z / gl_FragCoord.w) / 2 + 0.5; 75 76 float rec = 1.0 / (1.0 - fogDistance); 77 78 float factor = 1.0 - (depth - fogDistance) * rec; 79 80 factor = min(factor, fogMax); 81 82 return mix(colour, fogColour, factor); 83 } 84 85 67 86 void main() 68 87 { 69 88 vec4 tex = texture2D(baseTex, v_tex); … … 75 94 #endif 76 95 77 96 #if USE_TRANSPARENT 78 gl_FragColor.a = tex.a; 97 gl_FragData[0].a = tex.a; 98 gl_FragData[1].a = tex.a; 79 99 #else 80 gl_Frag Color.a = 1.0;100 gl_FragData[0].a = 1.0; 81 101 #endif 82 102 83 103 vec3 texdiffuse = tex.rgb; … … 104 124 105 125 vec3 color = (texdiffuse * sundiffuse + specular) * get_shadow() + texdiffuse * ambient; 106 126 127 //color = apply_fog(color); 128 107 129 #if !IGNORE_LOS 108 130 float los = texture2D(losTex, v_los).a; 109 color *= los; 131 ///color *= los; 132 gl_FragData[1].rgb = los; 110 133 #endif 111 134 112 135 color *= shadingColor; 113 136 114 gl_Frag Color.rgb = color;137 gl_FragData[0].rgb = color; 115 138 } -
binaries/data/mods/public/shaders/glsl/fog.fs
1 #version 110 2 3 varying vec2 v_tex; 4 5 uniform sampler2D bgl_RenderedTexture; 6 uniform sampler2D bgl_DepthTexture; 7 uniform sampler2D bgl_LuminanceTexture; 8 uniform float bgl_RenderedTextureWidth; 9 uniform float bgl_RenderedTextureHeight; 10 11 #define PI 3.14159265 12 13 float width = bgl_RenderedTextureWidth; //texture width 14 float height = bgl_RenderedTextureHeight; //texture height 15 16 vec2 texcoord = v_tex; 17 18 19 20 21 void main(void) 22 { 23 vec3 colour = texture2D(bgl_RenderedTexture, texcoord); 24 25 //gl_FragColor.rgb = colour; 26 //return; 27 28 vec3 depth = texture2D(bgl_DepthTexture, texcoord); 29 30 vec3 fogColour = vec3(0.6, 0.6, 0.65); 31 float dist = 0.991; 32 float maxFog = 0.6; 33 34 float rec = 1 / (1 - dist); 35 36 float factor = (depth.r - dist) * rec; 37 38 factor = min(factor, maxFog); 39 40 if (depth.r >= dist && depth.r < 1.0) 41 gl_FragColor.rgb = mix(colour, fogColour, factor); 42 else 43 gl_FragColor.rgb = colour; 44 45 //gl_FragColor.rgb = (depth - 0.99) * 100; 46 47 } 48 -
binaries/data/mods/public/shaders/glsl/los_interp.fs
1 #version 110 2 3 varying vec2 v_tex; 4 5 uniform sampler2D bgl_RenderedTexture; 6 uniform sampler2D bgl_DepthTexture; 7 uniform sampler2D losTex1, losTex2; 8 uniform float bgl_RenderedTextureWidth; 9 uniform float bgl_RenderedTextureHeight; 10 11 #define PI 3.14159265 12 13 float width = bgl_RenderedTextureWidth; //texture width 14 float height = bgl_RenderedTextureHeight; //texture height 15 16 uniform vec3 delta; 17 18 vec2 texcoord = v_tex; 19 20 21 22 23 void main(void) 24 { 25 //vec3 colour = texture2D(bgl_RenderedTexture, texcoord); 26 27 vec4 los2 = texture2D(losTex1, texcoord); 28 vec4 los1 = texture2D(losTex2, texcoord); 29 30 //colour *= los; 31 32 //gl_FragColor.rgb = colour; 33 34 //gl_FragColor = vec4(0,0,0,los); 35 36 gl_FragColor = mix(los1, los2, clamp(delta.r, 0.0, 1.0)); 37 38 //gl_FragColor.a = (1.0 - clamp(delta.r, 0.0, 1.0)) * los;//delta.r; 39 40 //gl_FragColor.rgb = (depth - 0.99) * 100; 41 42 } 43 -
binaries/data/mods/public/shaders/glsl/water_high.fs
53 53 specular = pow(max(0.0, ndoth), shininess) * sunColor * specularStrength; 54 54 55 55 losMod = texture2D(losMap, gl_TexCoord[3].st).a; 56 gl_FragData[1] = losMod; 56 57 57 gl_Frag Color.rgb = mix(refrColor + 0.3*specular, reflColor + specular, fresnel)* losMod;58 gl_FragData[0].rgb = mix(refrColor + 0.3*specular, reflColor + specular, fresnel);// * losMod; 58 59 59 60 // Make alpha vary based on both depth (so it blends with the shore) and view angle (make it 60 61 // become opaque faster at lower view angles so we can't look "underneath" the water plane) 61 62 t = 18.0 * max(0.0, 0.7 - v.y); 62 gl_Frag Color.a = 0.15 * waterDepth * (1.2 + t + fresnel);63 gl_FragData[0].a = 0.15 * waterDepth * (1.2 + t + fresnel); 63 64 } -
binaries/data/mods/public/shaders/glsl/bloom.vs
1 #version 110 2 3 uniform mat4 transform; 4 5 varying vec2 v_tex; 6 7 attribute vec3 a_vertex; 8 attribute vec2 a_uv0; 9 10 void main() 11 { 12 gl_Position = gl_Vertex; 13 14 v_tex = vec2(gl_MultiTexCoord0); 15 } -
binaries/data/mods/public/shaders/glsl/fog.vs
1 #version 110 2 3 uniform mat4 transform; 4 5 varying vec2 v_tex; 6 7 attribute vec3 a_vertex; 8 attribute vec2 a_uv0; 9 10 void main() 11 { 12 gl_Position = gl_Vertex; 13 14 v_tex = vec2(gl_MultiTexCoord0); 15 } -
binaries/data/mods/public/shaders/glsl/los.fs
1 #version 110 2 3 varying vec2 v_tex; 4 5 uniform sampler2D bgl_RenderedTexture; 6 uniform sampler2D bgl_DepthTexture; 7 uniform sampler2D losTexPersp; 8 uniform float bgl_RenderedTextureWidth; 9 uniform float bgl_RenderedTextureHeight; 10 11 #define PI 3.14159265 12 13 float width = bgl_RenderedTextureWidth; //texture width 14 float height = bgl_RenderedTextureHeight; //texture height 15 16 vec2 texcoord = v_tex; 17 18 19 20 21 void main(void) 22 { 23 vec3 colour = texture2D(bgl_RenderedTexture, texcoord); 24 25 vec3 los = texture2D(losTexPersp, texcoord); 26 27 colour *= los; 28 29 gl_FragColor.rgb = colour; 30 31 //gl_FragColor.rgb = (depth - 0.99) * 100; 32 33 } 34 -
binaries/data/mods/public/shaders/glsl/los_interp.vs
1 #version 110 2 3 uniform mat4 transform; 4 uniform vec2 losTransform; 5 6 varying vec2 v_tex; 7 8 attribute vec3 a_vertex; 9 attribute vec2 a_uv0; 10 11 12 varying vec2 v_los; 13 14 void main() 15 { 16 gl_Position = gl_Vertex; 17 18 v_tex = vec2(gl_MultiTexCoord0); 19 } -
binaries/data/mods/public/shaders/glsl/fog.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <program type="glsl"> 3 4 <vertex file="glsl/bloom.vs"> 5 <stream name="pos"/> 6 <stream name="uv0"/> 7 <attrib name="a_vertex" semantics="gl_Vertex"/> 8 <attrib name="a_uv0" semantics="gl_MultiTexCoord0"/> 9 </vertex> 10 11 <fragment file="glsl/fog.fs"/> 12 13 </program> -
binaries/data/mods/public/shaders/glsl/model_common_norm.fs
1 #version 120 2 3 uniform sampler2D baseTex; 4 uniform sampler2D normTex; 5 uniform sampler2D losTex; 6 uniform sampler2D specTex; 7 8 #if USE_SHADOW 9 #if USE_SHADOW_SAMPLER 10 uniform sampler2DShadow shadowTex; 11 #else 12 uniform sampler2D shadowTex; 13 #endif 14 #endif 15 16 #if USE_OBJECTCOLOR 17 uniform vec3 objectColor; 18 #else 19 #if USE_PLAYERCOLOR 20 uniform vec3 playerColor; 21 #endif 22 #endif 23 24 uniform vec3 ambient; 25 uniform vec4 shadowOffsets1; 26 uniform vec4 shadowOffsets2; 27 28 //uniform mat4 normalMatrix; 29 30 //varying vec3 v_lighting; 31 varying vec2 v_tex; 32 varying vec4 v_shadow; 33 varying vec2 v_los; 34 35 uniform vec3 sunDir; 36 uniform vec3 sunColor; 37 38 /*#if USE_SPECULAR 39 uniform float specularPower; 40 uniform vec3 specularColor; 41 varying vec3 v_normal; 42 #endif*/ 43 44 varying vec3 v_half; 45 46 //varying vec3 lightVec; 47 varying vec3 eyeVec; 48 varying vec3 v_normal; 49 varying vec4 v_tangent; 50 varying vec3 v_bitangent; 51 52 53 //varying float sign; 54 55 56 float get_shadow() 57 { 58 #if USE_SHADOW && !DISABLE_RECEIVE_SHADOWS 59 #if USE_SHADOW_SAMPLER 60 #if USE_SHADOW_PCF 61 return 0.25 * ( 62 shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets1.xy, v_shadow.z)).r + 63 shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets1.zw, v_shadow.z)).r + 64 shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets2.xy, v_shadow.z)).r + 65 shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets2.zw, v_shadow.z)).r 66 ); 67 #else 68 return shadow2D(shadowTex, v_shadow.xyz).r; 69 #endif 70 #else 71 if (v_shadow.z >= 1.0) 72 return 1.0; 73 #if USE_SHADOW_PCF 74 return ( 75 (v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets1.xy).x ? 0.25 : 0.0) + 76 (v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets1.zw).x ? 0.25 : 0.0) + 77 (v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets2.xy).x ? 0.25 : 0.0) + 78 (v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets2.zw).x ? 0.25 : 0.0) 79 ); 80 #else 81 return (v_shadow.z <= texture2D(shadowTex, v_shadow.xy).x ? 1.0 : 0.0); 82 #endif 83 #endif 84 #else 85 return 1.0; 86 #endif 87 } 88 89 90 91 vec3 apply_fog(vec3 colour) 92 { 93 vec3 fogColour = vec3(0.6, 0.6, 0.65); 94 float fogDistance = 1000; 95 float fogMax = 0.6; 96 97 float dep = (gl_FragCoord.z / gl_FragCoord.w) / fogDistance; 98 99 dep = clamp(dep, 0, fogMax); 100 101 return mix(colour, fogColour, dep); 102 } 103 104 105 106 #define USE_PARALLAX 1 107 #define USE_NORMAL_MAP 1 108 #define USE_SPECULAR_MAP 1 109 #define USE_SELF_LIGHT 1 110 #define USE_DISTANCE_FOG 1 111 112 void main() 113 { 114 115 116 vec3 color; 117 mat3 tbn; 118 vec2 coord = v_tex; 119 float sign = v_tangent.w; 120 121 122 #if USE_PARALLAX 123 float h = texture2D(normTex, coord).a; 124 125 tbn = transpose(mat3(v_tangent.xyz, v_bitangent * sign, v_normal)); 126 127 vec3 eyeDir = normalize( tbn * eyeVec ); 128 float dist = length(eyeVec); 129 130 if (dist < 100 && h < 0.999) 131 { 132 float scale = 0.01; 133 134 if (dist > 65) 135 { 136 scale = 0.01 * (100 - dist) / 35.0; 137 } 138 139 float height = 1.0; 140 float iter; 141 142 float s; 143 vec2 move; 144 iter = (75 - (dist - 25)) / 3 + 5; 145 146 if (iter > 15) iter = 15; 147 148 vec3 tangEye = -eyeDir; 149 150 iter = mix(iter * 2, iter, tangEye.z); 151 152 s = 1.0 / iter; 153 move = vec2(-eyeDir.x, eyeDir.y) * scale / (eyeDir.z * iter); 154 155 while (h < height) 156 { 157 height -= s; 158 coord += move; 159 h = texture2D(normTex, coord).a; 160 } 161 162 } 163 #endif 164 165 166 167 tbn = transpose(mat3(v_tangent.xyz, v_bitangent * -sign, v_normal)); 168 vec3 ntex = texture2D(normTex, coord).rgb * 2.0 - 1.0; 169 vec3 vNout = normalize(ntex * tbn); 170 171 172 173 #if USE_NORMAL_MAP 174 float bump = max (dot (-sunDir, vNout), 0.0) ; 175 #else 176 float bump = 1.0; 177 #endif 178 179 180 vec3 specular; 181 vec4 specColour = vec4(1.0); 182 #if USE_SPECULAR_MAP 183 specColour = texture2D(specTex, coord); 184 specular = bump * specColour.xyz * sunColor * pow(max(0.0, dot(normalize(vNout), v_half)), 12); 185 #else 186 // if enabled, do normal specular 187 specular = vec3(0.0); 188 #endif 189 190 191 vec4 diffuse = texture2D(baseTex, coord); 192 193 #if USE_TRANSPARENT 194 gl_FragData[0].a = diffuse.a; 195 gl_FragData[1].a = diffuse.a; 196 #else 197 gl_FragData[0].a = 1.0; 198 #endif 199 200 vec3 texdiffuse = diffuse.rgb; 201 202 // Apply-coloring based on texture alpha 203 #if USE_OBJECTCOLOR 204 texdiffuse *= mix(objectColor, vec3(1.0, 1.0, 1.0), diffuse.a); 205 #else 206 #if USE_PLAYERCOLOR 207 texdiffuse *= mix(playerColor, vec3(1.0, 1.0, 1.0), diffuse.a); 208 #endif 209 #endif 210 211 212 213 214 color = (texdiffuse + specular) * bump * sunColor * get_shadow() + texdiffuse * ambient; 215 216 #if USE_SELF_LIGHT 217 color = mix(texdiffuse, color, specColour.a); 218 #endif 219 220 221 222 //color = apply_fog(color); 223 224 225 226 #if !IGNORE_LOS 227 float los = texture2D(losTex, v_los).a; 228 //color *= los; 229 gl_FragData[1].rgb = los; 230 #endif 231 232 233 //gl_FragColor.rgb = color; 234 gl_FragData[0].rgb = color; 235 } -
binaries/data/mods/public/shaders/glsl/ssao.fs
1 #version 110 2 3 varying vec2 v_tex; 4 5 uniform sampler2D bgl_RenderedTexture; 6 uniform sampler2D bgl_DepthTexture; 7 uniform sampler2D bgl_LuminanceTexture; 8 uniform float bgl_RenderedTextureWidth; 9 uniform float bgl_RenderedTextureHeight; 10 11 #define PI 3.14159265 12 13 float width = bgl_RenderedTextureWidth; //texture width 14 float height = bgl_RenderedTextureHeight; //texture height 15 16 //float near = 10; //Z-near 17 //float far = 100; //Z-far 18 19 //float near = 0.5; //Z-near 20 //float far = 75.0; //Z-far 21 22 float near = 1.4; //Z-near 23 float far = 75.0; //Z-far 24 25 int samples = 6; //samples on the first ring (5-10) 26 int rings = 3; //ring count (2-6) 27 28 //vec2 texCoord = gl_TexCoord[0].st; 29 vec2 texCoord = v_tex; 30 vec2 texcoord = v_tex; 31 32 33 vec2 rand(in vec2 coord) //generating random noise 34 { 35 float noiseX = (fract(sin(dot(coord ,vec2(12.9898,78.233))) * 43758.5453)); 36 float noiseY = (fract(sin(dot(coord ,vec2(12.9898,78.233)*2.0)) * 43758.5453)); 37 return vec2(noiseX,noiseY); 38 } 39 40 float readDepth(in vec2 coord) 41 { 42 return (2.0 * near) / (far + near - texture2D(bgl_DepthTexture, coord ).x * (far-near)); 43 } 44 45 float compareDepths( in float depth1, in float depth2 ) 46 { 47 float aoCap = 1.2; 48 //float aoMultiplier = 250.0; 49 float aoMultiplier = 250.0; 50 float depthTolerance = 0.0000; 51 float aorange = 1.2;// units in space the AO effect extends to (this gets divided by the camera far range 52 float diff = sqrt(clamp(1.0-(depth1-depth2) / (aorange/(far-near)),0.0,1.0)); 53 float ao = min(aoCap,max(0.0,depth1-depth2-depthTolerance) * aoMultiplier) * diff; 54 return ao; 55 } 56 57 void main(void) 58 { 59 /*if (texture2D(bgl_DepthTexture, texcoord).x <= 0.5) 60 { 61 gl_FragColor = texture2D(bgl_RenderedTexture, texcoord); 62 return; 63 }*/ 64 65 float depth = readDepth(texCoord); 66 float d; 67 68 float aspect = width/height; 69 vec2 noise = rand(texCoord)*0.003; 70 71 float w = (0.001/depth+noise.x); 72 float h = (0.001/depth+noise.y); 73 74 float pw; 75 float ph; 76 77 float ao; 78 float s; 79 80 for (int i = 0 ; i < rings; ++i) 81 { 82 for (int j = 0 ; j < samples; ++j) 83 { 84 float step = PI*2.0 / float(samples); 85 pw = (cos(float(j)*step)*float(i)); 86 ph = (sin(float(j)*step)*float(i))*aspect; 87 d = readDepth( vec2(texCoord.s+pw*w,texCoord.t+ph*h)); 88 ao += compareDepths(depth,d); 89 s += 1.0; 90 } 91 } 92 93 ao /= s; 94 ao = 1.0-ao; 95 96 vec3 color = texture2D(bgl_RenderedTexture,texCoord).rgb; 97 //vec3 luminance = texture2D(bgl_LuminanceTexture,texCoord).rgb; 98 vec3 luminance = vec3(dot(color, vec3(0.299, 0.587, 0.114))); 99 vec3 white = vec3(1.0,1.0,1.0); 100 vec3 black = vec3(0.0,0.0,0.0); 101 //vec3 treshold = vec3(0.2,0.2,0.2); 102 103 vec3 treshold = vec3(0.8); 104 105 luminance = clamp(max(black,luminance-treshold)+max(black,luminance-treshold)+max(black,luminance-treshold),0.0,1.0); 106 107 gl_FragColor = vec4(color*mix(vec3(ao,ao,ao),white,luminance),1.0); 108 //gl_FragColor = vec4(mix(vec3(ao,ao,ao),white,luminance),1.0);// vec4(color*vec3(ao,ao,ao),1.0); 109 //gl_FragColor = vec4(mix(vec3(ao,ao,ao),white,luminance),1.0); 110 //gl_FragColor = vec4(ao * color, 1.0); 111 112 //if (texcoord.x > 0.75) gl_FragColor = texture2D(bgl_RenderedTexture, texcoord); 113 } 114 -
binaries/data/config/default.cfg
58 58 renderpath = default 59 59 60 60 ; Prefer GLSL shaders over ARB shaders (not recommended) 61 preferglsl = false61 preferglsl = true 62 62 63 63 ; Replace alpha-blending with alpha-testing, for performance experiments 64 64 forcealphatest = false