Ticket #1429: bumpy3.diff
File bumpy3.diff, 157.9 KB (added by , 12 years ago) |
---|
-
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/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/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/renderer/PostprocManager.h
1 #ifndef INCLUDED_POSTPROCMANAGER 2 #define INCLUDED_POSTPROCMANAGER 3 4 class PostprocManager 5 { 6 public: 7 8 GLuint fbo; 9 GLuint colourTex; 10 GLuint depthTex; 11 GLuint lumaTex; 12 13 std::vector<std::vector<CShaderTechniquePtr> > renderStages; 14 15 int width, height; 16 17 bool isInitialised; 18 19 PostprocManager(); 20 ~PostprocManager(); 21 22 void Initialize(); 23 24 void RecreateBuffers(); 25 26 void LoadEffect(const char* name, int stage); 27 28 void ApplyEffect(CShaderTechniquePtr &shaderTech1); 29 void ApplyPostproc(int stage); 30 31 void CaptureRenderOutput(); 32 33 void PostprocStage1(); 34 void PostprocStage2(); 35 36 void ReleaseRenderOutput(); 37 38 39 40 41 }; 42 43 44 #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 9 #include "graphics/ShaderManager.h" 10 #include "renderer/Renderer.h" 11 12 #include "renderer/PostprocManager.h" 13 14 15 PostprocManager::PostprocManager() 16 { 17 isInitialised = false; 18 fbo = 0; 19 colourTex = 0; 20 depthTex = 0; 21 lumaTex = 0; 22 } 23 24 25 PostprocManager::~PostprocManager() 26 { 27 if (isInitialised) 28 { 29 if (fbo) pglDeleteFramebuffersEXT(1, &fbo); 30 if (colourTex) glDeleteTextures(1, &colourTex); 31 if (depthTex) glDeleteTextures(1, &depthTex); 32 if (lumaTex) glDeleteTextures(1, &lumaTex); 33 } 34 } 35 36 void PostprocManager::Initialize() 37 { 38 RecreateBuffers(); 39 isInitialised = true; 40 41 renderStages = std::vector<std::vector<CShaderTechniquePtr> >(5); 42 43 LoadEffect("ssao", 0); 44 45 LoadEffect("hdr", 1); 46 LoadEffect("bloom", 1); 47 } 48 49 50 void PostprocManager::RecreateBuffers() 51 { 52 if (isInitialised) 53 { 54 if (fbo) pglDeleteFramebuffersEXT(1, &fbo); 55 if (colourTex) glDeleteTextures(1, &colourTex); 56 if (depthTex) glDeleteTextures(1, &depthTex); 57 if (lumaTex) glDeleteTextures(1, &lumaTex); 58 } 59 60 61 /*width = height = (int)round_up_to_pow2((unsigned)std::max(g_Renderer.GetWidth(), g_Renderer.GetHeight())); 62 width = std::min(width, (int)ogl_max_tex_size); 63 height = std::min(height, (int)ogl_max_tex_size);*/ 64 65 width = g_Renderer.GetWidth(); 66 height = g_Renderer.GetHeight(); 67 68 69 glGenTextures(1, (GLuint*)&colourTex); 70 glBindTexture(GL_TEXTURE_2D, colourTex); 71 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, 72 GL_HALF_FLOAT, 0); 73 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 74 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 75 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 76 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 77 78 79 glGenTextures(1, (GLuint*)&depthTex); 80 glBindTexture(GL_TEXTURE_2D, depthTex); 81 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, width, height, 82 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE,NULL); 83 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, 84 GL_NONE); 85 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 86 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 87 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 88 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 89 90 91 glGenTextures(1, (GLuint*)&lumaTex); 92 glBindTexture(GL_TEXTURE_2D, lumaTex); 93 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE16, width, height, 94 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0); 95 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 96 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 97 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 98 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 99 100 glBindTexture(GL_TEXTURE_2D, 0); 101 102 /**pglGenFramebuffersEXT(1, &fbo); 103 pglBindFramebufferEXT(GL_FRAMEBUFFER, fbo); 104 pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colourTex, 0); 105 pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTex, 0); 106 //glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT, GL_TEXTURE_2D, colourTex, 0); 107 108 pglBindFramebufferEXT(GL_FRAMEBUFFER, 0);*/ 109 } 110 111 112 void PostprocManager::CaptureRenderOutput() 113 { 114 glBindTexture(GL_TEXTURE_2D, colourTex); 115 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, 0, 0, width, height, 0); 116 glBindTexture(GL_TEXTURE_2D, depthTex); 117 glCopyTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT, 0, 0, width, height, 0); 118 glBindTexture(GL_TEXTURE_2D, lumaTex); 119 glCopyTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE16, 0, 0, width, height, 0); 120 } 121 122 123 void PostprocManager::ReleaseRenderOutput() 124 { 125 //pglBindFramebufferEXT(GL_FRAMEBUFFER, 0); 126 } 127 128 void PostprocManager::LoadEffect(const char* name, int stage) 129 { 130 CShaderTechniquePtr shaderTech1 = g_Renderer.GetShaderManager().LoadEffect(name); 131 132 renderStages[stage].push_back(shaderTech1); 133 134 } 135 136 void PostprocManager::ApplyEffect(CShaderTechniquePtr &shaderTech1) 137 { 138 CaptureRenderOutput(); 139 140 glDisable(GL_DEPTH_TEST); 141 glDepthMask(GL_FALSE); 142 143 shaderTech1->BeginPass(); 144 CShaderProgramPtr shader = shaderTech1->GetShader(); 145 146 shader->Bind(); 147 148 shader->BindTexture("bgl_RenderedTexture", colourTex); 149 150 shader->BindTexture("bgl_DepthTexture", depthTex); 151 152 shader->BindTexture("bgl_LuminanceTexture", lumaTex); 153 154 shader->Uniform("bgl_RenderedTextureWidth", width); 155 shader->Uniform("bgl_RenderedTextureHeight", height); 156 157 glBegin(GL_QUADS); 158 glColor4f(1.f, 1.f, 1.f, 1.f); 159 glTexCoord2f(1.0, 1.0); glVertex2f(1,1); 160 glTexCoord2f(0.0, 1.0); glVertex2f(-1,1); 161 glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1); 162 glTexCoord2f(1.0, 0.0); glVertex2f(1,-1); 163 glEnd(); 164 165 shader->Unbind(); 166 167 shaderTech1->EndPass(); 168 169 glDepthMask(GL_TRUE); 170 glEnable(GL_DEPTH_TEST); 171 } 172 173 174 175 void PostprocManager::ApplyPostproc(int stage) 176 { 177 if (!isInitialised) 178 return; 179 180 std::vector<CShaderTechniquePtr> &effects = renderStages[stage]; 181 182 //std::cout << "EFFECT!!! " << effects.size() << std::endl; 183 184 for (size_t i = 0; i < effects.size(); i++) 185 { 186 ApplyEffect(effects[i]); 187 } 188 } 189 190 /*void PostprocManager::PostprocStage2() 191 { 192 CShaderTechniquePtr shaderTech2 = g_Renderer.GetShaderManager().LoadEffect("hdr"); 193 194 shaderTech2->BeginPass(); 195 CShaderProgramPtr shader2 = shaderTech2->GetShader(); 196 197 shader2->Bind(); 198 199 shader2->BindTexture("bgl_RenderedTexture", texname[0]); 200 shader2->BindTexture("bgl_DepthTexture", texname[1]); 201 shader2->BindTexture("bgl_LuminanceTexture", texname[2]); 202 203 glBegin(GL_QUADS); 204 glColor4f(1.f, 1.f, 1.f, 1.f); 205 glTexCoord2f(1.0, 1.0); glVertex2f(1,1); 206 glTexCoord2f(0.0, 1.0); glVertex2f(-1,1); 207 //glTexCoord2f(1.0, 1.0); glVertex2f(1,0); 208 //glTexCoord2f(0.0, 1.0); glVertex2f(-1,0); 209 glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1); 210 glTexCoord2f(1.0, 0.0); glVertex2f(1,-1); 211 glEnd(); 212 213 shaderTech2->EndPass(); 214 shader2->Unbind(); 215 216 217 218 219 CShaderTechniquePtr shaderTech3 = g_Renderer.GetShaderManager().LoadEffect("bloom"); 220 221 shaderTech3->BeginPass(); 222 CShaderProgramPtr shader3 = shaderTech3->GetShader(); 223 224 shader3->Bind(); 225 226 shader3->BindTexture("bgl_RenderedTexture", texname[0]); 227 shader3->BindTexture("bgl_DepthTexture", texname[1]); 228 shader3->BindTexture("bgl_LuminanceTexture", texname[2]); 229 230 glBegin(GL_QUADS); 231 glColor4f(1.f, 1.f, 1.f, 1.f); 232 glTexCoord2f(1.0, 1.0); glVertex2f(1,1); 233 glTexCoord2f(0.0, 1.0); glVertex2f(-1,1); 234 //glTexCoord2f(1.0, 1.0); glVertex2f(1,0); 235 //glTexCoord2f(0.0, 1.0); glVertex2f(-1,0); 236 glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1); 237 glTexCoord2f(1.0, 0.0); glVertex2f(1,-1); 238 glEnd(); 239 240 shaderTech3->EndPass(); 241 shader3->Unbind(); 242 }*/ 243 No newline at end of file -
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
66 66 #include "renderer/TerrainRenderer.h" 67 67 #include "renderer/VertexBufferManager.h" 68 68 #include "renderer/WaterManager.h" 69 #include "renderer/PostprocManager.h" 69 70 70 71 71 72 /////////////////////////////////////////////////////////////////////////////////// … … 271 272 272 273 /// Shadow map 273 274 ShadowMap shadow; 275 276 PostprocManager postprocManager; 274 277 275 278 /// Various model renderers 276 279 struct Models … … 631 634 // Let component renderers perform one-time initialization after graphics capabilities and 632 635 // the shader path have been determined. 633 636 m->overlayRenderer.Initialize(); 637 638 m->postprocManager.Initialize(); 634 639 635 640 return true; 636 641 } … … 639 644 void CRenderer::Resize(int width,int height) 640 645 { 641 646 // need to recreate the shadow map object to resize the shadow texture 642 m->shadow.RecreateTexture(); 647 m->shadow.RecreateTexture(); 643 648 644 649 m_Width = width; 645 650 m_Height = height; 651 652 m->postprocManager.RecreateBuffers(); 646 653 } 647 654 648 655 ////////////////////////////////////////////////////////////////////////////////////////// … … 705 712 // SetRenderPath: Select the preferred render path. 706 713 // This may only be called before Open(), because the layout of vertex arrays and other 707 714 // data may depend on the chosen render path. 708 void CRenderer::SetRenderPath(RenderPath rp) 715 void CRenderer::SetRenderPath(RenderPath rp) 709 716 { 710 717 if (!m->IsOpen) 711 718 { … … 1416 1423 } 1417 1424 } 1418 1425 1426 RenderModels(context); 1427 ogl_WarnIfError(); 1428 1429 m->postprocManager.ApplyPostproc(0); 1430 1419 1431 // render submitted patches and models 1420 1432 RenderPatches(context); 1421 1433 ogl_WarnIfError(); … … 1428 1440 m->overlayRenderer.RenderOverlaysBeforeWater(); 1429 1441 ogl_WarnIfError(); 1430 1442 1431 RenderModels(context);1432 ogl_WarnIfError();1433 1434 1443 // render water 1435 1444 if (m_WaterManager->m_RenderWater && g_Game && waterScissor.GetVolume() > 0) 1436 1445 { … … 1452 1461 ogl_WarnIfError(); 1453 1462 } 1454 1463 1464 m->postprocManager.ApplyPostproc(1); 1465 1455 1466 // render debug-related terrain overlays 1456 1467 ITerrainOverlay::RenderOverlaysAfterWater(); 1457 1468 ogl_WarnIfError(); -
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
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/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/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
Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
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/actors/structures/romans/civic_centre.xml
Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: binaries/data/mods/public/art/textures/skins/structural/rome_struct_spec.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: binaries/data/mods/public/art/textures/skins/structural/rome_struct_norm.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: binaries/data/mods/public/art/textures/skins/structural/rome_struct_arch_spec.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: binaries/data/mods/public/art/textures/skins/structural/rome_struct_arch_norm.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream
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/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/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/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 vec3 v_half; 37 27 38 #if USE_SPECULAR 28 39 uniform float specularPower; 29 40 uniform vec3 specularColor; … … 40 51 vec4 size = vec4(offset + 1.0, 2.0 - offset); 41 52 vec4 weight = (vec4(2.0 - 1.0 / size.xy, 1.0 / size.zw - 1.0) + (v_shadow.xy - offset).xyxy) * shadowScale.zwzw; 42 53 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));54 vec4(shadow2D(shadowTex, vec3(weight.zw, v_shadow.z)).r, 55 shadow2D(shadowTex, vec3(weight.xw, v_shadow.z)).r, 56 shadow2D(shadowTex, vec3(weight.zy, v_shadow.z)).r, 57 shadow2D(shadowTex, vec3(weight.xy, v_shadow.z)).r)); 47 58 #else 48 return shadow2D(shadowTex, v_shadow.xyz). a;59 return shadow2D(shadowTex, v_shadow.xyz).r; 49 60 #endif 50 61 #else 51 62 if (v_shadow.z >= 1.0) … … 83 94 vec3 specular = vec3(0.0); 84 95 #endif 85 96 86 vec3 color = (texdiffuse * sundiffuse + specular) * get_shadow() + texdiffuse * ambient; 97 vec3 bump = sundiffuse; 98 if (hasNormalMap.x > 0.5) 99 { 100 vec3 t = vec3(1, 0, 0); 101 t = normalize(t - v_normal * dot(v_normal, t)); 102 vec3 b = cross(v_normal, t); 103 //vec3 b = vec3(0, 0, 1); 104 //b = normalize(b - v_normal * dot(v_normal, b)); 87 105 106 107 mat3 tbn = transpose(mat3(t, b, v_normal)); 108 vec3 ntex = texture2D(normTex, v_tex).rgb * 2.0 - 1.0; 109 vec3 vNout = normalize(ntex * tbn); 110 111 112 bump = vec3(max (dot (-sunDir, vNout), 0.0)) * sunColor; 113 114 vec4 specColour = vec4(1.0); 115 116 if (hasSpecularMap.x > 0.5) 117 { 118 specColour = texture2D(specTex, v_tex); 119 specular = specColour.xyz * sunColor * pow(max(0.0, dot(normalize(vNout), v_half)), 12); 120 } 121 } 122 123 124 //vec3 specular; 125 126 127 128 129 vec3 color = (texdiffuse + specular) * bump * get_shadow() + texdiffuse * ambient; 130 88 131 float los = texture2D(losTex, v_los).a; 89 132 color *= los; 90 133 -
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 21 ///float avgL = 0.38; 22 //float HDRamount = 0.3; 23 ///float HDRamount = 0.1; 24 25 //float avgL = 0.4; 26 //float HDRamount = 0.1; 27 28 //float avgL = 0.65; 29 //float HDRamount = 0.1; 30 31 float avgL = 0.7; 32 float HDRamount = 0.1; 33 34 void main(void) 35 { 36 //gl_FragColor = texture2D(bgl_RenderedTexture, texcoord); 37 //return; 38 39 40 //avgL = int(texcoord.x * 10) / 10.0; 41 //HDRamount = int(texcoord.y * 10) / 10.0; 42 43 44 45 46 47 float contrast = avgL; 48 float brightness = avgL * HDRamount; 49 50 vec4 value = texture2D(bgl_RenderedTexture, texcoord); 51 52 //value *= 0.5; 53 54 gl_FragColor = (value/contrast)-brightness; 55 56 ///float grey = (gl_FragColor.r + gl_FragColor.g + gl_FragColor.b) / 3.0; 57 58 ///gl_FragColor = vec4(mix(gl_FragColor.rgb, vec3(grey), 0.2), 1.0); 59 60 //if (texcoord.x > 0.75) gl_FragColor = texture2D(bgl_RenderedTexture, texcoord); 61 62 } 63 64 -
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 //varying float sign; 55 56 57 void main() 58 { 59 #if USE_GPU_SKINNING 60 vec3 p = vec3(0.0); 61 vec3 n = vec3(0.0); 62 for (int i = 0; i < MAX_INFLUENCES; ++i) { 63 int joint = a_skinJoints[i]; 64 if (joint != 0xff) { 65 mat4 m = skinBlendMatrices[joint]; 66 p += vec3(m * vec4(a_vertex, 1.0)) * a_skinWeights[i]; 67 n += vec3(m * vec4(a_normal, 0.0)) * a_skinWeights[i]; 68 } 69 } 70 vec4 position = instancingTransform * vec4(p, 1.0); 71 vec3 normal = mat3(instancingTransform) * normalize(n); 72 #else 73 #if USE_INSTANCING 74 vec4 position = instancingTransform * vec4(a_vertex, 1.0); 75 vec3 normal = mat3(instancingTransform) * a_normal; 76 vec4 tangent = vec4(mat3(instancingTransform) * a_tangent.xyz, a_tangent.w); 77 #else 78 vec4 position = vec4(a_vertex, 1.0); 79 vec3 normal = a_normal; 80 vec4 tangent = a_tangent; 81 #endif 82 #endif 83 84 gl_Position = transform * position; 85 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 = transform * vec4(a_vertex, 1.0); 13 gl_Position = gl_Vertex; 14 15 v_tex = vec2(gl_MultiTexCoord0); 16 } 17 18 19 /*#version 110 20 21 void main(void) 22 { 23 gl_Position = gl_Vertex; 24 } 25 26 //uniform mat4 transform; 27 28 //attribute vec3 a_vertex; 29 30 varying float uv; 31 32 33 void main() 34 { 35 gl_Position = gl_Vertex; 36 } 37 */ 38 No newline at end of file -
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; 20 21 22 varying vec3 v_half; 23 21 24 #if USE_SPECULAR 22 25 varying vec3 v_normal; 23 26 varying vec3 v_half; 24 27 #endif 25 28 26 29 attribute vec3 a_vertex; 30 attribute vec3 a_normal; 27 31 attribute vec3 a_color; 28 32 attribute vec2 a_uv0; 29 33 attribute vec2 a_uv1; … … 35 39 gl_Position = transform * position; 36 40 37 41 v_lighting = a_color * sunColor; 42 43 //v_lighting = dot(-sunDir, a_normal) * sunColor; 44 45 //v_lighting = sunColor; 38 46 39 47 #if DECAL 40 48 v_tex = a_uv0; … … 72 80 v_normal = normal; 73 81 #endif 74 82 83 vec3 eyeVec = cameraPos.xyz - position.xyz; 84 85 86 vec3 sunVec = -sunDir; 87 88 v_half = normalize(sunVec + eyeVec); 89 90 v_normal = a_normal; 91 75 92 v_los = a_vertex.xz * losTransform.x + losTransform.yy; 76 93 } -
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 = transform * vec4(a_vertex, 1.0); 13 gl_Position = gl_Vertex; 14 15 v_tex = vec2(gl_MultiTexCoord0); 16 } 17 18 19 /*#version 110 20 21 void main(void) 22 { 23 gl_Position = gl_Vertex; 24 } 25 26 //uniform mat4 transform; 27 28 //attribute vec3 a_vertex; 29 30 varying float uv; 31 32 33 void main() 34 { 35 gl_Position = gl_Vertex; 36 } 37 */ 38 No newline at end of file -
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/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/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/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/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.3; 21 //float BRIGHT_PASS_OFFSET = 0.5; 22 23 float BRIGHT_PASS_THRESHOLD = 0.6; 24 float BRIGHT_PASS_OFFSET = 0.6; 25 26 #define blurclamp 0.0015 27 #define bias 0.01 28 29 #define KERNEL_SIZE 3.0 30 31 32 33 vec4 bright(vec2 coo) 34 { 35 //BRIGHT_PASS_THRESHOLD = int(texcoord.x * 10) / 10.0; 36 //BRIGHT_PASS_OFFSET = int(texcoord.y * 10) / 10.0; 37 38 vec4 color = texture2D(bgl_RenderedTexture, coo); 39 40 color = max(color - BRIGHT_PASS_THRESHOLD, 0.0); 41 42 return color / (color + BRIGHT_PASS_OFFSET); 43 } 44 45 46 void main(void) 47 { 48 //gl_FragColor = texture2D(bgl_RenderedTexture, texcoord); 49 //return; 50 51 52 vec2 blur = vec2(clamp( bias, -blurclamp, blurclamp )); 53 54 vec4 col = vec4( 0, 0, 0, 0 ); 55 for ( float x = -KERNEL_SIZE + 1.0; x < KERNEL_SIZE; x += 1.0 ) 56 { 57 for ( float y = -KERNEL_SIZE + 1.0; y < KERNEL_SIZE; y += 1.0 ) 58 { 59 col += bright( texcoord + vec2( blur.x * x, blur.y * y ) ); 60 } 61 } 62 col /= ((KERNEL_SIZE+KERNEL_SIZE)-1.0)*((KERNEL_SIZE+KERNEL_SIZE)-1.0); 63 //gl_FragColor = col + texture2D(bgl_RenderedTexture, texcoord); 64 65 //col *= 0.9; 66 gl_FragColor = 1.0 - (1.0 - col) * (1.0 - texture2D(bgl_RenderedTexture, texcoord)); 67 68 69 /*vec3 color = texture2D(bgl_RenderedTexture,texCoord).rgb; 70 vec3 luminance = texture2D(bgl_LuminanceTexture,texCoord).rgb; 71 vec3 white = vec3(1.0,1.0,1.0); 72 vec3 black = vec3(0.0,0.0,0.0); 73 //vec3 treshold = vec3(0.2,0.2,0.2); 74 75 vec3 treshold = vec3(0.3); 76 77 luminance = clamp(max(black,luminance-treshold)+max(black,luminance-treshold)+max(black,luminance-treshold),0.0,1.0); 78 79 if (texcoord.x > 0.5) 80 gl_FragColor = vec4(mix(gl_FragColor.rgb,color,1.0-luminance),1.0);*/ 81 82 83 //gl_FragColor = mix(gl_FragColor, texture2D(bgl_RenderedTexture, texcoord), 0.5); 84 85 //if (texcoord.x > 0.5) gl_FragColor = texture2D(bgl_RenderedTexture, texcoord); 86 87 } 88 -
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) -
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 = transform * vec4(a_vertex, 1.0); 13 gl_Position = gl_Vertex; 14 15 v_tex = vec2(gl_MultiTexCoord0); 16 } 17 18 19 /*#version 110 20 21 void main(void) 22 { 23 gl_Position = gl_Vertex; 24 } 25 26 //uniform mat4 transform; 27 28 //attribute vec3 a_vertex; 29 30 varying float uv; 31 32 33 void main() 34 { 35 gl_Position = gl_Vertex; 36 } 37 */ 38 No newline at end of file -
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 #define USE_PARALLAX 1 91 #define USE_NORMAL_MAP 1 92 #define USE_SPECULAR_MAP 1 93 #define USE_SELF_LIGHT 1 94 95 void main() 96 { 97 98 99 vec3 color; 100 mat3 tbn; 101 vec2 coord = v_tex; 102 float sign = v_tangent.w; 103 104 105 #if USE_PARALLAX 106 float h = texture2D(normTex, coord).a; 107 108 tbn = transpose(mat3(v_tangent.xyz, v_bitangent * sign, v_normal)); 109 110 vec3 eyeDir = normalize( tbn * eyeVec ); 111 float dist = length(eyeVec); 112 113 if (dist < 100 && h < 0.999) 114 { 115 float scale = 0.01; 116 117 if (dist > 65) 118 { 119 scale = 0.01 * (100 - dist) / 35.0; 120 } 121 122 float height = 1.0; 123 float iter; 124 125 float s; 126 vec2 move; 127 iter = (75 - (dist - 25)) / 3 + 5; 128 129 if (iter > 15) iter = 15; 130 131 vec3 tangEye = -eyeDir; 132 133 iter = mix(iter * 2, iter, tangEye.z); 134 135 s = 1.0 / iter; 136 move = vec2(-eyeDir.x, eyeDir.y) * scale / (eyeDir.z * iter); 137 138 while (h < height) 139 { 140 height -= s; 141 coord += move; 142 h = texture2D(normTex, coord).a; 143 } 144 145 } 146 #endif 147 148 149 150 tbn = transpose(mat3(v_tangent.xyz, v_bitangent * -sign, v_normal)); 151 vec3 ntex = texture2D(normTex, coord).rgb * 2.0 - 1.0; 152 vec3 vNout = normalize(ntex * tbn); 153 154 155 156 #if USE_NORMAL_MAP 157 float bump = max (dot (-sunDir, vNout), 0.0) ; 158 #else 159 float bump = 1.0; 160 #endif 161 162 163 vec3 specular; 164 vec4 specColour = vec4(1.0); 165 #if USE_SPECULAR_MAP 166 specColour = texture2D(specTex, coord); 167 specular = bump * specColour.xyz * sunColor * pow(max(0.0, dot(normalize(vNout), v_half)), 12); 168 #else 169 // if enabled, do normal specular 170 specular = vec3(0.0); 171 #endif 172 173 174 vec4 diffuse = texture2D(baseTex, coord); 175 176 #if USE_TRANSPARENT 177 gl_FragColor.a = diffuse.a; 178 #else 179 gl_FragColor.a = 1.0; 180 #endif 181 182 vec3 texdiffuse = diffuse.rgb; 183 184 // Apply-coloring based on texture alpha 185 #if USE_OBJECTCOLOR 186 texdiffuse *= mix(objectColor, vec3(1.0, 1.0, 1.0), diffuse.a); 187 #else 188 #if USE_PLAYERCOLOR 189 texdiffuse *= mix(playerColor, vec3(1.0, 1.0, 1.0), diffuse.a); 190 #endif 191 #endif 192 193 194 195 196 color = (texdiffuse + specular) * bump * sunColor * get_shadow() + texdiffuse * ambient; 197 198 #if USE_SELF_LIGHT 199 color = mix(texdiffuse, color, specColour.a); 200 #endif 201 202 203 204 205 #if !IGNORE_LOS 206 float los = texture2D(losTex, v_los).a; 207 color *= los; 208 #endif 209 210 211 gl_FragColor.rgb = color; 212 } -
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 int samples = 6; //samples on the first ring (5-10) 23 int rings = 3; //ring count (2-6) 24 25 //vec2 texCoord = gl_TexCoord[0].st; 26 vec2 texCoord = v_tex; 27 vec2 texcoord = v_tex; 28 29 30 vec2 rand(in vec2 coord) //generating random noise 31 { 32 float noiseX = (fract(sin(dot(coord ,vec2(12.9898,78.233))) * 43758.5453)); 33 float noiseY = (fract(sin(dot(coord ,vec2(12.9898,78.233)*2.0)) * 43758.5453)); 34 return vec2(noiseX,noiseY); 35 } 36 37 float readDepth(in vec2 coord) 38 { 39 return (2.0 * near) / (far + near - texture2D(bgl_DepthTexture, coord ).x * (far-near)); 40 } 41 42 float compareDepths( in float depth1, in float depth2 ) 43 { 44 float aoCap = 1.2; 45 float aoMultiplier = 250.0; 46 float depthTolerance = 0.0000; 47 float aorange = 2.5;// units in space the AO effect extends to (this gets divided by the camera far range 48 float diff = sqrt(clamp(1.0-(depth1-depth2) / (aorange/(far-near)),0.0,1.0)); 49 float ao = min(aoCap,max(0.0,depth1-depth2-depthTolerance) * aoMultiplier) * diff; 50 return ao; 51 } 52 53 void main(void) 54 { 55 /*if (texture2D(bgl_DepthTexture, texcoord).x <= 0.5) 56 { 57 gl_FragColor = texture2D(bgl_RenderedTexture, texcoord); 58 return; 59 }*/ 60 61 float depth = readDepth(texCoord); 62 float d; 63 64 float aspect = width/height; 65 vec2 noise = rand(texCoord)*0.003; 66 67 float w = (0.001/depth+noise.x); 68 float h = (0.001/depth+noise.y); 69 70 float pw; 71 float ph; 72 73 float ao; 74 float s; 75 76 for (int i = 0 ; i < rings; ++i) 77 { 78 for (int j = 0 ; j < samples; ++j) 79 { 80 float step = PI*2.0 / float(samples); 81 pw = (cos(float(j)*step)*float(i)); 82 ph = (sin(float(j)*step)*float(i))*aspect; 83 d = readDepth( vec2(texCoord.s+pw*w,texCoord.t+ph*h)); 84 ao += compareDepths(depth,d); 85 s += 1.0; 86 } 87 } 88 89 ao /= s; 90 ao = 1.0-ao; 91 92 vec3 color = texture2D(bgl_RenderedTexture,texCoord).rgb; 93 //vec3 luminance = texture2D(bgl_LuminanceTexture,texCoord).rgb; 94 vec3 luminance = vec3(dot(color, vec3(0.299, 0.587, 0.114))); 95 vec3 white = vec3(1.0,1.0,1.0); 96 vec3 black = vec3(0.0,0.0,0.0); 97 //vec3 treshold = vec3(0.2,0.2,0.2); 98 99 vec3 treshold = vec3(0.8); 100 101 luminance = clamp(max(black,luminance-treshold)+max(black,luminance-treshold)+max(black,luminance-treshold),0.0,1.0); 102 103 gl_FragColor = vec4(color*mix(vec3(ao,ao,ao),white,luminance),1.0); 104 //gl_FragColor = vec4(mix(vec3(ao,ao,ao),white,luminance),1.0);// vec4(color*vec3(ao,ao,ao),1.0); 105 //gl_FragColor = vec4(mix(vec3(ao,ao,ao),white,luminance),1.0); 106 //gl_FragColor = vec4(ao * color, 1.0); 107 108 //if (texcoord.x > 0.75) gl_FragColor = texture2D(bgl_RenderedTexture, texcoord); 109 } 110 111 #if (0) 112 113 vec2 rand(in vec2 coord) //generating random noise 114 { 115 float noiseX = (fract(sin(dot(coord ,vec2(12.9898,78.233))) * 43758.5453)); 116 float noiseY = (fract(sin(dot(coord ,vec2(12.9898,78.233)*2.0)) * 43758.5453)); 117 return vec2(noiseX,noiseY); 118 } 119 120 float readDepth(in vec2 coord) 121 { 122 return (2.0 * near) / (far + near - texture2D(bgl_DepthTexture, coord ).x * (far-near)); 123 } 124 125 float compareDepths( in float depth1, in float depth2 ) 126 { 127 float aoCap = 1.0; 128 float aoMultiplier = 100.0; 129 float depthTolerance = 0.0000; 130 float aorange = 6.0;// units in space the AO effect extends to (this gets divided by the camera far range 131 float diff = sqrt(clamp(1.0-(depth1-depth2) / (aorange/(far-near)),0.0,1.0)); 132 float ao = min(aoCap,max(0.0,depth1-depth2-depthTolerance) * aoMultiplier) * diff; 133 return ao; 134 } 135 136 void main(void) 137 { 138 float depth = readDepth(texCoord); 139 float d; 140 141 float aspect = width/height; 142 vec2 noise = rand(texCoord)*0.003; 143 144 float w = (0.001/depth+noise.x); 145 float h = (0.001/depth+noise.y); 146 147 float pw; 148 float ph; 149 150 float ao; 151 float s; 152 153 for (int i = 0 ; i < rings; ++i) 154 { 155 for (int j = 0 ; j < samples; ++j) 156 { 157 float step = PI*2.0 / float(samples); 158 pw = (cos(float(j)*step)*float(i)); 159 ph = (sin(float(j)*step)*float(i))*aspect; 160 d = readDepth( vec2(texCoord.s+pw*w,texCoord.t+ph*h)); 161 ao += compareDepths(depth,d); 162 s += 1.0; 163 } 164 } 165 166 ao /= s; 167 ao = 1.0-ao; 168 169 vec3 color = texture2D(bgl_RenderedTexture,texCoord).rgb; 170 vec3 luminance = texture2D(bgl_LuminanceTexture,texCoord).rgb; 171 vec3 white = vec3(1.0,1.0,1.0); 172 vec3 black = vec3(0.0,0.0,0.0); 173 vec3 treshold = vec3(0.2,0.2,0.2); 174 175 luminance = clamp(max(black,luminance-treshold)+max(black,luminance-treshold)+max(black,luminance-treshold),0.0,1.0); 176 177 gl_FragColor = vec4(color*mix(vec3(ao,ao,ao),white,luminance), 1.0); //vec4(color*mix(vec3(ao,ao,ao),white,luminance),1.0); 178 179 //gl_FragColor = vec4(color*mix(vec3(ao,ao,ao),white,luminance),1.0); 180 //gl_FragColor = ao * texture2D(bgl_RenderedTexture, texCoord ); 181 //gl_FragColor = ao; 182 183 //gl_FragColor = texture2D(bgl_RenderedTexture, texCoord); 184 185 if (texcoord.x > 0.5) gl_FragColor = texture2D(bgl_RenderedTexture, texcoord); 186 } 187 188 #endif 189 190 /*#define camx 100 191 #define camy 200 192 193 194 int j; 195 int i; 196 197 198 199 float readDepth( in vec2 coord ) { 200 return (2.0 * camx) / (camy + camx - texture2D(bgl_DepthTexture, coord ).x * (camy - camx)); 201 } 202 203 float compareDepths( in float depth1, in float depth2 ) { 204 float aoCap = 1.0; 205 float aoMultiplier=100.0; 206 float depthTolerance=0.0000; 207 float aorange = 20.0;// units in space the AO effect extends to (this gets divided by the camera far range 208 float diff = sqrt( clamp(1.0-(depth1-depth2) / (aorange/(camy-camx)),0.0,1.0) ); 209 float ao = min(aoCap,max(0.0,depth1-depth2-depthTolerance) * aoMultiplier) * diff; 210 return ao; 211 } 212 213 void main(void) 214 { 215 //gl_FragColor = texture2D(bgl_RenderedTexture, texCoord); 216 217 float depth = readDepth( texCoord ); 218 float d; 219 220 float pw = 1.0 / float(width); 221 float ph = 1.0 / float(height); 222 223 float aoCap = 2.0; 224 225 float ao = 5.0; 226 227 float aoMultiplier=1.0; 228 229 float depthTolerance = 0.0000; 230 231 float aoscale=0.7; 232 233 d=readDepth( vec2(texCoord.s+pw,texCoord.t+ph)); 234 ao+=compareDepths(depth,d)/aoscale; 235 236 d=readDepth( vec2(texCoord.s-pw,texCoord.t+ph)); 237 ao+=compareDepths(depth,d)/aoscale; 238 239 d=readDepth( vec2(texCoord.s+pw,texCoord.t-ph)); 240 ao+=compareDepths(depth,d)/aoscale; 241 242 d=readDepth( vec2(texCoord.s-pw,texCoord.t-ph)); 243 ao+=compareDepths(depth,d)/aoscale; 244 245 pw*=2.0; 246 ph*=2.0; 247 aoMultiplier/=2.0; 248 aoscale*=1.2; 249 250 d=readDepth( vec2(texCoord.s+pw,texCoord.t+ph)); 251 ao+=compareDepths(depth,d)/aoscale; 252 253 d=readDepth( vec2(texCoord.s-pw,texCoord.t+ph)); 254 ao+=compareDepths(depth,d)/aoscale; 255 256 d=readDepth( vec2(texCoord.s+pw,texCoord.t-ph)); 257 ao+=compareDepths(depth,d)/aoscale; 258 259 d=readDepth( vec2(texCoord.s-pw,texCoord.t-ph)); 260 ao+=compareDepths(depth,d)/aoscale; 261 262 pw*=2.0; 263 ph*=2.0; 264 aoMultiplier/=2.0; 265 aoscale*=1.4; 266 267 d=readDepth( vec2(texCoord.s+pw,texCoord.t+ph)); 268 ao+=compareDepths(depth,d)/aoscale; 269 270 d=readDepth( vec2(texCoord.s-pw,texCoord.t+ph)); 271 ao+=compareDepths(depth,d)/aoscale; 272 273 d=readDepth( vec2(texCoord.s+pw,texCoord.t-ph)); 274 ao+=compareDepths(depth,d)/aoscale; 275 276 d=readDepth( vec2(texCoord.s-pw,texCoord.t-ph)); 277 ao+=compareDepths(depth,d)/aoscale; 278 279 pw*=2.0; 280 ph*=2.0; 281 aoMultiplier/=2.0; 282 aoscale*=1.6; 283 284 d=readDepth( vec2(texCoord.s+pw,texCoord.t+ph)); 285 ao+=compareDepths(depth,d)/aoscale; 286 287 d=readDepth( vec2(texCoord.s-pw,texCoord.t+ph)); 288 ao+=compareDepths(depth,d)/aoscale; 289 290 d=readDepth( vec2(texCoord.s+pw,texCoord.t-ph)); 291 ao+=compareDepths(depth,d)/aoscale; 292 293 d=readDepth( vec2(texCoord.s-pw,texCoord.t-ph)); 294 ao+=compareDepths(depth,d)/aoscale; 295 296 pw*=2.0; 297 ph*=2.0; 298 aoMultiplier/=2.0; 299 aoscale*=1.8; 300 301 d=readDepth( vec2(texCoord.s+pw,texCoord.t+ph)); 302 ao+=compareDepths(depth,d)/aoscale; 303 304 d=readDepth( vec2(texCoord.s-pw,texCoord.t+ph)); 305 ao+=compareDepths(depth,d)/aoscale; 306 307 d=readDepth( vec2(texCoord.s+pw,texCoord.t-ph)); 308 ao+=compareDepths(depth,d)/aoscale; 309 310 d=readDepth( vec2(texCoord.s-pw,texCoord.t-ph)); 311 ao+=compareDepths(depth,d)/aoscale; 312 313 ao/=15.0; 314 315 vec4 finalao = vec4(1.0-ao,1.0-ao,1.0-ao,1.0); 316 finalao = clamp(finalao,0.0,0.7)+0.3; 317 318 gl_FragColor = finalao * texture2D(bgl_RenderedTexture, texCoord ); 319 gl_FragColor.a = 1.0; 320 321 322 gl_FragColor = texture2D(bgl_RenderedTexture, texCoord); 323 } 324 */ 325 No newline at end of file -
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