Ticket #1429: bumpy4.diff

File bumpy4.diff, 177.7 KB (added by myconid, 12 years ago)
  • source/ps/Game.cpp

     
    283283                g_GUI->SendEventToAll("SimulationUpdate");
    284284            }
    285285
    286             GetView()->GetLOSTexture().MakeDirty();
     286            //GetView()->GetLOSTexture().MakeDirty();
     287            GetView()->GetLOSTexture().MakeDirty();         
     288            //GetScene().GetLOSTexture().InterpolateLOS();
    287289        }
     290       
     291        GetView()->GetLOSTexture().m_LosTexTimer = deltaSimTime;
    288292    }
    289293
    290294    if (doInterpolate)
  • source/graphics/Material.h

     
    3838
    3939    void SetDiffuseTexture(const CTexturePtr& texture);
    4040    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; }
    4147
    4248    void SetShaderEffect(const CStr& effect);
    4349    CStrIntern GetShaderEffect() const { return m_ShaderEffect; }
     
    5056
    5157private:
    5258    CTexturePtr m_DiffuseTexture;
     59    CTexturePtr m_NormalTexture;
     60    CTexturePtr m_SpecularTexture;
    5361    CStrIntern m_ShaderEffect;
    5462    CShaderDefines m_ShaderDefines;
    5563    CShaderUniforms m_StaticUniforms;
  • source/graphics/LOSTexture.cpp

     
    2020#include "LOSTexture.h"
    2121
    2222#include "graphics/Terrain.h"
     23#include "graphics/ShaderManager.h"
    2324#include "lib/bits.h"
     25#include "ps/CLogger.h"
    2426#include "ps/Game.h"
    2527#include "ps/Profile.h"
    2628#include "renderer/Renderer.h"
     
    4850static const size_t g_BlurSize = 7;
    4951
    5052CLOSTexture::CLOSTexture(CSimulation2& simulation) :
    51     m_Simulation(simulation), m_Dirty(true), m_Texture(0), m_MapSize(0), m_TextureSize(0)
     53    m_Simulation(simulation), m_Dirty(true), m_Texture(0), m_smoothFbo(0), m_MapSize(0), m_TextureSize(0), m_LosTexTimer(0.0), whichTex(true)
    5254{
     55    pglGenFramebuffersEXT(1, &m_smoothFbo);
     56    m_smoothShader = g_Renderer.GetShaderManager().LoadEffect("los_interp");
    5357}
    5458
    5559CLOSTexture::~CLOSTexture()
     
    6165void CLOSTexture::DeleteTexture()
    6266{
    6367    glDeleteTextures(1, &m_Texture);
    64     m_Texture = 0;
     68    glDeleteTextures(1, &m_TextureSmooth1);
     69    glDeleteTextures(1, &m_TextureSmooth2);
     70    m_Texture = 0; 
    6571}
    6672
    6773void CLOSTexture::MakeDirty()
     
    8086    g_Renderer.BindTexture(unit, m_Texture);
    8187}
    8288
     89GLuint CLOSTexture::GetTextureSmooth()
     90{
     91    return whichTex ? m_TextureSmooth1 : m_TextureSmooth2;
     92}
     93
     94void CLOSTexture::InterpolateLOS()
     95{
     96    if (m_Dirty)
     97    {
     98        RecomputeTexture(0);
     99        m_Dirty = false;
     100    }
     101   
     102    GLint originalFBO;
     103    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &originalFBO);
     104   
     105    //if (!m_smoothFbo)
     106       
     107   
     108    //if (!m_smoothShader) 
     109   
     110    pglBindFramebufferEXT(GL_FRAMEBUFFER, m_smoothFbo);
     111    pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
     112                   whichTex ? m_TextureSmooth2 : m_TextureSmooth1, 0);
     113   
     114    GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
     115    if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
     116    {
     117        LOGWARNING(L"Framebuffer object incomplete: 0x%04X", status);
     118    }
     119   
     120   
     121    /*glActiveTexture(GL_TEXTURE0);
     122    glBindTexture(GL_TEXTURE_2D, m_Texture);
     123   
     124    glBegin(GL_QUADS);
     125        glColor4f(1.f, 1.f, 1.f, 0.5f);
     126        glTexCoord2f(1.0, 1.0); glVertex2f(1,1);
     127        glTexCoord2f(0.0, 1.0); glVertex2f(-1,1);       
     128        glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1);
     129        glTexCoord2f(1.0, 0.0); glVertex2f(1,-1);
     130    glEnd();*/
     131
     132    m_smoothShader->BeginPass();
     133    CShaderProgramPtr shader = m_smoothShader->GetShader();
     134   
     135    shader->Bind();
     136   
     137    //shader->BindTexture("smoothTex", stencilTex);
     138    shader->BindTexture("losTex1", m_Texture);
     139    shader->BindTexture("losTex2", whichTex ? m_TextureSmooth1 : m_TextureSmooth2);
     140   
     141    //std::cout << m_LosTexTimer * 1 << std::endl;
     142    shader->Uniform("delta", CVector3D(m_LosTexTimer * 4, 0, 0));
     143    //m_LosTexTimer = 0;
     144   
     145    glEnable(GL_BLEND);
     146    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     147   
     148    glPushAttrib(GL_VIEWPORT_BIT);
     149    glViewport(0, 0, m_TextureSize, m_TextureSize);
     150   
     151    glBegin(GL_QUADS);
     152        glColor4f(1.f, 1.f, 1.f, 1.f);
     153        glTexCoord2f(1.0, 1.0); glVertex2f(1,1);
     154        glTexCoord2f(0.0, 1.0); glVertex2f(-1,1);       
     155        glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1);
     156        glTexCoord2f(1.0, 0.0); glVertex2f(1,-1);
     157    glEnd();
     158   
     159    glPopAttrib();
     160   
     161   
     162    shader->Unbind();
     163   
     164    m_smoothShader->EndPass();
     165   
     166    pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
     167   
     168   
     169    //glDisable(GL_BLEND);
     170   
     171    pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, originalFBO);
     172   
     173    whichTex = !whichTex;
     174
     175    //return m_TextureSmooth;
     176}
     177
     178
    83179GLuint CLOSTexture::GetTexture()
    84180{
    85181    if (m_Dirty)
     
    114210    m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize + g_BlurSize - 1);
    115211
    116212    glGenTextures(1, &m_Texture);
    117     g_Renderer.BindTexture(unit, m_Texture);
     213    glGenTextures(1, &m_TextureSmooth1);
     214    glGenTextures(1, &m_TextureSmooth2);
     215   
    118216
    119217    // Initialise texture with SoD colour, for the areas we don't
    120218    // overwrite with glTexSubImage2D later
    121219    u8* texData = new u8[m_TextureSize * m_TextureSize];
    122220    memset(texData, 0x00, m_TextureSize * m_TextureSize);
     221   
     222    g_Renderer.BindTexture(unit, m_TextureSmooth1);
    123223    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_TextureSize, m_TextureSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texData);
    124     delete[] texData;
    125 
    126224    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    127225    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    128226    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    129227    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     228   
     229    g_Renderer.BindTexture(unit, m_TextureSmooth2);
     230    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_TextureSize, m_TextureSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texData);
     231    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     232    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     233    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     234    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     235   
     236    g_Renderer.BindTexture(unit, m_Texture);
     237    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_TextureSize, m_TextureSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texData);
     238    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     239    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     240    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     241    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     242   
     243    delete[] texData;
    130244
    131245    {
    132246        // Texture matrix: We want to map
  • source/graphics/TerrainTextureManager.cpp

     
    143143        // multiple extensions.
    144144        if(!tex_is_known_extension(pathnames[i]))
    145145            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        }
    146157
    147158        VfsPath pathnameXML = pathnames[i].ChangeExtension(L".xml");
    148159        CTerrainPropertiesPtr myprops;
  • source/graphics/TerrainProperties.cpp

     
    103103    ATTR(movementclass);
    104104    ATTR(angle);
    105105    ATTR(size);
     106    ATTR(normalmap);
     107    ATTR(specularmap);
    106108    #undef ELMT
    107109    #undef ATTR
    108110
     
    154156        {
    155157            m_MovementClass = attr.Value;
    156158        }
     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        }
    157167    }
    158168}
    159169
  • source/graphics/ObjectEntry.h

     
    4747    CObjectBase* m_Base;
    4848
    4949    VfsPath m_TextureName;
     50    VfsPath m_NormalName;
     51    VfsPath m_SpecularName;
    5052    // model name
    5153    VfsPath m_ModelName;
    5254    // 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
     29extern "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
     62typedef int tbool;
     63typedef struct SMikkTSpaceContext SMikkTSpaceContext;
     64
     65typedef 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
     107struct 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!
     114tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext); // Default (recommended) fAngularThreshold is 180 degrees (which means threshold disabled)
     115tbool 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
     34static 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
     38int 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
     73static 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

     
    4747    CTerrainPropertiesPtr m_pProperties;
    4848   
    4949    CTexturePtr m_Texture;
     50    CTexturePtr m_Normal;
     51    CTexturePtr m_Specular;
    5052
    5153    CMatrix3D m_TextureMatrix;
    5254   
     
    7981        return m_Texture;
    8082    }
    8183
     84    const CTexturePtr& GetNormal() {
     85        return m_Normal;
     86    }
     87
     88    const CTexturePtr& GetSpecular() {
     89        return m_Specular;
     90    }
     91
    8292    // Returns a matrix of the form [c 0 -s 0; -s 0 -c 0; 0 0 0 0; 0 0 0 1]
    8393    // mapping world-space (x,y,z,1) coordinates onto (u,v,0,1) texcoords
    8494    const float* GetTextureMatrix();
  • source/graphics/LOSTexture.h

     
    1818#include "lib/ogl.h"
    1919
    2020#include "maths/Matrix3D.h"
     21
     22#include "graphics/ShaderManager.h"
     23
    2124#include "simulation2/components/ICmpRangeManager.h"
    2225
    2326class CSimulation2;
     
    5558     * The texture is in 8-bit ALPHA format.
    5659     */
    5760    GLuint GetTexture();
     61   
     62    void InterpolateLOS();
     63    GLuint GetTextureSmooth();
    5864
    5965    /**
    6066     * Returns a matrix to map (x,y,z) world coordinates onto (u,v) LOS texture
     
    6975     * This must only be called after BindTexture.
    7076     */
    7177    const float* GetMinimapTextureMatrix();
     78   
     79    double m_LosTexTimer;
    7280
    7381private:
    7482    void DeleteTexture();
     
    8391    bool m_Dirty;
    8492
    8593    GLuint m_Texture;
     94    GLuint m_TextureSmooth1, m_TextureSmooth2;
     95   
     96    bool whichTex;
     97   
     98    GLuint m_smoothFbo;
     99    CShaderTechniquePtr m_smoothShader;
    86100
    87101    ssize_t m_MapSize; // vertexes per side
    88102    GLsizei m_TextureSize; // texels per side
  • source/graphics/mikktspace.cpp

     
     1#include "precompiled.h"
     2
     3/** \file mikktspace/mikktspace.c
     4 *  \ingroup mikktspace
     5 */
     6/**
     7 *  Copyright (C) 2011 by Morten S. Mikkelsen
     8 *
     9 *  This software is provided 'as-is', without any express or implied
     10 *  warranty.  In no event will the authors be held liable for any damages
     11 *  arising from the use of this software.
     12 *
     13 *  Permission is granted to anyone to use this software for any purpose,
     14 *  including commercial applications, and to alter it and redistribute it
     15 *  freely, subject to the following restrictions:
     16 *
     17 *  1. The origin of this software must not be misrepresented; you must not
     18 *     claim that you wrote the original software. If you use this software
     19 *     in a product, an acknowledgment in the product documentation would be
     20 *     appreciated but is not required.
     21 *  2. Altered source versions must be plainly marked as such, and must not be
     22 *     misrepresented as being the original software.
     23 *  3. This notice may not be removed or altered from any source distribution.
     24 */
     25
     26#include <assert.h>
     27#include <stdio.h>
     28#include <math.h>
     29#include <string.h>
     30#include <float.h>
     31#include <stdlib.h>
     32
     33#include "mikktspace.h"
     34
     35#define TFALSE      0
     36#define TTRUE       1
     37
     38#ifndef M_PI
     39#define M_PI    3.1415926535897932384626433832795
     40#endif
     41
     42#define INTERNAL_RND_SORT_SEED      39871946
     43
     44// internal structure
     45typedef struct
     46{
     47    float x, y, z;
     48} SVec3;
     49
     50static 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
     55static 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
     67static 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
     78static 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
     89static float            LengthSquared( const SVec3 v )
     90{
     91    return v.x*v.x + v.y*v.y + v.z*v.z;
     92}
     93
     94static float            Length( const SVec3 v )
     95{
     96    return sqrtf(LengthSquared(v));
     97}
     98
     99static SVec3        Normalize( const SVec3 v )
     100{
     101    return vscale(1 / Length(v), v);
     102}
     103
     104static 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
     110static tbool NotZero(const float fX)
     111{
     112    // could possibly use FLT_EPSILON instead
     113    return fabsf(fX) > FLT_MIN;
     114}
     115
     116static 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
     124typedef struct
     125{
     126    int iNrFaces;
     127    int * pTriMembers;
     128} SSubGroup;
     129
     130typedef 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
     146typedef 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
     161typedef 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
     171static int GenerateInitialVerticesIndexList(STriInfo pTriInfos[], int piTriList_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn);
     172static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn);
     173static void InitTriInfo(STriInfo pTriInfos[], const int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn);
     174static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupTrianglesBuffer[], const int piTriListIn[], const int iNrTrianglesIn);
     175static 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
     179static 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
     185static void IndexToData(int * piFace, int * piVert, const int iIndexIn)
     186{
     187    piVert[0] = iIndexIn&0x3;
     188    piFace[0] = iIndexIn>>2;
     189}
     190
     191static 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
     221static SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index);
     222static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index);
     223static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index);
     224
     225
     226// degen triangles
     227static void DegenPrologue(STriInfo pTriInfos[], int piTriList_out[], const int iNrTrianglesIn, const int iTotTris);
     228static void DegenEpilogue(STSpace psTspace[], STriInfo pTriInfos[], int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn, const int iTotTris);
     229
     230
     231tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext)
     232{
     233    return genTangSpace(pContext, 180.0f);
     234}
     235
     236tbool 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
     431typedef struct
     432{
     433    float vert[3];
     434    int index;
     435} STmpVert;
     436
     437const 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.
     448NOINLINE 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
     455static void MergeVertsFast(int piTriList_in_and_out[], STmpVert pTmpVert[], const SMikkTSpaceContext * pContext, const int iL_in, const int iR_in);
     456static void MergeVertsSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int pTable[], const int iEntries);
     457static void GenerateSharedVerticesIndexListSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn);
     458
     459static 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
     584static 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
     694static 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
     729static 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
     772static 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
     883static 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
     893static 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
     903static 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
     916typedef union
     917{
     918    struct
     919    {
     920        int i0, i1, f;
     921    };
     922    int array[3];
     923} SEdge;
     924
     925static void BuildNeighborsFast(STriInfo pTriInfos[], SEdge * pEdges, const int piTriListIn[], const int iNrTrianglesIn);
     926static void BuildNeighborsSlow(STriInfo pTriInfos[], const int piTriListIn[], const int iNrTrianglesIn);
     927
     928// returns the texture area times 2
     929static 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
     945static 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
     1067static tbool AssignRecur(const int piTriListIn[], STriInfo psTriInfos[], const int iMyTriIndex, SGroup * pGroup);
     1068static void AddTriToGroup(SGroup * pGroup, const int iTriIndex);
     1069
     1070static 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
     1131static void AddTriToGroup(SGroup * pGroup, const int iTriIndex)
     1132{
     1133    pGroup->pFaceIndices[pGroup->iNrFaces] = iTriIndex;
     1134    ++pGroup->iNrFaces;
     1135}
     1136
     1137static 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
     1192static tbool CompareSubGroups(const SSubGroup * pg1, const SSubGroup * pg2);
     1193static void QuickSort(int* pSortBuffer, int iLeft, int iRight, unsigned int uSeed);
     1194static STSpace EvalTspace(int face_indices[], const int iFaces, const int piTriListIn[], const STriInfo pTriInfos[], const SMikkTSpaceContext * pContext, const int iVertexRepresentitive);
     1195
     1196static 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
     1365static 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
     1439static 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
     1452static 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
     1496static void QuickSortEdges(SEdge * pSortBuffer, int iLeft, int iRight, const int channel, unsigned int uSeed);
     1497static void GetEdge(int * i0_out, int * i1_out, int * edgenum_out, const int indices[], const int i0_in, const int i1_in);
     1498
     1499static 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
     1594static 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
     1643static 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
     1700static 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
     1734static 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
     1817static 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

     
    8080        int m_Frequency;
    8181        VfsPath m_ModelFilename;
    8282        VfsPath m_TextureFilename;
     83        VfsPath m_NormalFilename;
     84        VfsPath m_SpecularFilename;
    8385        Decal m_Decal;
    8486        VfsPath m_Particles;
    8587        CStr m_Color;
     
    9193    struct Variation
    9294    {
    9395        VfsPath texture;
     96        VfsPath normal;
     97        VfsPath specular;
    9498        VfsPath model;
    9599        Decal decal;
    96100        VfsPath particles;
  • source/graphics/TerrainTextureEntry.cpp

     
    4444    // TODO: anisotropy should probably be user-configurable, but we want it to be
    4545    // at least 2 for terrain else the ground looks very blurry when you tilt the
    4646    // camera upwards
    47     texture.SetMaxAnisotropy(2.0f);
     47    texture.SetMaxAnisotropy(2.0f); 
    4848
    4949    if (CRenderer::IsInitialised())
    5050        m_Texture = g_Renderer.GetTextureManager().CreateTexture(texture);
     
    7171        (*it)->AddTerrain(this);
    7272   
    7373    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    }
    7493}
    7594
    7695CTerrainTextureEntry::~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
     27extern "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.
     41int 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

     
    3232    m_DiffuseTexture = texture;
    3333}
    3434
     35void CMaterial::SetNormalTexture(const CTexturePtr& texture)
     36{
     37    m_NormalTexture = texture;
     38}
     39
     40void CMaterial::SetSpecularTexture(const CTexturePtr& texture)
     41{
     42    m_SpecularTexture = texture;
     43}
     44
    3545void CMaterial::SetShaderEffect(const CStr& effect)
    3646{
    3747    m_ShaderEffect = CStrIntern(effect);
  • source/graphics/ObjectBase.cpp

     
    6262    EL(prop);
    6363    EL(mesh);
    6464    EL(texture);
     65    EL(normal);
     66    EL(specular);
    6567    EL(colour);
    6668    EL(decal);
    6769    EL(particles);
     
    151153                    {
    152154                        currentVariant->m_TextureFilename = VfsPath("art/textures/skins") / option.GetText().FromUTF8();
    153155                    }
     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                    }                   
    154164                    else if (option_name == el_decal)
    155165                    {
    156166                        XMBAttributeList attrs = option.GetAttributes();
     
    399409        if (! var.m_TextureFilename.empty())
    400410            variation.texture = var.m_TextureFilename;
    401411
     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
    402418        if (! var.m_ModelFilename.empty())
    403419            variation.model = var.m_ModelFilename;
    404420
  • source/graphics/TerrainProperties.h

     
    6666    GroupVector m_Groups;
    6767
    6868    void LoadXml(XMBElement node, CXeromyces *pFile, const VfsPath& pathname);
     69   
     70    VfsPath m_NormalMap;
     71   
     72    VfsPath m_SpecularMap;
    6973
    7074public:
    7175    CTerrainProperties(CTerrainPropertiesPtr parent);
     
    111115    {
    112116        return m_Groups;
    113117    }
     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    }
    114138};
    115139
    116140#endif
  • source/graphics/ObjectEntry.cpp

     
    6161    // Copy the chosen data onto this model:
    6262
    6363    m_TextureName = variation.texture;
     64    m_NormalName = variation.normal;
     65    m_SpecularName = variation.specular;
    6466    m_ModelName = variation.model;
    6567
    6668    if (! variation.color.empty())
     
    128130    texture->Prefetch(); // if we've loaded this model we're probably going to render it soon, so prefetch its texture
    129131    model->GetMaterial().SetDiffuseTexture(texture);
    130132
     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
    131145    // calculate initial object space bounds, based on vertex positions
    132146    model->CalcStaticObjectBounds();
    133147
  • source/lib/external_libraries/glext_funcs.h

     
    181181FUNC(void, glFramebufferRenderbufferEXT, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer))
    182182FUNC(void, glGetFramebufferAttachmentParameterivEXT, (GLenum target, GLenum attachment, GLenum pname, GLint *params))
    183183FUNC(void, glGenerateMipmapEXT, (GLenum target))
     184FUNC(void, glBlitFramebufferEXT, (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter))
     185FUNC(void, glDrawBuffers, (GLsizei n, const GLenum *bufs))
    184186
     187
    185188// GL_ARB_vertex_program, GL_ARB_fragment_program
    186189FUNC(void, glProgramStringARB, (GLenum target, GLenum format, GLsizei len, const GLvoid *string))
    187190FUNC(void, glBindProgramARB, (GLenum target, GLuint program))
  • source/renderer/PostprocManager.h

     
     1#ifndef INCLUDED_POSTPROCMANAGER
     2#define INCLUDED_POSTPROCMANAGER
     3
     4class PostprocManager
     5{
     6public:
     7   
     8    GLuint pingFbo, pongFbo;
     9    GLuint colourTex1, colourTex2;
     10    GLuint depthTex, stencilTex;
     11    GLuint losTex;
     12   
     13    bool whichBuffer;
     14   
     15    std::vector<std::vector<CShaderTechniquePtr> > renderStages;
     16   
     17    int width, height;
     18   
     19    bool isInitialised;
     20   
     21    PostprocManager();
     22    ~PostprocManager();
     23   
     24    void Initialize();
     25   
     26    void Cleanup();
     27   
     28    void RecreateBuffers();
     29   
     30    void LoadEffect(const char* name, int stage);
     31   
     32    void ApplyEffect(CShaderTechniquePtr &shaderTech1);
     33    void ApplyPostproc(int stage);
     34    void ApplyLos();
     35   
     36    void CaptureRenderOutput();
     37   
     38    void PostprocStage1();
     39    void PostprocStage2();
     40   
     41    void ReleaseRenderOutput();
     42   
     43   
     44   
     45
     46};
     47
     48
     49#endif //INCLUDED_POSTPROCMANAGER
  • source/renderer/PatchRData.h

     
    7272        CVector3D m_Position;
    7373        // diffuse color from sunlight
    7474        SColor4ub m_DiffuseColor;
     75        CVector3D m_Normal;
    7576    };
    76     cassert(sizeof(SBaseVertex) == 16);
     77    cassert(sizeof(SBaseVertex) == 28);
    7778
    7879    struct SSideVertex {
    7980        // vertex position
     
    9192        // vertex uvs for alpha texture
    9293        float m_AlphaUVs[2];
    9394        // add some padding since VBOs prefer power-of-two sizes
    94         u32 m_Padding[2];
     95        //u32 m_Padding[2];
     96        CVector3D m_Normal;
    9597    };
    96     cassert(sizeof(SBlendVertex) == 32);
     98    cassert(sizeof(SBlendVertex) == 36);
    9799
    98100    // Mixed Fancy/Simple water vertex description data structure
    99101    struct SWaterVertex {
  • source/renderer/RenderModifiers.h

     
    7373     */
    7474    virtual void PrepareTexture(const CShaderProgramPtr& shader, CTexture& texture) = 0;
    7575
     76    virtual void PrepareNormal(const CShaderProgramPtr& shader, CTexture& normal) = 0;
     77
     78    virtual void PrepareSpecular(const CShaderProgramPtr& shader, CTexture& specular) = 0;
     79
    7680    /**
    7781     * PrepareModel: Called before rendering the given model.
    7882     *
     
    134138    // Implementation
    135139    void BeginPass(const CShaderProgramPtr& shader);
    136140    void PrepareTexture(const CShaderProgramPtr& shader, CTexture& texture);
     141    void PrepareNormal(const CShaderProgramPtr& shader, CTexture& normal);
     142    void PrepareSpecular(const CShaderProgramPtr& shader, CTexture& specular);
    137143    void PrepareModel(const CShaderProgramPtr& shader, CModel* model);
    138144
    139145private:
     
    141147    CShaderProgram::Binding m_BindingShadingColor;
    142148    CShaderProgram::Binding m_BindingPlayerColor;
    143149    CShaderProgram::Binding m_BindingBaseTex;
     150    CShaderProgram::Binding m_BindingNormTex;
     151    CShaderProgram::Binding m_BindingSpecTex;
    144152};
    145153
    146154#endif // INCLUDED_RENDERMODIFIERS
  • source/renderer/ModelRenderer.cpp

     
    3535#include "renderer/ModelVertexRenderer.h"
    3636#include "renderer/Renderer.h"
    3737#include "renderer/RenderModifiers.h"
     38#include "renderer/MikktspaceWrap.h"
    3839
    3940#include <boost/weak_ptr.hpp>
    4041
     
    5758#endif
    5859}
    5960
     61void ModelRenderer::GenTangents(const CModelDefPtr& mdef, std::vector<float>& newVertices)
     62{
     63    MikkTSpace ms(mdef, newVertices);
     64
     65    ms.generate();
     66}
     67
    6068// Helper function to copy object-space position and normal vectors into arrays.
    6169void ModelRenderer::CopyPositionAndNormals(
    6270        const CModelDefPtr& mdef,
     
    557565                m->vertexRenderer->BeginPass(streamflags);
    558566
    559567                CTexture* currentTex = NULL;
     568                CTexture* currentNorm = NULL;
     569                CTexture* currentSpec = NULL;
    560570                CModelDef* currentModeldef = NULL;
    561571                CShaderUniforms currentStaticUniforms;
    562572                // (Texture needs to be rebound after binding a new shader, so we
     
    581591                            modifier->PrepareTexture(shader, *currentTex);
    582592                        }
    583593
     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
    584608                        // Bind modeldef when it changes
    585609                        CModelDef* newModeldef = model->GetModelDef().get();
    586610                        if (newModeldef != currentModeldef)
  • source/renderer/MikktspaceWrap.h

     
     1#ifndef INCLUDED_MIKKWRAP
     2#define INCLUDED_MIKKWRAP
     3
     4
     5#include <graphics/mikktspace.h>
     6
     7class MikkTSpace
     8{
     9
     10public:
     11   
     12    MikkTSpace(const CModelDefPtr& m, std::vector<float>& v);
     13
     14    void generate();
     15   
     16private:
     17   
     18    SMikkTSpaceInterface interface;
     19    SMikkTSpaceContext context;
     20
     21    const CModelDefPtr& model;
     22
     23    std::vector<float>& newVertices;
     24   
     25
     26    // Returns the number of faces (triangles/quads) on the mesh to be processed.
     27    static int getNumFaces(const SMikkTSpaceContext *pContext);
     28
     29
     30    // Returns the number of vertices on face number iFace
     31    // iFace is a number in the range {0, 1, ..., getNumFaces()-1}
     32    static int getNumVerticesOfFace(const SMikkTSpaceContext *pContext, const int iFace);
     33
     34
     35    // returns the position/normal/texcoord of the referenced face of vertex number iVert.
     36    // iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads.
     37    static void getPosition(const SMikkTSpaceContext *pContext,
     38            float fvPosOut[], const int iFace, const int iVert);
     39
     40    static void getNormal(const SMikkTSpaceContext *pContext,
     41            float fvNormOut[], const int iFace, const int iVert);
     42
     43    static void getTexCoord(const SMikkTSpaceContext *pContext,
     44            float fvTexcOut[], const int iFace, const int iVert);
     45
     46
     47    // either (or both) of the two setTSpace callbacks can be set.
     48    // The call-back m_setTSpaceBasic() is sufficient for basic normal mapping.
     49
     50    // This function is used to return the tangent and fSign to the application.
     51    // fvTangent is a unit length vector.
     52    // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
     53    // bitangent = fSign * cross(vN, tangent);
     54    // Note that the results are returned unindexed. It is possible to generate a new index list
     55    // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results.
     56    // DO NOT! use an already existing index list.
     57    //void setTSpaceBasic(const MikkTSpace *parent, const SMikkTSpaceContext *pContext,
     58    //      const float fvTangent[], const float fSign, const int iFace, const int iVert);
     59
     60
     61    // This function is used to return tangent space results to the application.
     62    // fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are their
     63    // true magnitudes which can be used for relief mapping effects.
     64    // fvBiTangent is the "real" bitangent and thus may not be perpendicular to fvTangent.
     65    // However, both are perpendicular to the vertex normal.
     66    // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
     67    // fSign = bIsOrientationPreserving ? 1.0f : (-1.0f);
     68    // bitangent = fSign * cross(vN, tangent);
     69    // Note that the results are returned unindexed. It is possible to generate a new index list
     70    // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results.
     71    // DO NOT! use an already existing index list.
     72    static void setTSpace(const SMikkTSpaceContext * pContext, const float fvTangent[],
     73            const float fvBiTangent[], const float fMagS, const float fMagT,
     74            const tbool bIsOrientationPreserving, const int iFace, const int iVert);
     75
     76
     77};
     78
     79
     80#endif // INCLUDED_MIKKWRAP
     81 No newline at end of file
  • source/renderer/PostprocManager.cpp

     
     1#include "precompiled.h"
     2
     3#include "lib/ogl.h"
     4#include "maths/MathUtil.h"
     5
     6#include "gui/GUIutil.h"
     7#include "lib/bits.h"
     8#include "ps/CLogger.h"
     9
     10#include "graphics/ShaderManager.h"
     11#include "renderer/Renderer.h"
     12
     13#include "renderer/PostprocManager.h"
     14
     15
     16PostprocManager::PostprocManager()
     17{
     18    isInitialised = false;
     19    pingFbo = 0;
     20    pongFbo = 0;
     21    colourTex1 = 0;
     22    colourTex2 = 0;
     23    depthTex = 0;
     24    stencilTex = 0;
     25    losTex = 0;
     26    whichBuffer = true;
     27}
     28
     29
     30PostprocManager::~PostprocManager()
     31{
     32    Cleanup();
     33}
     34
     35void PostprocManager::Initialize()
     36{
     37    RecreateBuffers();
     38    isInitialised = true;
     39   
     40    renderStages = std::vector<std::vector<CShaderTechniquePtr> >(5);
     41   
     42    LoadEffect("ssao", 1);     
     43
     44   
     45    LoadEffect("fog", 1);
     46    LoadEffect("hdr",   1);
     47    LoadEffect("bloom", 1);
     48   
     49    LoadEffect("los", 4);
     50}
     51
     52void PostprocManager::Cleanup()
     53{
     54    if (isInitialised)
     55    {
     56        if (pingFbo) pglDeleteFramebuffersEXT(1, &pingFbo);
     57        if (pongFbo) pglDeleteFramebuffersEXT(1, &pongFbo);
     58        if (colourTex1) glDeleteTextures(1, &colourTex1);
     59        if (colourTex2) glDeleteTextures(1, &colourTex2);
     60        if (depthTex) glDeleteTextures(1, &depthTex);
     61        if (losTex) glDeleteTextures(1, &losTex);
     62    }
     63}
     64
     65
     66void PostprocManager::RecreateBuffers()
     67{
     68    Cleanup();
     69       
     70   
     71    width = g_Renderer.GetWidth();
     72    height = g_Renderer.GetHeight();
     73
     74   
     75    glGenTextures(1, (GLuint*)&colourTex1);
     76    glBindTexture(GL_TEXTURE_2D, colourTex1);
     77    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
     78            GL_UNSIGNED_BYTE, 0);
     79    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     80    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     81    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
     82    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
     83   
     84       
     85    glGenTextures(1, (GLuint*)&colourTex2);
     86    glBindTexture(GL_TEXTURE_2D, colourTex2);
     87    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
     88            GL_UNSIGNED_BYTE, 0);
     89    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     90    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     91    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
     92    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
     93
     94
     95    glGenTextures(1, (GLuint*)&depthTex);
     96    glBindTexture(GL_TEXTURE_2D, depthTex);
     97    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, width, height,
     98              0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE,NULL);
     99    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,
     100            GL_NONE);
     101    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     102    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     103    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
     104    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
     105   
     106   
     107    glGenTextures(1, (GLuint*)&stencilTex);
     108    glBindTexture(GL_TEXTURE_2D, stencilTex);
     109    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height,
     110              0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8,NULL);
     111    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,
     112            GL_NONE);
     113    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     114    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     115    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
     116    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
     117   
     118   
     119    glGenTextures(1, (GLuint*)&losTex);
     120    glBindTexture(GL_TEXTURE_2D, losTex);
     121    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE16, width, height,
     122          0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0);
     123    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     124    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     125    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
     126    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
     127
     128    /*glGenTextures(1, (GLuint*)&lumaTex);
     129    glBindTexture(GL_TEXTURE_2D, lumaTex);
     130    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE16, width, height,
     131          0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0);
     132    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     133    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     134    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
     135    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);*/
     136   
     137    glBindTexture(GL_TEXTURE_2D, 0);
     138
     139    pglGenFramebuffersEXT(1, &pingFbo);
     140    pglBindFramebufferEXT(GL_FRAMEBUFFER, pingFbo);
     141    pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colourTex1, 0);
     142    pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, losTex, 0);
     143    //pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, lumaTex, 0);
     144    pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, stencilTex, 0);
     145   
     146    GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
     147    if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
     148    {
     149        LOGWARNING(L"Framebuffer object incomplete (A): 0x%04X", status);
     150    }
     151   
     152    pglGenFramebuffersEXT(1, &pongFbo);
     153    pglBindFramebufferEXT(GL_FRAMEBUFFER, pongFbo);
     154    pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colourTex2, 0);
     155    pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, losTex, 0);
     156    //pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, lumaTex, 0);
     157    pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, stencilTex, 0);
     158   
     159    status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
     160    if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
     161    {
     162        LOGWARNING(L"Framebuffer object incomplete (B): 0x%04X", status);
     163    }
     164   
     165
     166    pglBindFramebufferEXT(GL_FRAMEBUFFER, 0);
     167}
     168
     169
     170void PostprocManager::CaptureRenderOutput()
     171{
     172    /*glBindTexture(GL_TEXTURE_2D, colourTex1);
     173    glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, width, height, 0);
     174    glBindTexture(GL_TEXTURE_2D, depthTex);
     175    glCopyTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT, 0, 0, width, height, 0);*/
     176    //glBindTexture(GL_TEXTURE_2D, lumaTex);
     177    //glCopyTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE16, 0, 0, width, height, 0);
     178   
     179   
     180    // clear both FBOs and leave pingFbo selected for rendering;
     181    // whichBuffer stays true at this point
     182    pglBindFramebufferEXT(GL_FRAMEBUFFER, pongFbo);
     183    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
     184   
     185    GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
     186    pglDrawBuffers(2, buffers);
     187   
     188    pglBindFramebufferEXT(GL_FRAMEBUFFER, pingFbo);
     189    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
     190    pglDrawBuffers(2, buffers);
     191    //glClear(GL_COLOR_BUFFER_BIT);
     192   
     193    whichBuffer = true;
     194}
     195
     196
     197void PostprocManager::ReleaseRenderOutput()
     198{
     199    ApplyLos();
     200   
     201    pglBindFramebufferEXT(GL_FRAMEBUFFER, 0);
     202    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
     203   
     204    // we blit to screen from the previous buffer active
     205    if (whichBuffer)
     206        pglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, pingFbo);
     207    else
     208        pglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, pongFbo);
     209   
     210    pglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
     211    pglBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height,
     212                  GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
     213    pglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
     214
     215   
     216   
     217    pglBindFramebufferEXT(GL_FRAMEBUFFER, 0);
     218   
     219}
     220
     221void PostprocManager::LoadEffect(const char* name, int stage)
     222{
     223    CShaderTechniquePtr shaderTech1 = g_Renderer.GetShaderManager().LoadEffect(name);
     224   
     225    renderStages[stage].push_back(shaderTech1);
     226   
     227}
     228
     229void PostprocManager::ApplyEffect(CShaderTechniquePtr &shaderTech1)
     230{
     231    ///CaptureRenderOutput();
     232   
     233    // select the other FBO for rendering
     234    if (!whichBuffer)
     235        pglBindFramebufferEXT(GL_FRAMEBUFFER, pingFbo);
     236    else
     237        pglBindFramebufferEXT(GL_FRAMEBUFFER, pongFbo);
     238   
     239   
     240   
     241    glDisable(GL_DEPTH_TEST);
     242    glDepthMask(GL_FALSE);
     243
     244    shaderTech1->BeginPass();
     245    CShaderProgramPtr shader = shaderTech1->GetShader();
     246   
     247    shader->Bind();
     248   
     249    // use the textures from the current FBO as input to the shader
     250    if (whichBuffer)
     251        shader->BindTexture("bgl_RenderedTexture", colourTex1);
     252    else
     253        shader->BindTexture("bgl_RenderedTexture", colourTex2);
     254   
     255    shader->BindTexture("bgl_DepthTexture", stencilTex);
     256   
     257    //shader->BindTexture("losTexPersp", losTex);
     258   
     259    shader->Uniform("bgl_RenderedTextureWidth", width);
     260    shader->Uniform("bgl_RenderedTextureHeight", height);
     261   
     262    glBegin(GL_QUADS);
     263        glColor4f(1.f, 1.f, 1.f, 1.f);
     264        glTexCoord2f(1.0, 1.0); glVertex2f(1,1);
     265        glTexCoord2f(0.0, 1.0); glVertex2f(-1,1);       
     266        glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1);
     267        glTexCoord2f(1.0, 0.0); glVertex2f(1,-1);
     268    glEnd();
     269   
     270    shader->Unbind();
     271   
     272    shaderTech1->EndPass();
     273       
     274    glDepthMask(GL_TRUE);
     275    glEnable(GL_DEPTH_TEST);
     276   
     277    whichBuffer = !whichBuffer;
     278}
     279
     280
     281
     282void PostprocManager::ApplyPostproc(int stage)
     283{
     284    if (!isInitialised)
     285        return;
     286   
     287    pglBindFramebufferEXT(GL_FRAMEBUFFER, pongFbo);
     288    pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, 0, 0);
     289   
     290    GLenum buffers[] = { GL_COLOR_ATTACHMENT0 };
     291    pglDrawBuffers(1, buffers);
     292   
     293    pglBindFramebufferEXT(GL_FRAMEBUFFER, pingFbo);
     294    pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, 0, 0);
     295    pglDrawBuffers(1, buffers);
     296   
     297   
     298    pglBindFramebufferEXT(GL_FRAMEBUFFER, pongFbo);
     299    pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
     300   
     301    pglBindFramebufferEXT(GL_FRAMEBUFFER, pingFbo);
     302    pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
     303   
     304    std::vector<CShaderTechniquePtr> &effects = renderStages[stage];
     305   
     306    //std::cout << "EFFECT!!! " << effects.size() << std::endl;
     307   
     308    for (size_t i = 0; i < effects.size(); i++)
     309    {       
     310        ApplyEffect(effects[i]);
     311    }
     312   
     313    pglBindFramebufferEXT(GL_FRAMEBUFFER, pongFbo);
     314    pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, stencilTex, 0);
     315   
     316    pglBindFramebufferEXT(GL_FRAMEBUFFER, pingFbo);
     317    pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, stencilTex, 0);
     318}
     319
     320
     321void PostprocManager::ApplyLos()
     322{
     323   
     324   
     325    CShaderTechniquePtr &shaderTech1 = renderStages[4][0];
     326       
     327    //CShaderProgramPtr shader = shaderTech1->GetShader();
     328   
     329   
     330    //ApplyEffect(shaderTech1);
     331   
     332   
     333   
     334    if (!whichBuffer)
     335        pglBindFramebufferEXT(GL_FRAMEBUFFER, pingFbo);
     336    else
     337        pglBindFramebufferEXT(GL_FRAMEBUFFER, pongFbo);
     338   
     339   
     340   
     341    glDisable(GL_DEPTH_TEST);
     342    glDepthMask(GL_FALSE);
     343
     344    shaderTech1->BeginPass();
     345    CShaderProgramPtr shader = shaderTech1->GetShader();
     346   
     347    shader->Bind();
     348   
     349    // use the textures from the current FBO as input to the shader
     350    if (whichBuffer)
     351        shader->BindTexture("bgl_RenderedTexture", colourTex1);
     352    else
     353        shader->BindTexture("bgl_RenderedTexture", colourTex2);
     354   
     355    //shader->BindTexture("bgl_DepthTexture", stencilTex);
     356   
     357    shader->BindTexture("losTexPersp", losTex);
     358   
     359    shader->Uniform("bgl_RenderedTextureWidth", width);
     360    shader->Uniform("bgl_RenderedTextureHeight", height);
     361   
     362    glBegin(GL_QUADS);
     363        glColor4f(1.f, 1.f, 1.f, 1.f);
     364        glTexCoord2f(1.0, 1.0); glVertex2f(1,1);
     365        glTexCoord2f(0.0, 1.0); glVertex2f(-1,1);       
     366        glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1);
     367        glTexCoord2f(1.0, 0.0); glVertex2f(1,-1);
     368    glEnd();
     369   
     370    shader->Unbind();
     371   
     372    shaderTech1->EndPass();
     373       
     374    glDepthMask(GL_TRUE);
     375    glEnable(GL_DEPTH_TEST);
     376   
     377    whichBuffer = !whichBuffer;
     378   
     379    pglBindFramebufferEXT(GL_FRAMEBUFFER, pongFbo);
     380    pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, losTex, 0);
     381   
     382    pglBindFramebufferEXT(GL_FRAMEBUFFER, pingFbo);
     383    pglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, losTex, 0);
     384       
     385}
  • source/renderer/InstancingModelRenderer.cpp

     
    3131#include "graphics/LightEnv.h"
    3232#include "graphics/Model.h"
    3333#include "graphics/ModelDef.h"
     34#include "graphics/weldmesh.h"
    3435
    3536#include "renderer/InstancingModelRenderer.h"
    3637#include "renderer/Renderer.h"
     
    4950    /// Position, normals and UV are all static
    5051    VertexArray::Attribute m_Position;
    5152    VertexArray::Attribute m_Normal;
     53    VertexArray::Attribute m_Tangent;
    5254    VertexArray::Attribute m_UV;
    5355    VertexArray::Attribute m_BlendJoints; // valid iff gpuSkinning == true
    5456    VertexArray::Attribute m_BlendWeights; // valid iff gpuSkinning == true
     
    7678    m_UV.type = GL_FLOAT;
    7779    m_UV.elems = 2;
    7880    m_Array.AddAttribute(&m_UV);
     81   
     82    m_Tangent.type = GL_FLOAT;
     83    m_Tangent.elems = 4;
     84    m_Array.AddAttribute(&m_Tangent);
    7985
    8086    if (gpuSkinning)
    8187    {
     
    8793        m_BlendWeights.elems = 4;
    8894        m_Array.AddAttribute(&m_BlendWeights);
    8995    }
     96   
    9097
    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);
    92118    m_Array.Layout();
    93119
    94120    VertexArrayIterator<CVector3D> Position = m_Position.GetIterator<CVector3D>();
    95121    VertexArrayIterator<CVector3D> Normal = m_Normal.GetIterator<CVector3D>();
    96122    VertexArrayIterator<float[2]> UVit = m_UV.GetIterator<float[2]>();
     123    VertexArrayIterator<CVector4D> Tangent = m_Tangent.GetIterator<CVector4D>();
    97124
    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    }
    100141
    101142    if (gpuSkinning)
    102143    {
     
    118159
    119160    m_IndexArray.SetNumVertices(mdef->GetNumFaces()*3);
    120161    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   
    122176    m_IndexArray.Upload();
    123177    m_IndexArray.FreeBackingStore();
    124178}
     
    211265    if (streamflags & STREAM_UV0)
    212266        shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, stride, base + m->imodeldef->m_UV.offset);
    213267
     268    shader->VertexAttribPointer("a_tangent", 4, GL_FLOAT, GL_TRUE, stride, base + m->imodeldef->m_Tangent.offset);
     269
    214270    // GPU skinning requires extra attributes to compute positions/normals
    215271    if (m->gpuSkinning)
    216272    {
  • source/renderer/Renderer.cpp

     
    4444#include "ps/Loader.h"
    4545#include "ps/ProfileViewer.h"
    4646#include "graphics/Camera.h"
     47#include "graphics/LOSTexture.h"
    4748#include "graphics/GameView.h"
    4849#include "graphics/LightEnv.h"
    4950#include "graphics/MaterialManager.h"
     
    6667#include "renderer/TerrainRenderer.h"
    6768#include "renderer/VertexBufferManager.h"
    6869#include "renderer/WaterManager.h"
     70#include "renderer/PostprocManager.h"
    6971
    7072
    7173///////////////////////////////////////////////////////////////////////////////////
     
    271273
    272274    /// Shadow map
    273275    ShadowMap shadow;
     276   
     277    PostprocManager postprocManager;
    274278
    275279    /// Various model renderers
    276280    struct Models
     
    631635    // Let component renderers perform one-time initialization after graphics capabilities and
    632636    // the shader path have been determined.
    633637    m->overlayRenderer.Initialize();
     638   
     639    m->postprocManager.Initialize();
    634640
    635641    return true;
    636642}
     
    639645void CRenderer::Resize(int width,int height)
    640646{
    641647    // need to recreate the shadow map object to resize the shadow texture
    642     m->shadow.RecreateTexture();
     648    m->shadow.RecreateTexture();   
    643649
    644650    m_Width = width;
    645651    m_Height = height;
     652   
     653    m->postprocManager.RecreateBuffers();
    646654}
    647655
    648656//////////////////////////////////////////////////////////////////////////////////////////
     
    705713// SetRenderPath: Select the preferred render path.
    706714// This may only be called before Open(), because the layout of vertex arrays and other
    707715// data may depend on the chosen render path.
    708 void CRenderer::SetRenderPath(RenderPath rp)
     716void CRenderer::SetRenderPath(RenderPath rp) 
    709717{
    710718    if (!m->IsOpen)
    711719    {
     
    769777//////////////////////////////////////////////////////////////////////////////////////////
    770778// BeginFrame: signal frame start
    771779void CRenderer::BeginFrame()
    772 {
     780{   
    773781    PROFILE("begin frame");
    774782
    775783    // zero out all the per-frame stats
     
    13511359// RenderSubmissions: force rendering of any batched objects
    13521360void CRenderer::RenderSubmissions()
    13531361{
    1354     PROFILE3("render submissions");
     1362    GetScene().GetLOSTexture().InterpolateLOS();
     1363   
     1364    if (GetRenderPath() == RP_SHADER)
     1365        m->postprocManager.CaptureRenderOutput();
     1366   
     1367    PROFILE3("render submissions");
    13551368
    13561369    CShaderDefines context = m->globalContext;
    13571370
     
    13801393    if (m_Caps.m_Shadows && m_Options.m_Shadows && GetRenderPath() == RP_SHADER)
    13811394    {
    13821395        RenderShadowMap(context);
    1383     }
     1396    }   
    13841397
    13851398    {
    13861399        PROFILE3_GPU("clear buffers");
     
    14151428            }
    14161429        }
    14171430    }
     1431   
    14181432
     1433    RenderModels(context);
     1434    ogl_WarnIfError(); 
     1435
     1436    //if (GetRenderPath() == RP_SHADER)
     1437    //  m->postprocManager.ApplyPostproc(0);
     1438
    14191439    // render submitted patches and models
    14201440    RenderPatches(context);
    14211441    ogl_WarnIfError();
     
    14281448    m->overlayRenderer.RenderOverlaysBeforeWater();
    14291449    ogl_WarnIfError();
    14301450
    1431     RenderModels(context);
    1432     ogl_WarnIfError();
    1433 
    14341451    // render water
    14351452    if (m_WaterManager->m_RenderWater && g_Game && waterScissor.GetVolume() > 0)
    14361453    {
     
    14551472    // render debug-related terrain overlays
    14561473    ITerrainOverlay::RenderOverlaysAfterWater();
    14571474    ogl_WarnIfError();
     1475   
     1476    if (GetRenderPath() == RP_SHADER)
     1477        m->postprocManager.ApplyPostproc(1);
    14581478
    14591479    // render some other overlays after water (so they can be displayed on top of water)
    14601480    m->overlayRenderer.RenderOverlaysAfterWater();
    14611481    ogl_WarnIfError();
    1462 
     1482   
    14631483    // particles are transparent so render after water
    14641484    if (m_Options.m_Particles)
    14651485    {
    14661486        RenderParticles();
    14671487        ogl_WarnIfError();
    1468     }
     1488    }   
    14691489
    14701490    if (m_Options.m_Silhouettes)
    14711491    {
     
    14901510    // render overlays that should appear on top of all other objects
    14911511    m->overlayRenderer.RenderForegroundOverlays(m_ViewCamera);
    14921512    ogl_WarnIfError();
     1513       
     1514    if (GetRenderPath() == RP_SHADER)
     1515        m->postprocManager.ReleaseRenderOutput();
    14931516}
    14941517
    14951518///////////////////////////////////////////////////////////////////////////////////////////////////
  • source/renderer/PatchRData.cpp

     
    367367
    368368    terrain->CalcPosition(gx, gz, dst.m_Position);
    369369    terrain->CalcNormal(gx, gz, normal);
     370    dst.m_Normal = normal;
    370371    dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal);
    371372    dst.m_AlphaUVs[0] = vtx[0].m_AlphaUVs[0];
    372373    dst.m_AlphaUVs[1] = vtx[0].m_AlphaUVs[1];
     
    374375
    375376    terrain->CalcPosition(gx + 1, gz, dst.m_Position);
    376377    terrain->CalcNormal(gx + 1, gz, normal);
     378    dst.m_Normal = normal;
    377379    dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal);
    378380    dst.m_AlphaUVs[0] = vtx[1].m_AlphaUVs[0];
    379381    dst.m_AlphaUVs[1] = vtx[1].m_AlphaUVs[1];
     
    381383
    382384    terrain->CalcPosition(gx + 1, gz + 1, dst.m_Position);
    383385    terrain->CalcNormal(gx + 1, gz + 1, normal);
     386    dst.m_Normal = normal;
    384387    dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal);
    385388    dst.m_AlphaUVs[0] = vtx[2].m_AlphaUVs[0];
    386389    dst.m_AlphaUVs[1] = vtx[2].m_AlphaUVs[1];
     
    388391
    389392    terrain->CalcPosition(gx, gz + 1, dst.m_Position);
    390393    terrain->CalcNormal(gx, gz + 1, normal);
     394    dst.m_Normal = normal;
    391395    dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal);
    392396    dst.m_AlphaUVs[0] = vtx[3].m_AlphaUVs[0];
    393397    dst.m_AlphaUVs[1] = vtx[3].m_AlphaUVs[1];
     
    546550            // for all vertices, it need not be stored in the vertex structure)
    547551            CVector3D normal;
    548552            terrain->CalcNormal(ix,iz,normal);
     553           
     554            vertices[v].m_Normal = normal;
    549555
    550556            vertices[v].m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal);
    551557        }
     
    747753        if (itt->first)
    748754        {
    749755            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());
    750765
    751766#if !CONFIG2_GLES
    752767            if (isDummyShader)
     
    774789            SBaseVertex *base = (SBaseVertex *)itv->first->Bind();
    775790            shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]);
    776791            shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, &base->m_DiffuseColor);
     792            shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]);               
    777793            shader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, &base->m_Position[0]);
    778794
    779795            shader->AssertPointersBound();
     
    932948        if (itt->m_Texture)
    933949        {
    934950            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           
    935961
    936962#if !CONFIG2_GLES
    937963            if (isDummyShader)
     
    965991
    966992                shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]);
    967993                shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, &base->m_DiffuseColor);
     994                shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]);
    968995                shader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, &base->m_Position[0]);
    969996                shader->TexCoordPointer(GL_TEXTURE1, 2, GL_FLOAT, stride, &base->m_AlphaUVs[0]);
    970997            }
  • source/renderer/RenderModifiers.cpp

     
    9595    if (shader->GetTextureBinding("losTex").Active())
    9696    {
    9797        CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture();
    98         shader->BindTexture("losTex", los.GetTexture());
     98        shader->BindTexture("losTex", los.GetTextureSmooth());
    9999        // Don't bother sending the whole matrix, we just need two floats (scale and translation)
    100100        shader->Uniform("losTransform", los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f);
    101101    }
     
    104104    m_BindingShadingColor = shader->GetUniformBinding("shadingColor");
    105105    m_BindingPlayerColor = shader->GetUniformBinding("playerColor");
    106106    m_BindingBaseTex = shader->GetTextureBinding("baseTex");
     107    m_BindingNormTex = shader->GetTextureBinding("normTex");
     108    m_BindingSpecTex = shader->GetTextureBinding("specTex");
    107109}
    108110
    109111void ShaderRenderModifier::PrepareTexture(const CShaderProgramPtr& shader, CTexture& texture)
     
    112114        shader->BindTexture(m_BindingBaseTex, texture.GetHandle());
    113115}
    114116
     117void ShaderRenderModifier::PrepareNormal(const CShaderProgramPtr& shader, CTexture& normal)
     118{
     119    if (m_BindingNormTex.Active())
     120        shader->BindTexture(m_BindingNormTex, normal.GetHandle());
     121}
     122
     123void ShaderRenderModifier::PrepareSpecular(const CShaderProgramPtr& shader, CTexture& specular)
     124{
     125    if (m_BindingSpecTex.Active())
     126        shader->BindTexture(m_BindingSpecTex, specular.GetHandle());
     127}
     128
    115129void ShaderRenderModifier::PrepareModel(const CShaderProgramPtr& shader, CModel* model)
    116130{
    117131    if (m_BindingInstancingTransform.Active())
  • source/renderer/ShadowMap.cpp

     
    8383    // Copy of renderer's standard view camera, saved between
    8484    // BeginRender and EndRender while we replace it with the shadow camera
    8585    CCamera SavedViewCamera;
     86   
     87    // Save the caller's FBO so it can be restored
     88    GLint originalFBO;
    8689
    8790    // Helper functions
    8891    void CalcShadowMatrices();
     
    318321        pglDeleteFramebuffersEXT(1, &Framebuffer);
    319322        Framebuffer = 0;
    320323    }
     324   
     325    // save the caller's FBO   
     326    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &originalFBO);
    321327
    322328    pglGenFramebuffersEXT(1, &Framebuffer);
    323329
     
    433439
    434440    GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
    435441
    436     pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
     442    pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, originalFBO);
    437443
    438444    if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
    439445    {
     
    451457{
    452458    // HACK HACK: this depends in non-obvious ways on the behaviour of the caller
    453459
     460    // save caller's FBO
     461    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m->originalFBO);
     462   
    454463    // Calc remaining shadow matrices
    455464    m->CalcShadowMatrices();
    456465
     
    502511
    503512    {
    504513        PROFILE("unbind framebuffer");
    505         pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
     514        pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m->originalFBO);
    506515    }
    507516
    508517    glViewport(0, 0, g_Renderer.GetWidth(), g_Renderer.GetHeight());
  • source/renderer/MikktspaceWrap.cpp

     
     1
     2#include "precompiled.h"
     3
     4#include <boost/bind.hpp>
     5
     6#include "graphics/Color.h"
     7#include "graphics/LightEnv.h"
     8#include "graphics/Model.h"
     9#include "graphics/ModelDef.h"
     10#include "graphics/ShaderManager.h"
     11#include "graphics/TextureManager.h"
     12#include <graphics/mikktspace.h>
     13
     14#include <renderer/MikktspaceWrap.h>
     15
     16
     17
     18MikkTSpace::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
     32void MikkTSpace::generate()
     33{
     34    genTangSpaceDefault(&context);
     35}
     36
     37
     38int MikkTSpace::getNumFaces(const SMikkTSpaceContext *pContext)
     39{
     40    return ((MikkTSpace*)pContext->m_pUserData)->model->GetNumFaces();
     41}
     42
     43
     44int MikkTSpace::getNumVerticesOfFace(const SMikkTSpaceContext *pContext, const int iFace)
     45{
     46    return 3;
     47}
     48
     49
     50void 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
     63void 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
     76void 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
     88void MikkTSpace::setTSpace(const SMikkTSpaceContext * pContext, const float fvTangent[],
     89        const float fvBiTangent[], const float fMagS, const float fMagT,
     90        const tbool bIsOrientationPreserving, const int iFace, const int iVert)
     91{
     92    SModelFace &face = ((MikkTSpace*)pContext->m_pUserData)->model->GetFaces()[iFace];
     93    long i = face.m_Verts[iVert];
     94   
     95    const CVector3D &p = ((MikkTSpace*)pContext->m_pUserData)->model->GetVertices()[i].m_Coords;
     96    const CVector3D &n = ((MikkTSpace*)pContext->m_pUserData)->model->GetVertices()[i].m_Norm;
     97    const float u = ((MikkTSpace*)pContext->m_pUserData)->model->GetVertices()[i].m_U;
     98    const float v = 1.0 - ((MikkTSpace*)pContext->m_pUserData)->model->GetVertices()[i].m_V;
     99   
     100    ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(p.X);
     101    ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(p.Y);
     102    ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(p.Z);
     103   
     104    ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(n.X);
     105    ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(n.Y);
     106    ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(n.Z);
     107   
     108    ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(u);
     109    ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(v);
     110   
     111    ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(fvTangent[0]);
     112    ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(fvTangent[1]);
     113    ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(fvTangent[2]);
     114    ((MikkTSpace*)pContext->m_pUserData)->newVertices.push_back(bIsOrientationPreserving > 0.5 ? 1.0f : (-1.0f));
     115}
     116
     117
     118
  • source/renderer/TerrainRenderer.cpp

     
    477477    shader->Uniform("sunColor", lightEnv.m_SunColor);
    478478
    479479    CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture();
    480     shader->BindTexture("losTex", los.GetTexture());
     480    shader->BindTexture("losTex", los.GetTextureSmooth());
    481481    shader->Uniform("losTransform", los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f);
    482482
    483483    shader->Uniform("ambient", lightEnv.m_TerrainAmbientColor);
     
    709709    m->fancyWaterShader->BindTexture("reflectionMap", WaterMgr->m_ReflectionTexture);
    710710    m->fancyWaterShader->BindTexture("refractionMap", WaterMgr->m_RefractionTexture);
    711711
    712     m->fancyWaterShader->BindTexture("losMap", losTexture.GetTexture());
     712    m->fancyWaterShader->BindTexture("losMap", losTexture.GetTextureSmooth());
    713713
    714714    const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
    715715    m->fancyWaterShader->Uniform("ambient", lightEnv.m_TerrainAmbientColor);
  • source/renderer/ModelRenderer.h

     
    253253    static void BuildIndices(
    254254            const CModelDefPtr& mdef,
    255255            const VertexArrayIterator<u16>& Indices);
     256
     257
     258    static void GenTangents(const CModelDefPtr& mdef, std::vector<float>& newVertices);
    256259};
    257260
    258261
  • binaries/data/mods/public/maps/scenarios/Hellenised_Egypt.xml

     
    44    <Environment>
    55        <LightingModel>standard</LightingModel>
    66        <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"/>
    88        <SunElevation angle="0.877437"/>
    99        <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"/>
    1212        <Water>
    1313            <WaterBody>
    1414                <Type>default</Type>
     
    2424        </Water>
    2525    </Environment>
    2626    <Camera>
    27         <Position x="322.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"/>
    2929        <Declination angle="0.610865"/>
    3030    </Camera>
    3131    <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

     
    33<!DOCTYPE Terrains SYSTEM "/art/textures/terrain/types/terrains.dtd">
    44
    55<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"/>
    77</Terrains>
  • binaries/data/mods/public/art/textures/terrain/types/snow/snow

     
     1<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
     2
     3<!DOCTYPE Terrains SYSTEM "/art/textures/terrain/types/terrains.dtd">
     4
     5<Terrains>
     6    <Terrain normalmap="art/textures/terrain/types/snow/snow grass 2_norm.png" specularmap="art/textures/terrain/types/snow/snow grass 2_spec.png"/>
     7</Terrains>
  • binaries/data/mods/public/art/particles/rain.xml

     
    66
    77    <start_full/>
    88
    9     <constant name="emissionrate" value="300.0"/>
     9    <constant name="emissionrate" value="3000.0"/>
    1010    <uniform name="lifetime" min="4.0" max="5.0"/>
    1111
    1212    <uniform name="position.x" min="-50.0" max="50.0"/>
  • binaries/data/mods/public/art/actors/structures/romans/civic_centre.xml

     
    1515        <prop actor="props/units/weapons/arrow_front.xml" attachpoint="projectile"/>
    1616      </props>
    1717      <texture>structural/rome_struct.png</texture>
     18      <normal>structural/rome_struct_norm.png</normal>
     19      <specular>structural/rome_struct_spec.png</specular>
    1820    </variant>
    1921  </group>
    2022  <group>
     
    3638      </props>
    3739    </variant>
    3840  </group>
    39   <material>player_trans.xml</material>
     41  <material>player_trans_norm.xml</material>
    4042</actor>
  • binaries/data/mods/public/art/actors/structures/romans/triumphal_arch.xml

     
    55    <variant frequency="100" name="Roman Triumphal Arch">
    66      <mesh>structural/rome_arch.dae</mesh>
    77      <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>
    810    </variant>
    911  </group>
    1012  <group>
     
    1719      </props>
    1820    </variant>
    1921  </group>
    20   <material>player_trans.xml</material>
     22  <material>player_trans_norm.xml</material>
    2123</actor>
  • binaries/data/mods/public/shaders/effects/model_norm.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<effect>
     3
     4    <technique>
     5        <require context="MODE_SHADOWCAST || MODE_SILHOUETTEOCCLUDER"/>
     6        <require shaders="arb"/>
     7        <pass shader="arb/model_solid"/>
     8    </technique>
     9
     10    <technique>
     11        <require context="MODE_SHADOWCAST || MODE_SILHOUETTEOCCLUDER"/>
     12        <require shaders="glsl"/>
     13        <pass shader="glsl/model_solid"/>
     14    </technique>
     15
     16    <technique>
     17        <require context="MODE_SHADOWCAST || MODE_SILHOUETTEOCCLUDER"/>
     18        <require shaders="fixed"/>
     19        <define name="USE_PLAYERCOLOR" value="0"/>
     20        <define name="USE_OBJECTCOLOR" value="0"/>
     21        <pass shader="fixed:model_solid"/>
     22    </technique>
     23
     24
     25    <technique>
     26        <require context="MODE_SILHOUETTEDISPLAY || MODE_WIREFRAME"/>
     27        <require shaders="arb"/>
     28        <pass shader="arb/model_solid_player"/>
     29    </technique>
     30
     31    <technique>
     32        <require context="MODE_SILHOUETTEDISPLAY || MODE_WIREFRAME"/>
     33        <require shaders="glsl"/>
     34        <pass shader="glsl/model_solid_player"/>
     35    </technique>
     36
     37    <technique>
     38        <require context="MODE_SILHOUETTEDISPLAY || MODE_WIREFRAME"/>
     39        <require shaders="fixed"/>
     40        <define name="USE_PLAYERCOLOR" value="1"/>
     41        <define name="USE_OBJECTCOLOR" value="0"/>
     42        <pass shader="fixed:model_solid"/>
     43    </technique>
     44
     45
     46    <technique>
     47        <require shaders="arb"/>
     48        <pass shader="arb/model_common"/>
     49    </technique>
     50
     51    <technique>
     52        <require shaders="glsl"/>
     53        <pass shader="glsl/model_common_norm"/>
     54    </technique>
     55
     56    <technique>
     57        <require context="USE_PLAYERCOLOR || USE_OBJECTCOLOR"/>
     58        <require shaders="fixed"/>
     59        <pass shader="fixed:model_color"/>
     60    </technique>
     61
     62    <technique>
     63        <require shaders="fixed"/>
     64        <pass shader="fixed:model"/>
     65    </technique>
     66
     67</effect>
  • binaries/data/mods/public/shaders/effects/los.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<effect>
     3
     4    <technique>
     5        <require shaders="glsl"/>
     6        <pass shader="glsl/los"/>
     7    </technique>
     8
     9</effect>
  • binaries/data/mods/public/shaders/effects/ssao.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<effect>
     3
     4    <technique>
     5        <require shaders="glsl"/>
     6        <pass shader="glsl/ssao"/>
     7    </technique>
     8
     9</effect>
  • binaries/data/mods/public/shaders/effects/bloom.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<effect>
     3
     4    <technique>
     5        <require shaders="glsl"/>
     6        <pass shader="glsl/bloom"/>
     7    </technique>
     8
     9</effect>
  • binaries/data/mods/public/shaders/effects/fog.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<effect>
     3
     4    <technique>
     5        <require shaders="glsl"/>
     6        <pass shader="glsl/fog"/>
     7    </technique>
     8
     9</effect>
  • binaries/data/mods/public/shaders/effects/hdr.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<effect>
     3
     4    <technique>
     5        <require shaders="glsl"/>
     6        <pass shader="glsl/hdr"/>
     7    </technique>
     8
     9</effect>
  • binaries/data/mods/public/shaders/effects/los_interp.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<effect>
     3
     4    <technique>
     5        <require shaders="glsl"/>
     6        <pass shader="glsl/los_interp"/>
     7    </technique>
     8
     9</effect>
  • binaries/data/mods/public/shaders/glsl/terrain_common.fs

     
    11#version 120
    22
    33uniform sampler2D baseTex;
     4uniform sampler2D normTex;
     5uniform sampler2D specTex;
    46uniform sampler2D blendTex;
    57uniform sampler2D losTex;
    68
     
    1719
    1820uniform vec3 shadingColor;
    1921uniform vec3 ambient;
     22uniform vec3 sunDir;
    2023
     24uniform vec3 sunColor;
     25
     26uniform vec3 hasNormalMap;
     27uniform vec3 hasSpecularMap;
     28
    2129varying vec3 v_lighting;
    2230varying vec2 v_tex;
    2331varying vec4 v_shadow;
    2432varying vec2 v_los;
    2533varying vec2 v_blend;
     34varying vec3 v_normal;
    2635
     36//varying float depth;
     37
     38varying vec3 v_half;
     39
    2740#if USE_SPECULAR
    2841  uniform float specularPower;
    2942  uniform vec3 specularColor;
     
    4053        vec4 size = vec4(offset + 1.0, 2.0 - offset);
    4154        vec4 weight = (vec4(2.0 - 1.0 / size.xy, 1.0 / size.zw - 1.0) + (v_shadow.xy - offset).xyxy) * shadowScale.zwzw;
    4255        return (1.0/9.0)*dot(size.zxzx*size.wwyy,
    43           vec4(shadow2D(shadowTex, vec3(weight.zw, v_shadow.z)).a,
    44                shadow2D(shadowTex, vec3(weight.xw, v_shadow.z)).a,
    45                shadow2D(shadowTex, vec3(weight.zy, v_shadow.z)).a,
    46                shadow2D(shadowTex, vec3(weight.xy, v_shadow.z)).a));
     56          vec4(shadow2D(shadowTex, vec3(weight.zw, v_shadow.z)).r,
     57               shadow2D(shadowTex, vec3(weight.xw, v_shadow.z)).r,
     58               shadow2D(shadowTex, vec3(weight.zy, v_shadow.z)).r,
     59               shadow2D(shadowTex, vec3(weight.xy, v_shadow.z)).r));
    4760      #else
    48         return shadow2D(shadowTex, v_shadow.xyz).a;
     61        return shadow2D(shadowTex, v_shadow.xyz).r;
    4962      #endif
    5063    #else
    5164      if (v_shadow.z >= 1.0)
     
    5770  #endif
    5871}
    5972
     73vec3 apply_fog(vec3 colour)
     74{
     75    vec3 fogColour = vec3(0.6, 0.6, 0.65);
     76    float fogDistance = 300;
     77    float fogMax = 0.7;
     78
     79    float depth = (gl_FragCoord.z / gl_FragCoord.w) / 2 + 0.5;
     80
     81    float rec = 1.0 / (1.0 - fogDistance);
     82
     83    float factor = 1.0 - (depth - fogDistance) * rec;
     84
     85    factor = min(factor, fogMax);
     86   
     87    return mix(colour, fogColour, factor);
     88}
     89
    6090void main()
    6191{
    6292  #if BLEND
    6393    // Use alpha from blend texture
    64     gl_FragColor.a = 1.0 - texture2D(blendTex, v_blend).a;
     94    gl_FragData[0].a = 1.0 - texture2D(blendTex, v_blend).a;
    6595  #endif
    6696
    6797  vec4 tex = texture2D(baseTex, v_tex);
    6898
    6999  #if DECAL
    70100    // Use alpha from main texture
    71     gl_FragColor.a = tex.a;
     101    gl_FragData[0].a = tex.a;
    72102  #endif
    73103
    74104  vec3 texdiffuse = tex.rgb;
     
    83113    vec3 specular = vec3(0.0);
    84114  #endif
    85115
    86   vec3 color = (texdiffuse * sundiffuse + specular) * get_shadow() + texdiffuse * ambient;
     116    vec3 bump = sundiffuse;
     117    if (hasNormalMap.x > 0.5)
     118    {
     119        vec3 t = vec3(1, 0, 0);
     120        t = normalize(t - v_normal * dot(v_normal, t));
     121        vec3 b = cross(v_normal, t);
     122        //vec3 b = vec3(0, 0, 1);
     123        //b = normalize(b - v_normal * dot(v_normal, b));
    87124
     125
     126        mat3 tbn = transpose(mat3(t, b, v_normal));
     127        vec3 ntex = texture2D(normTex, v_tex).rgb * 2.0 - 1.0;
     128        vec3 vNout = normalize(ntex * tbn);
     129
     130
     131        bump = vec3(max (dot (-sunDir, vNout), 0.0)) * sunColor;
     132
     133        vec4 specColour = vec4(1.0);
     134
     135        if (hasSpecularMap.x > 0.5)
     136        {
     137            specColour = texture2D(specTex, v_tex);
     138            specular = specColour.xyz * sunColor * pow(max(0.0, dot(normalize(vNout), v_half)), 12);
     139        }
     140    }
     141
     142
     143    //vec3 specular;
     144
     145   
     146
     147
     148  vec3 color = (texdiffuse + specular) * bump * get_shadow() + texdiffuse * ambient;
     149
     150 
     151  //color = apply_fog(color);
     152
     153
    88154  float los = texture2D(losTex, v_los).a;
    89   color *= los;
     155  ///color *= los;
     156  gl_FragData[1].rgb = los;
     157 
    90158
    91159  #if DECAL
    92160    color *= shadingColor;
    93161  #endif
    94162
    95   gl_FragColor.rgb = color;
     163  gl_FragData[0].rgb = color;
    96164}
  • binaries/data/mods/public/shaders/glsl/hdr.fs

     
     1#version 110
     2
     3varying vec2 v_tex;
     4
     5uniform sampler2D bgl_RenderedTexture;
     6uniform sampler2D bgl_DepthTexture;
     7uniform sampler2D bgl_LuminanceTexture;
     8uniform float bgl_RenderedTextureWidth;
     9uniform float bgl_RenderedTextureHeight;
     10
     11#define PI    3.14159265
     12
     13float width = bgl_RenderedTextureWidth; //texture width
     14float height = bgl_RenderedTextureHeight; //texture height
     15
     16vec2 texCoord = v_tex;
     17vec2 texcoord = v_tex;
     18
     19
     20float avgL = 0.7;
     21float HDRamount = 0.1;
     22
     23void main(void)
     24{
     25    //gl_FragColor = texture2D(bgl_RenderedTexture, texcoord);
     26    //return;
     27
     28    float contrast = avgL;
     29    float brightness = avgL * HDRamount;
     30   
     31    vec4 value =  texture2D(bgl_RenderedTexture, texcoord);
     32
     33    //value *= 0.5;
     34   
     35    gl_FragColor = (value/contrast)-brightness;
     36}
     37
     38
  • binaries/data/mods/public/shaders/glsl/los.vs

     
     1#version 110
     2
     3uniform mat4 transform;
     4uniform vec2 losTransform;
     5
     6varying vec2 v_tex;
     7
     8attribute vec3 a_vertex;
     9attribute vec2 a_uv0;
     10
     11
     12varying vec2 v_los;
     13
     14void main()
     15
     16  gl_Position = gl_Vertex;
     17
     18  v_los = position.xz * losTransform.x + losTransform.y;
     19
     20  v_tex = vec2(gl_MultiTexCoord0);
     21}
  • binaries/data/mods/public/shaders/glsl/model_common_norm.vs

     
     1#if USE_GPU_SKINNING
     2// Skinning requires GLSL 1.30 for ivec4 vertex attributes
     3#version 130
     4#else
     5#version 120
     6#endif
     7
     8uniform mat4 transform;
     9uniform vec3 cameraPos;
     10uniform vec3 sunDir;
     11uniform vec3 sunColor;
     12uniform vec2 losTransform;
     13uniform mat4 shadowTransform;
     14uniform mat4 instancingTransform;
     15
     16//varying vec3 v_lighting;
     17varying vec2 v_tex;
     18varying vec4 v_shadow;
     19varying vec2 v_los;
     20
     21//#if USE_SPECULAR
     22  varying vec3 v_half;
     23//#endif
     24
     25attribute vec3 a_vertex;
     26attribute vec3 a_normal;
     27attribute vec2 a_uv0;
     28
     29attribute 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
     41varying vec4 debugx;
     42
     43
     44
     45
     46//varying vec3 lightVec;
     47varying vec3 eyeVec;
     48
     49varying vec3 v_normal;
     50varying vec4 v_tangent;
     51varying vec3 v_bitangent;
     52
     53
     54
     55//varying float sign;
     56
     57
     58void main()
     59{
     60  #if USE_GPU_SKINNING
     61    vec3 p = vec3(0.0);
     62    vec3 n = vec3(0.0);
     63    for (int i = 0; i < MAX_INFLUENCES; ++i) {
     64      int joint = a_skinJoints[i];
     65      if (joint != 0xff) {
     66        mat4 m = skinBlendMatrices[joint];
     67        p += vec3(m * vec4(a_vertex, 1.0)) * a_skinWeights[i];
     68        n += vec3(m * vec4(a_normal, 0.0)) * a_skinWeights[i];
     69      }
     70    }
     71    vec4 position = instancingTransform * vec4(p, 1.0);
     72    vec3 normal = mat3(instancingTransform) * normalize(n);
     73  #else
     74  #if USE_INSTANCING
     75    vec4 position = instancingTransform * vec4(a_vertex, 1.0);
     76    vec3 normal = mat3(instancingTransform) * a_normal;
     77    vec4 tangent = vec4(mat3(instancingTransform) * a_tangent.xyz, a_tangent.w);
     78  #else
     79    vec4 position = vec4(a_vertex, 1.0);
     80    vec3 normal = a_normal;
     81    vec4 tangent = a_tangent;   
     82  #endif
     83  #endif
     84
     85  gl_Position = transform * position;
     86 
     87   
     88
     89    eyeVec = cameraPos.xyz - position.xyz;
     90    //lightVec = -sunDir;
     91
     92
     93   
     94 
     95    vec3 sunVec = -sunDir;
     96   
     97    v_half = normalize(sunVec + eyeVec);
     98
     99   
     100    v_normal = normal;
     101    v_tangent = tangent;//.xyz;
     102    //sign = tangent.w;
     103    v_bitangent = cross(v_normal, v_tangent);
     104   
     105
     106  //v_lighting = max(0.0, dot(normal, -sunDir)) * sunColor;
     107  v_tex = a_uv0;
     108  v_shadow = shadowTransform * position;
     109  v_los = position.xz * losTransform.x + losTransform.y;
     110}
  • binaries/data/mods/public/shaders/glsl/ssao.vs

     
     1#version 110
     2
     3uniform mat4 transform;
     4
     5varying vec2 v_tex;
     6
     7attribute vec3 a_vertex;
     8attribute vec2 a_uv0;
     9
     10void main()
     11
     12  gl_Position = gl_Vertex; 
     13
     14  v_tex = vec2(gl_MultiTexCoord0);
     15}
  • binaries/data/mods/public/shaders/glsl/los.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<program type="glsl">
     3
     4    <vertex file="glsl/bloom.vs">
     5        <stream name="pos"/>
     6        <stream name="uv0"/>
     7        <attrib name="a_vertex" semantics="gl_Vertex"/>
     8        <attrib name="a_uv0" semantics="gl_MultiTexCoord0"/>
     9    </vertex>
     10
     11    <fragment file="glsl/los.fs"/>
     12
     13</program>
  • binaries/data/mods/public/shaders/glsl/terrain_base.xml

     
    66        <stream name="color"/>
    77        <stream name="uv0"/>
    88        <attrib name="a_vertex" semantics="gl_Vertex"/>
     9    <attrib name="a_normal" semantics="gl_Normal"/>
    910        <attrib name="a_color" semantics="gl_Color"/>
    1011        <attrib name="a_uv0" semantics="gl_MultiTexCoord0"/>
    1112    </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

     
    1717varying vec4 v_shadow;
    1818varying vec2 v_los;
    1919varying vec2 v_blend;
     20varying vec3 v_normal;
     21//varying float depth;
    2022
     23varying vec3 v_half;
     24
    2125#if USE_SPECULAR
    2226  varying vec3 v_normal;
    2327  varying vec3 v_half;
    2428#endif
    2529
    2630attribute vec3 a_vertex;
     31attribute vec3 a_normal;
    2732attribute vec3 a_color;
    2833attribute vec2 a_uv0;
    2934attribute vec2 a_uv1;
     
    3439
    3540  gl_Position = transform * position;
    3641
     42  //depth = gl_Position.z / gl_Position.w;
     43
    3744  v_lighting = a_color * sunColor;
     45
     46  //v_lighting = dot(-sunDir, a_normal) * sunColor;
     47
     48  //v_lighting = sunColor;
    3849 
    3950  #if DECAL
    4051    v_tex = a_uv0;
     
    7283    v_normal = normal;
    7384  #endif
    7485
     86    vec3 eyeVec = cameraPos.xyz - position.xyz;
     87   
     88 
     89    vec3 sunVec = -sunDir;
     90   
     91    v_half = normalize(sunVec + eyeVec);
     92
     93  v_normal = a_normal;
     94
    7595  v_los = a_vertex.xz * losTransform.x + losTransform.yy;
    7696}
  • binaries/data/mods/public/shaders/glsl/ssao.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<program type="glsl">
     3
     4    <vertex file="glsl/ssao.vs">
     5        <stream name="pos"/>
     6        <stream name="uv0"/>
     7        <attrib name="a_vertex" semantics="gl_Vertex"/>
     8        <attrib name="a_uv0" semantics="gl_MultiTexCoord0"/>
     9    </vertex>
     10
     11    <fragment file="glsl/ssao.fs"/>
     12
     13</program>
  • binaries/data/mods/public/shaders/glsl/hdr.vs

     
     1#version 110
     2
     3uniform mat4 transform;
     4
     5varying vec2 v_tex;
     6
     7attribute vec3 a_vertex;
     8attribute vec2 a_uv0;
     9
     10void main()
     11
     12  gl_Position = gl_Vertex; 
     13
     14  v_tex = vec2(gl_MultiTexCoord0);
     15}
  • binaries/data/mods/public/shaders/glsl/bloom.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<program type="glsl">
     3
     4    <vertex file="glsl/bloom.vs">
     5        <stream name="pos"/>
     6        <stream name="uv0"/>
     7        <attrib name="a_vertex" semantics="gl_Vertex"/>
     8        <attrib name="a_uv0" semantics="gl_MultiTexCoord0"/>
     9    </vertex>
     10
     11    <fragment file="glsl/bloom.fs"/>
     12
     13</program>
  • binaries/data/mods/public/shaders/glsl/terrain_blend.xml

     
    1010        <stream name="uv1"/>
    1111        <attrib name="a_vertex" semantics="gl_Vertex"/>
    1212        <attrib name="a_color" semantics="gl_Color"/>
     13    <attrib name="a_normal" semantics="gl_Normal"/>
    1314        <attrib name="a_uv0" semantics="gl_MultiTexCoord0"/>
    1415        <attrib name="a_uv1" semantics="gl_MultiTexCoord1"/>
    1516    </vertex>
  • binaries/data/mods/public/shaders/glsl/hdr.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<program type="glsl">
     3
     4    <vertex file="glsl/hdr.vs">
     5        <stream name="pos"/>
     6        <stream name="uv0"/>
     7        <attrib name="a_vertex" semantics="gl_Vertex"/>
     8        <attrib name="a_uv0" semantics="gl_MultiTexCoord0"/>
     9    </vertex>
     10
     11    <fragment file="glsl/hdr.fs"/>
     12
     13</program>
  • binaries/data/mods/public/shaders/glsl/los_interp.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<program type="glsl">
     3
     4    <vertex file="glsl/los_interp.vs">
     5        <stream name="pos"/>
     6        <stream name="uv0"/>
     7        <attrib name="a_vertex" semantics="gl_Vertex"/>
     8        <attrib name="a_uv0" semantics="gl_MultiTexCoord0"/>
     9    </vertex>
     10
     11    <fragment file="glsl/los_interp.fs"/>
     12
     13</program>
  • binaries/data/mods/public/shaders/glsl/bloom.fs

     
     1#version 110
     2
     3varying vec2 v_tex;
     4
     5uniform sampler2D bgl_RenderedTexture;
     6uniform sampler2D bgl_DepthTexture;
     7uniform sampler2D bgl_LuminanceTexture;
     8uniform float bgl_RenderedTextureWidth;
     9uniform float bgl_RenderedTextureHeight;
     10
     11#define PI    3.14159265
     12
     13float width = bgl_RenderedTextureWidth; //texture width
     14float height = bgl_RenderedTextureHeight; //texture height
     15
     16vec2 texCoord = v_tex;
     17vec2 texcoord = v_tex;
     18
     19
     20float BRIGHT_PASS_THRESHOLD = 0.6;
     21float BRIGHT_PASS_OFFSET = 0.6;
     22
     23#define blurclamp 0.0015
     24#define bias 0.01
     25
     26#define KERNEL_SIZE  3.0
     27
     28
     29
     30vec4 bright(vec2 coo)
     31{   
     32    vec4 color = texture2D(bgl_RenderedTexture, coo);
     33   
     34    color = max(color - BRIGHT_PASS_THRESHOLD, 0.0);
     35   
     36    return color / (color + BRIGHT_PASS_OFFSET);   
     37}
     38
     39
     40void main(void)
     41{   
     42    vec2 blur = vec2(clamp( bias, -blurclamp, blurclamp ));
     43   
     44    vec4 col = vec4( 0, 0, 0, 0 );
     45    for ( float x = -KERNEL_SIZE + 1.0; x < KERNEL_SIZE; x += 1.0 )
     46    {
     47    for ( float y = -KERNEL_SIZE + 1.0; y < KERNEL_SIZE; y += 1.0 )
     48    {
     49         col += bright( texcoord + vec2( blur.x * x, blur.y * y ) );
     50    }
     51    }
     52    col /= ((KERNEL_SIZE+KERNEL_SIZE)-1.0)*((KERNEL_SIZE+KERNEL_SIZE)-1.0);
     53
     54    //gl_FragColor = col + texture2D(bgl_RenderedTexture, texcoord);
     55
     56    //col *= 0.9;
     57    gl_FragColor = 1.0 - (1.0 - col) * (1.0 - texture2D(bgl_RenderedTexture, texcoord));
     58
     59}
     60
  • binaries/data/mods/public/shaders/glsl/model_common.fs

     
    4747        vec4 size = vec4(offset + 1.0, 2.0 - offset);
    4848        vec4 weight = (vec4(2.0 - 1.0 / size.xy, 1.0 / size.zw - 1.0) + (v_shadow.xy - offset).xyxy) * shadowScale.zwzw;
    4949        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));
    5454      #else
    55         return shadow2D(shadowTex, v_shadow.xyz).a;
     55        return shadow2D(shadowTex, v_shadow.xyz).r;
    5656      #endif
    5757    #else
    5858      if (v_shadow.z >= 1.0)
     
    6464  #endif
    6565}
    6666
     67
     68vec3 apply_fog(vec3 colour)
     69{
     70    vec3 fogColour = vec3(0.6, 0.6, 0.65);
     71    float fogDistance = 300;
     72    float fogMax = 0.7;
     73
     74    float depth = (gl_FragCoord.z / gl_FragCoord.w) / 2 + 0.5;
     75
     76    float rec = 1.0 / (1.0 - fogDistance);
     77
     78    float factor = 1.0 - (depth - fogDistance) * rec;
     79
     80    factor = min(factor, fogMax);
     81   
     82    return mix(colour, fogColour, factor);
     83}
     84
     85
    6786void main()
    6887{
    6988  vec4 tex = texture2D(baseTex, v_tex);
     
    7594  #endif
    7695
    7796  #if USE_TRANSPARENT
    78     gl_FragColor.a = tex.a;
     97    gl_FragData[0].a = tex.a;
     98    gl_FragData[1].a = tex.a;
    7999  #else
    80     gl_FragColor.a = 1.0;
     100    gl_FragData[0].a = 1.0;
    81101  #endif
    82102 
    83103  vec3 texdiffuse = tex.rgb;
     
    104124
    105125  vec3 color = (texdiffuse * sundiffuse + specular) * get_shadow() + texdiffuse * ambient;
    106126
     127  //color = apply_fog(color);
     128
    107129  #if !IGNORE_LOS
    108130    float los = texture2D(losTex, v_los).a;
    109     color *= los;
     131    ///color *= los;
     132    gl_FragData[1].rgb = los;
    110133  #endif
    111134
    112135  color *= shadingColor;
    113136
    114   gl_FragColor.rgb = color;
     137  gl_FragData[0].rgb = color;
    115138}
  • binaries/data/mods/public/shaders/glsl/fog.fs

     
     1#version 110
     2
     3varying vec2 v_tex;
     4
     5uniform sampler2D bgl_RenderedTexture;
     6uniform sampler2D bgl_DepthTexture;
     7uniform sampler2D bgl_LuminanceTexture;
     8uniform float bgl_RenderedTextureWidth;
     9uniform float bgl_RenderedTextureHeight;
     10
     11#define PI    3.14159265
     12
     13float width = bgl_RenderedTextureWidth; //texture width
     14float height = bgl_RenderedTextureHeight; //texture height
     15
     16vec2 texcoord = v_tex;
     17
     18
     19
     20
     21void main(void)
     22{   
     23    vec3 colour = texture2D(bgl_RenderedTexture, texcoord);
     24
     25    //gl_FragColor.rgb = colour;
     26    //return;
     27
     28    vec3 depth = texture2D(bgl_DepthTexture, texcoord);
     29
     30    vec3 fogColour = vec3(0.6, 0.6, 0.65);
     31    float dist = 0.991;
     32    float maxFog = 0.6;
     33
     34    float rec = 1 / (1 - dist);
     35
     36    float factor = (depth.r - dist) * rec;
     37
     38    factor = min(factor, maxFog);
     39   
     40    if (depth.r >= dist && depth.r < 1.0)
     41        gl_FragColor.rgb = mix(colour, fogColour, factor);
     42    else
     43        gl_FragColor.rgb = colour;
     44   
     45    //gl_FragColor.rgb = (depth - 0.99) * 100;
     46
     47}
     48
  • binaries/data/mods/public/shaders/glsl/los_interp.fs

     
     1#version 110
     2
     3varying vec2 v_tex;
     4
     5uniform sampler2D bgl_RenderedTexture;
     6uniform sampler2D bgl_DepthTexture;
     7uniform sampler2D losTex1, losTex2;
     8uniform float bgl_RenderedTextureWidth;
     9uniform float bgl_RenderedTextureHeight;
     10
     11#define PI    3.14159265
     12
     13float width = bgl_RenderedTextureWidth; //texture width
     14float height = bgl_RenderedTextureHeight; //texture height
     15
     16uniform vec3 delta;
     17
     18vec2 texcoord = v_tex;
     19
     20
     21
     22
     23void main(void)
     24{   
     25    //vec3 colour = texture2D(bgl_RenderedTexture, texcoord);
     26
     27    vec4 los2 = texture2D(losTex1, texcoord);
     28    vec4 los1 = texture2D(losTex2, texcoord);
     29
     30    //colour *= los;
     31   
     32    //gl_FragColor.rgb = colour;
     33
     34    //gl_FragColor = vec4(0,0,0,los);
     35
     36    gl_FragColor = mix(los1, los2, clamp(delta.r, 0.0, 1.0));
     37
     38    //gl_FragColor.a = (1.0 - clamp(delta.r, 0.0, 1.0)) * los;//delta.r;
     39
     40    //gl_FragColor.rgb = (depth - 0.99) * 100;
     41
     42}
     43
  • binaries/data/mods/public/shaders/glsl/water_high.fs

     
    5353    specular = pow(max(0.0, ndoth), shininess) * sunColor * specularStrength;
    5454
    5555    losMod = texture2D(losMap, gl_TexCoord[3].st).a;
     56    gl_FragData[1] = losMod;
    5657
    57     gl_FragColor.rgb = mix(refrColor + 0.3*specular, reflColor + specular, fresnel) * losMod;
     58    gl_FragData[0].rgb = mix(refrColor + 0.3*specular, reflColor + specular, fresnel);// * losMod;
    5859   
    5960    // Make alpha vary based on both depth (so it blends with the shore) and view angle (make it
    6061    // become opaque faster at lower view angles so we can't look "underneath" the water plane)
    6162    t = 18.0 * max(0.0, 0.7 - v.y);
    62     gl_FragColor.a = 0.15 * waterDepth * (1.2 + t + fresnel);
     63    gl_FragData[0].a = 0.15 * waterDepth * (1.2 + t + fresnel);
    6364}
  • binaries/data/mods/public/shaders/glsl/bloom.vs

     
     1#version 110
     2
     3uniform mat4 transform;
     4
     5varying vec2 v_tex;
     6
     7attribute vec3 a_vertex;
     8attribute vec2 a_uv0;
     9
     10void main()
     11
     12  gl_Position = gl_Vertex; 
     13
     14  v_tex = vec2(gl_MultiTexCoord0);
     15}
  • binaries/data/mods/public/shaders/glsl/fog.vs

     
     1#version 110
     2
     3uniform mat4 transform;
     4
     5varying vec2 v_tex;
     6
     7attribute vec3 a_vertex;
     8attribute vec2 a_uv0;
     9
     10void main()
     11
     12  gl_Position = gl_Vertex; 
     13
     14  v_tex = vec2(gl_MultiTexCoord0);
     15}
  • binaries/data/mods/public/shaders/glsl/los.fs

     
     1#version 110
     2
     3varying vec2 v_tex;
     4
     5uniform sampler2D bgl_RenderedTexture;
     6uniform sampler2D bgl_DepthTexture;
     7uniform sampler2D losTexPersp;
     8uniform float bgl_RenderedTextureWidth;
     9uniform float bgl_RenderedTextureHeight;
     10
     11#define PI    3.14159265
     12
     13float width = bgl_RenderedTextureWidth; //texture width
     14float height = bgl_RenderedTextureHeight; //texture height
     15
     16vec2 texcoord = v_tex;
     17
     18
     19
     20
     21void main(void)
     22{   
     23    vec3 colour = texture2D(bgl_RenderedTexture, texcoord);
     24
     25    vec3 los = texture2D(losTexPersp, texcoord);
     26
     27    colour *= los;
     28   
     29    gl_FragColor.rgb = colour;
     30
     31    //gl_FragColor.rgb = (depth - 0.99) * 100;
     32
     33}
     34
  • binaries/data/mods/public/shaders/glsl/los_interp.vs

     
     1#version 110
     2
     3uniform mat4 transform;
     4uniform vec2 losTransform;
     5
     6varying vec2 v_tex;
     7
     8attribute vec3 a_vertex;
     9attribute vec2 a_uv0;
     10
     11
     12varying vec2 v_los;
     13
     14void main()
     15
     16  gl_Position = gl_Vertex; 
     17
     18  v_tex = vec2(gl_MultiTexCoord0);
     19}
  • binaries/data/mods/public/shaders/glsl/fog.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<program type="glsl">
     3
     4    <vertex file="glsl/bloom.vs">
     5        <stream name="pos"/>
     6        <stream name="uv0"/>
     7        <attrib name="a_vertex" semantics="gl_Vertex"/>
     8        <attrib name="a_uv0" semantics="gl_MultiTexCoord0"/>
     9    </vertex>
     10
     11    <fragment file="glsl/fog.fs"/>
     12
     13</program>
  • binaries/data/mods/public/shaders/glsl/model_common_norm.fs

     
     1#version 120
     2
     3uniform sampler2D baseTex;
     4uniform sampler2D normTex;
     5uniform sampler2D losTex;
     6uniform 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
     24uniform vec3 ambient;
     25uniform vec4 shadowOffsets1;
     26uniform vec4 shadowOffsets2;
     27
     28//uniform mat4 normalMatrix;
     29
     30//varying vec3 v_lighting;
     31varying vec2 v_tex;
     32varying vec4 v_shadow;
     33varying vec2 v_los;
     34
     35uniform vec3 sunDir;
     36uniform vec3 sunColor;
     37
     38/*#if USE_SPECULAR
     39  uniform float specularPower;
     40  uniform vec3 specularColor;
     41  varying vec3 v_normal;
     42#endif*/
     43
     44varying vec3 v_half;
     45
     46//varying vec3 lightVec;   
     47varying vec3 eyeVec;
     48varying vec3 v_normal;
     49varying vec4 v_tangent;
     50varying vec3 v_bitangent;
     51
     52
     53//varying float sign;
     54
     55
     56float 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
     91vec3 apply_fog(vec3 colour)
     92{
     93    vec3 fogColour = vec3(0.6, 0.6, 0.65);
     94    float fogDistance = 1000;
     95    float fogMax = 0.6;
     96
     97    float dep = (gl_FragCoord.z / gl_FragCoord.w) / fogDistance;
     98
     99    dep = clamp(dep, 0, fogMax);
     100       
     101    return mix(colour, fogColour, dep);
     102}
     103
     104
     105
     106#define USE_PARALLAX      1
     107#define USE_NORMAL_MAP    1
     108#define USE_SPECULAR_MAP  1
     109#define USE_SELF_LIGHT    1
     110#define USE_DISTANCE_FOG  1
     111
     112void main()
     113{
     114
     115
     116    vec3 color;
     117    mat3 tbn;
     118    vec2 coord = v_tex;
     119    float sign = v_tangent.w;
     120
     121
     122#if USE_PARALLAX
     123    float h = texture2D(normTex, coord).a;
     124
     125    tbn = transpose(mat3(v_tangent.xyz, v_bitangent * sign, v_normal));
     126
     127    vec3 eyeDir = normalize( tbn * eyeVec );
     128    float dist = length(eyeVec);
     129
     130    if (dist < 100 && h < 0.999)
     131    {
     132        float scale = 0.01;
     133
     134        if (dist > 65)
     135        {
     136            scale = 0.01 * (100 - dist) / 35.0;
     137        }
     138
     139        float height = 1.0;
     140        float iter;
     141
     142        float s;
     143        vec2 move;
     144        iter = (75 - (dist - 25)) / 3 + 5;
     145
     146        if (iter > 15) iter = 15;
     147
     148        vec3 tangEye = -eyeDir;
     149
     150        iter = mix(iter * 2, iter, tangEye.z);
     151       
     152        s = 1.0 / iter;
     153        move = vec2(-eyeDir.x, eyeDir.y) * scale / (eyeDir.z * iter);
     154
     155        while (h < height)
     156        {
     157            height -= s;
     158            coord += move;
     159            h = texture2D(normTex, coord).a;
     160        }
     161
     162    }
     163#endif
     164   
     165
     166
     167    tbn = transpose(mat3(v_tangent.xyz, v_bitangent * -sign, v_normal));
     168    vec3 ntex = texture2D(normTex, coord).rgb * 2.0 - 1.0;
     169    vec3 vNout = normalize(ntex * tbn);
     170
     171
     172
     173#if USE_NORMAL_MAP
     174    float bump = max (dot (-sunDir, vNout), 0.0) ;
     175#else
     176    float bump = 1.0;
     177#endif
     178
     179
     180    vec3 specular;
     181    vec4 specColour = vec4(1.0);
     182#if USE_SPECULAR_MAP
     183    specColour = texture2D(specTex, coord);
     184    specular = bump * specColour.xyz * sunColor * pow(max(0.0, dot(normalize(vNout), v_half)), 12);
     185#else
     186    // if enabled, do normal specular
     187    specular = vec3(0.0);
     188#endif
     189   
     190
     191    vec4 diffuse = texture2D(baseTex, coord);
     192
     193#if USE_TRANSPARENT
     194    gl_FragData[0].a = diffuse.a;
     195    gl_FragData[1].a = diffuse.a;
     196#else
     197    gl_FragData[0].a = 1.0;
     198#endif
     199
     200    vec3 texdiffuse = diffuse.rgb;
     201
     202    // Apply-coloring based on texture alpha
     203#if USE_OBJECTCOLOR
     204    texdiffuse *= mix(objectColor, vec3(1.0, 1.0, 1.0), diffuse.a);
     205#else
     206#if USE_PLAYERCOLOR
     207    texdiffuse *= mix(playerColor, vec3(1.0, 1.0, 1.0), diffuse.a);
     208#endif
     209#endif
     210
     211
     212
     213
     214    color = (texdiffuse + specular) * bump * sunColor * get_shadow() + texdiffuse * ambient;
     215
     216#if USE_SELF_LIGHT
     217    color = mix(texdiffuse, color, specColour.a);
     218#endif
     219
     220
     221
     222    //color = apply_fog(color);
     223   
     224
     225
     226#if !IGNORE_LOS
     227    float los = texture2D(losTex, v_los).a;
     228    //color *= los;
     229    gl_FragData[1].rgb = los;
     230#endif
     231
     232 
     233    //gl_FragColor.rgb = color;
     234    gl_FragData[0].rgb = color;
     235}
  • binaries/data/mods/public/shaders/glsl/ssao.fs

     
     1#version 110
     2
     3varying vec2 v_tex;
     4
     5uniform sampler2D bgl_RenderedTexture;
     6uniform sampler2D bgl_DepthTexture;
     7uniform sampler2D bgl_LuminanceTexture;
     8uniform float bgl_RenderedTextureWidth;
     9uniform float bgl_RenderedTextureHeight;
     10
     11#define PI    3.14159265
     12
     13float width = bgl_RenderedTextureWidth; //texture width
     14float 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
     22float near = 1.4; //Z-near
     23float far = 75.0; //Z-far
     24
     25int samples = 6; //samples on the first ring (5-10)
     26int rings = 3; //ring count (2-6)
     27
     28//vec2 texCoord = gl_TexCoord[0].st;
     29vec2 texCoord = v_tex;
     30vec2 texcoord = v_tex;
     31
     32
     33vec2 rand(in vec2 coord) //generating random noise
     34{
     35    float noiseX = (fract(sin(dot(coord ,vec2(12.9898,78.233))) * 43758.5453));
     36    float noiseY = (fract(sin(dot(coord ,vec2(12.9898,78.233)*2.0)) * 43758.5453));
     37    return vec2(noiseX,noiseY);
     38}
     39
     40float readDepth(in vec2 coord)
     41{
     42    return (2.0 * near) / (far + near - texture2D(bgl_DepthTexture, coord ).x * (far-near));   
     43}
     44
     45float compareDepths( in float depth1, in float depth2 )
     46{
     47    float aoCap = 1.2;
     48    //float aoMultiplier = 250.0;
     49    float aoMultiplier = 250.0;
     50    float depthTolerance = 0.0000;
     51    float aorange = 1.2;// units in space the AO effect extends to (this gets divided by the camera far range
     52    float diff = sqrt(clamp(1.0-(depth1-depth2) / (aorange/(far-near)),0.0,1.0));
     53    float ao = min(aoCap,max(0.0,depth1-depth2-depthTolerance) * aoMultiplier) * diff;
     54    return ao;
     55}
     56
     57void main(void)
     58{   
     59    /*if (texture2D(bgl_DepthTexture, texcoord).x <= 0.5)
     60    {   
     61        gl_FragColor = texture2D(bgl_RenderedTexture, texcoord);
     62        return;
     63    }*/
     64
     65    float depth = readDepth(texCoord);
     66    float d;
     67   
     68    float aspect = width/height;
     69    vec2 noise = rand(texCoord)*0.003;
     70   
     71    float w = (0.001/depth+noise.x);
     72    float h = (0.001/depth+noise.y);
     73   
     74    float pw;
     75    float ph;
     76
     77    float ao;   
     78    float s;
     79   
     80    for (int i = 0 ; i < rings; ++i)
     81    {
     82        for (int j = 0 ; j < samples; ++j)
     83        {
     84            float step = PI*2.0 / float(samples);
     85            pw = (cos(float(j)*step)*float(i));
     86            ph = (sin(float(j)*step)*float(i))*aspect;
     87            d = readDepth( vec2(texCoord.s+pw*w,texCoord.t+ph*h));
     88            ao += compareDepths(depth,d);   
     89            s += 1.0;
     90        }
     91    }
     92   
     93    ao /= s;
     94    ao = 1.0-ao;   
     95   
     96    vec3 color = texture2D(bgl_RenderedTexture,texCoord).rgb;
     97    //vec3 luminance = texture2D(bgl_LuminanceTexture,texCoord).rgb;
     98    vec3 luminance = vec3(dot(color, vec3(0.299, 0.587, 0.114)));
     99    vec3 white = vec3(1.0,1.0,1.0);
     100    vec3 black = vec3(0.0,0.0,0.0);
     101    //vec3 treshold = vec3(0.2,0.2,0.2);
     102
     103    vec3 treshold = vec3(0.8);
     104   
     105    luminance = clamp(max(black,luminance-treshold)+max(black,luminance-treshold)+max(black,luminance-treshold),0.0,1.0);
     106   
     107    gl_FragColor = vec4(color*mix(vec3(ao,ao,ao),white,luminance),1.0);
     108    //gl_FragColor = vec4(mix(vec3(ao,ao,ao),white,luminance),1.0);// vec4(color*vec3(ao,ao,ao),1.0);
     109    //gl_FragColor = vec4(mix(vec3(ao,ao,ao),white,luminance),1.0);
     110    //gl_FragColor = vec4(ao * color, 1.0);
     111
     112    //if (texcoord.x > 0.75) gl_FragColor = texture2D(bgl_RenderedTexture, texcoord);
     113}
     114
  • binaries/data/config/default.cfg

     
    5858renderpath = default
    5959
    6060; Prefer GLSL shaders over ARB shaders (not recommended)
    61 preferglsl = false
     61preferglsl = true
    6262
    6363; Replace alpha-blending with alpha-testing, for performance experiments
    6464forcealphatest = false