/* Copyright (C) 2012 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#include "precompiled.h"
#include
#include "graphics/Color.h"
#include "graphics/LightEnv.h"
#include "graphics/Model.h"
#include "graphics/ModelDef.h"
#include "graphics/ShaderManager.h"
#include "graphics/TextureManager.h"
#include "renderer/MikktspaceWrap.h"
#include "third_party/mikktspace/mikktspace.h"
MikkTSpace::MikkTSpace(const CModelDefPtr& m, std::vector& v, bool gpuSkinning) : m_Model(m),
m_NewVertices(v), m_GpuSkinning(gpuSkinning)
{
// ensure that m_NewVertices is empty
m_NewVertices.clear();
// set up SMikkTSpaceInterface struct
m_Interface.m_getNumFaces = getNumFaces;
m_Interface.m_getNumVerticesOfFace = getNumVerticesOfFace;
m_Interface.m_getPosition = getPosition;
m_Interface.m_getNormal = getNormal;
m_Interface.m_getTexCoord = getTexCoord;
m_Interface.m_setTSpaceBasic = NULL;
m_Interface.m_setTSpace = setTSpace;
// set up SMikkTSpaceContext struct
m_Context.m_pInterface = &m_Interface;
m_Context.m_pUserData = (void*)this;
}
void MikkTSpace::generate()
{
genTangSpaceDefault(&m_Context);
}
int MikkTSpace::getNumFaces(const SMikkTSpaceContext *pContext)
{
return ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetNumFaces();
}
int MikkTSpace::getNumVerticesOfFace(const SMikkTSpaceContext* UNUSED(pContext), const int UNUSED(iFace))
{
return 3;
}
void MikkTSpace::getPosition(const SMikkTSpaceContext *pContext,
float fvPosOut[], const int iFace, const int iVert)
{
SModelFace &face = ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetFaces()[iFace];
long i = face.m_Verts[iVert];
const CVector3D &p = ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetVertices()[i].m_Coords;
fvPosOut[0] = p.X;
fvPosOut[1] = p.Y;
fvPosOut[2] = p.Z;
}
void MikkTSpace::getNormal(const SMikkTSpaceContext *pContext,
float fvNormOut[], const int iFace, const int iVert)
{
SModelFace &face = ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetFaces()[iFace];
long i = face.m_Verts[iVert];
const CVector3D &n = ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetVertices()[i].m_Norm;
fvNormOut[0] = n.X;
fvNormOut[1] = n.Y;
fvNormOut[2] = n.Z;
}
void MikkTSpace::getTexCoord(const SMikkTSpaceContext *pContext,
float fvTexcOut[], const int iFace, const int iVert)
{
SModelFace &face = ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetFaces()[iFace];
long i = face.m_Verts[iVert];
SModelVertex &v = ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetVertices()[i];
// the tangents are calculated according to the 'default' UV set
fvTexcOut[0] = v.m_UVs[0];
fvTexcOut[1] = 1.0-v.m_UVs[1];
}
void MikkTSpace::setTSpace(const SMikkTSpaceContext * pContext, const float fvTangent[],
const float UNUSED(fvBiTangent)[], const float UNUSED(fMagS), const float UNUSED(fMagT),
const tbool bIsOrientationPreserving, const int iFace, const int iVert)
{
SModelFace &face = ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetFaces()[iFace];
long i = face.m_Verts[iVert];
SModelVertex* vertices = ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetVertices();
size_t numUVsPerVertex = ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetNumUVsPerVertex();
std::vector& m_NewVertices = ((MikkTSpace*)pContext->m_pUserData)->m_NewVertices;
const CVector3D &p = vertices[i].m_Coords;
const CVector3D &n = vertices[i].m_Norm;
m_NewVertices.push_back(p.X);
m_NewVertices.push_back(p.Y);
m_NewVertices.push_back(p.Z);
m_NewVertices.push_back(n.X);
m_NewVertices.push_back(n.Y);
m_NewVertices.push_back(n.Z);
m_NewVertices.push_back(fvTangent[0]);
m_NewVertices.push_back(fvTangent[1]);
m_NewVertices.push_back(fvTangent[2]);
m_NewVertices.push_back(bIsOrientationPreserving > 0.5 ? 1.0f : (-1.0f));
if (((MikkTSpace*)pContext->m_pUserData)->m_GpuSkinning)
{
for (size_t j = 0; j < 4; ++j)
{
m_NewVertices.push_back(vertices[i].m_Blend.m_Bone[j]);
m_NewVertices.push_back(255.f * vertices[i].m_Blend.m_Weight[j]);
}
}
for (size_t UVset = 0; UVset < numUVsPerVertex; ++UVset)
{
m_NewVertices.push_back(vertices[i].m_UVs[UVset * 2]);
m_NewVertices.push_back(1.0 - vertices[i].m_UVs[UVset * 2 + 1]);
}
}