/* Copyright (C) 2021 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 "renderer/MikktspaceWrap.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 = nullptr;
m_Interface.m_setTSpace = SetTSpace;
// set up SMikkTSpaceContext struct
m_Context.m_pInterface = &m_Interface;
m_Context.m_pUserData = static_cast(this);
}
void MikkTSpace::Generate()
{
genTangSpaceDefault(&m_Context);
}
int MikkTSpace::GetNumFaces(const SMikkTSpaceContext* pContext)
{
return GetUserDataFromContext(pContext)->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)
{
const CVector3D& position = GetVertex(pContext, iFace, iVert).m_Coords;
fvPosOut[0] = position.X;
fvPosOut[1] = position.Y;
fvPosOut[2] = position.Z;
}
void MikkTSpace::GetNormal(const SMikkTSpaceContext* pContext,
float* fvNormOut, const int iFace, const int iVert)
{
const CVector3D& normal = GetVertex(pContext, iFace, iVert).m_Norm;
fvNormOut[0] = normal.X;
fvNormOut[1] = normal.Y;
fvNormOut[2] = normal.Z;
}
void MikkTSpace::GetTexCoord(const SMikkTSpaceContext* pContext,
float* fvTexcOut, const int iFace, const int iVert)
{
const MikkTSpace* userData = GetUserDataFromContext(pContext);
const SModelFace& face = userData->m_Model->GetFaces()[iFace];
const size_t numberOfUVPerVertex = userData->m_Model->GetNumUVsPerVertex();
// The tangents are calculated according to the 'default' UV set
const CVector2D& uv = userData->m_Model->GetUVCoordinates()[face.m_Verts[iVert] * numberOfUVPerVertex];
fvTexcOut[0] = uv.X;
fvTexcOut[1] = 1.0 - uv.Y;
}
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)
{
const MikkTSpace* userData = GetUserDataFromContext(pContext);
const SModelFace& face = userData->m_Model->GetFaces()[iFace];
const SModelVertex& vertex = userData->m_Model->GetVertices()[face.m_Verts[iVert]];
const CVector3D& p = vertex.m_Coords;
userData->m_NewVertices.push_back(p.X);
userData->m_NewVertices.push_back(p.Y);
userData->m_NewVertices.push_back(p.Z);
const CVector3D& n = vertex.m_Norm;
userData->m_NewVertices.push_back(n.X);
userData->m_NewVertices.push_back(n.Y);
userData->m_NewVertices.push_back(n.Z);
userData->m_NewVertices.push_back(fvTangent[0]);
userData->m_NewVertices.push_back(fvTangent[1]);
userData->m_NewVertices.push_back(fvTangent[2]);
userData->m_NewVertices.push_back(bIsOrientationPreserving != 0 ? 1.f : -1.f);
if (userData->m_GpuSkinning)
{
for (u8 j = 0; j < 4; ++j)
{
userData->m_NewVertices.push_back(vertex.m_Blend.m_Bone[j]);
userData->m_NewVertices.push_back(255.f * vertex.m_Blend.m_Weight[j]);
}
}
const size_t numberOfUVPerVertex = userData->m_Model->GetNumUVsPerVertex();
for (size_t UVset = 0; UVset < numberOfUVPerVertex; ++UVset)
{
const CVector2D& uv = userData->m_Model->GetUVCoordinates()[face.m_Verts[iVert] * numberOfUVPerVertex + UVset];
userData->m_NewVertices.push_back(uv.X);
userData->m_NewVertices.push_back(1.f - uv.Y);
}
}
MikkTSpace* MikkTSpace::GetUserDataFromContext(const SMikkTSpaceContext* pContext)
{
return static_cast(pContext->m_pUserData);
}
SModelVertex MikkTSpace::GetVertex(const SMikkTSpaceContext* pContext, const int iFace, const int iVert)
{
const MikkTSpace* userData = GetUserDataFromContext(pContext);
const SModelFace& f = userData->m_Model->GetFaces()[iFace];
return userData->m_Model->GetVertices()[f.m_Verts[iVert]];
}