Files
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

718 lines
19 KiB
C++

//
// rageShaderMaya65/rageShaderUpdate.cpp
//
// Copyright (C) 1999-2006 Rockstar Games. All Rights Reserved.
//
#include <process.h>
#define REQUIRE_IOSTREAM
#pragma warning(push)
#pragma warning(disable : 4668)
#include <maya/MDagPath.h>
#include <maya/MFnMesh.h>
#include <maya/MFnSet.h>
#include <maya/M3dView.h>
#include <maya/MItDag.h>
#include <maya/MPlug.h>
#include <maya/MPlugArray.h>
#include <maya/MMatrix.h>
#include <maya/MFloatPointArray.h>
#include <maya/MFloatVectorArray.h>
#include <maya/MGlobal.h>
#include <maya/MFnCamera.h>
#pragma warning(error: 4668)
//#pragma comment(lib, "../devil/libtiff.lib")
#pragma comment(lib, "../3rdParty/Devil/lib/DevIL.lib")
#pragma comment(lib, "../3rdParty/Devil/lib/ILUT.lib")
#pragma comment(lib, "../3rdParty/Devil/lib/ILU.lib")
#include <IL/il.h>
#include <IL/ilu.h>
#pragma comment(lib, "opengl32.lib")
// #pragma comment(lib, "cg.lib")
// #pragma comment(lib, "cgGL.lib")
// #pragma comment(lib, "Cloth.lib")
#pragma comment(lib, "Foundation.lib")
// #pragma comment(lib, "Image.lib")
// #pragma comment(lib, "IMF.lib")
// #pragma comment(lib, "libfbxfilesdk.lib")
// #pragma comment(lib, "libmocap.lib")
#pragma comment(lib, "OpenMaya.lib")
// #pragma comment(lib, "OpenMayaAnim.lib")
// #pragma comment(lib, "OpenMayaFX.lib")
#pragma comment(lib, "OpenMayaRender.lib")
#pragma comment(lib, "OpenMayaUI.lib")
#include "system/timer.h"
#include "system/wndproc.h"
#include "mesh/mesh.h"
#include "mesh/serialize.h"
#include "init/modulesettings.h"
#include "file/device.h"
#include "file/asset.h"
#include "file/stream.h"
#include "file/token.h"
#include "vector/vector2.h"
#include "vector/vector3.h"
#include "vector/vector4.h"
#include "vector/matrix34.h"
#include "vector/matrix44.h"
#include "rageShaderMaterial/rageShaderMaterial.h"
#include "rageShaderMaterial/rageShaderMaterialGroup.h"
#include "rageShaderMaterial/rageShaderMaterialParamTexture.h"
#include "rageShaderViewer/rageShaderViewer.h"
#include "rageShaderViewer/ModelMaterialPairManager.h"
#include "rageShaderViewer/ModelMaterialPair.h"
#include "rageShaderUpdateManager.h"
#include "rageShaderUpdateData.h"
using namespace rage;
#define CHECK_STATUS(x) \
{ \
MStatus _maya_status = (x); \
if ( MStatus::kSuccess != _maya_status ) \
{ \
MString obStrErrorMessage(__FILE__); \
obStrErrorMessage += ":"; \
obStrErrorMessage += __LINE__; \
obStrErrorMessage += ":"; \
_maya_status.perror (obStrErrorMessage); \
} \
} \
#define DEG2RAD (PI / 180.0f)
#define RAD2DEG (180.0f / PI)
///////////////////////////////////////////////////////
// DESCRIPTION:
// The init function responsible for initalizing this class
//
///////////////////////////////////////////////////////
rageShaderUpdateData::rageShaderUpdateData()
{
// Displayf("%p Initialising m_ModelIndex to -1", this);
m_pMaterial = NULL;
m_pobModelData = NULL;
Reset();
}
///////////////////////////////////////////////////////
// DESCRIPTION:
// The init function responsible for initalizing this class
//
///////////////////////////////////////////////////////
rageShaderUpdateData::~rageShaderUpdateData()
{
delete m_pMaterial;
m_pMaterial = NULL;
if (m_pobModelData && (ModelMaterialPairManager::GetInstance()))
{
// Displayf("%p Deleting the data at m_ModelIndex %d", this, m_ModelIndex);
ModelMaterialPairManager::GetInstance()->RemoveModelData(m_pobModelData);
}
}
///////////////////////////////////////////////////////
// DESCRIPTION:
// The init function responsible for initalizing this class
//
///////////////////////////////////////////////////////
void rageShaderUpdateData::Reset()
{
m_Locked = true;
MObject null;
delete m_pMaterial;
m_pMaterial = NULL;
m_Mesh.Reset();
m_Transform = M34_IDENTITY;
for (int i=0; i<rageShaderMaterialParam::LIGHTMAP_TYPE_COUNT; i++)
{
m_LightmapFileNames[i] = "none";
}
if (m_pobModelData && (ModelMaterialPairManager::GetInstance()))
{
// Displayf("%p Deleting the data at m_ModelIndex %d", this, m_ModelIndex);
ModelMaterialPairManager::GetInstance()->RemoveModelData(m_pobModelData);
m_pobModelData = NULL;
}
m_Valid = false;
m_MeshNeedsUpdate = false;
m_TransformNeedsUpdate = false;
m_ShadersNeedsUpdate = false;
m_NeedsDeleting = false;
m_Locked = false;
}
///////////////////////////////////////////////////////
// DESCRIPTION:
// The init function responsible for initalizing this class
//
///////////////////////////////////////////////////////
void rageShaderUpdateData::InitShaderUpdateData(int nIndex, const MObject & shaderNode, const rageShaderMaterial* pMaterial, MObject& obMayaNode)
{
m_Locked = true;
m_Valid = true;
// Displayf("%p Setting m_ModelIndex from %d to %d", this, m_ModelIndex, nIndex);
m_ModelIndex = nIndex;
delete m_pMaterial;
m_pMaterial = new rageShaderMaterial();
m_pMaterial->Copy(*pMaterial);
for (int i=0; i<m_pMaterial->GetShaderParamCount(); i++)
{
rageShaderMaterialParam * param = m_pMaterial->GetShaderParam(i);
if (!param->GetUiHidden() && param->GetType() == grcEffect::VT_TEXTURE)
{
rageShaderMaterialParamTexture* pobTextureParam = (rageShaderMaterialParamTexture *)param;
exportTexture(pobTextureParam->GetData(), pobTextureParam->GetTextureOutputFormats());
}
}
fixupLightMaps(obMayaNode, m_LightmapFileNames);
convertMesh(obMayaNode, shaderNode, m_Mesh);
m_MeshNeedsUpdate = true;
m_ShadersNeedsUpdate = true;
m_NeedsDeleting = false;
m_Locked = false;
}
///////////////////////////////////////////////////////
// DESCRIPTION:
// The init function responsible for initalizing this class
//
///////////////////////////////////////////////////////
void rageShaderUpdateData::UpdateMesh(MObject & obMeshNode, const MObject & shaderNode)
{
m_Locked = true;
fixupLightMaps(obMeshNode, m_LightmapFileNames);
convertMesh(obMeshNode, shaderNode, m_Mesh);
m_MeshNeedsUpdate = true;
m_Locked = false;
}
///////////////////////////////////////////////////////
// DESCRIPTION:
// The init function responsible for initalizing this class
//
///////////////////////////////////////////////////////
void rageShaderUpdateData::UpdateTransform(const Matrix34 & m34)
{
m_Locked = true;
m_Transform = m34;
m_TransformNeedsUpdate = true;
m_Locked = false;
}
///////////////////////////////////////////////////////
// DESCRIPTION:
// The init function responsible for initalizing this class
//
///////////////////////////////////////////////////////
void rageShaderUpdateData::UpdateShaders(const rageShaderMaterial* pMaterial)
{
m_Locked = true;
delete m_pMaterial;
m_pMaterial = new rageShaderMaterial();
m_pMaterial->Copy(*pMaterial);
for (int i=0; i<GetMaterial()->GetShaderParamCount(); i++)
{
rageShaderMaterialParam * param = GetMaterial()->GetShaderParam(i);
if (!param->GetUiHidden() && param->GetType() == grcEffect::VT_TEXTURE)
{
rageShaderMaterialParamTexture* pobTextureParam = (rageShaderMaterialParamTexture *)param;
exportTexture(pobTextureParam->GetData(), pobTextureParam->GetTextureOutputFormats());
}
}
m_ShadersNeedsUpdate = true;
m_Locked = false;
}
///////////////////////////////////////////////////////
// DESCRIPTION:
// The init function responsible for initalizing this class
//
///////////////////////////////////////////////////////
void rageShaderUpdateData::UpdateViewer()
{
m_Locked = true;
if (m_ShadersNeedsUpdate && !ModelMaterialPairManager::GetInstance()->IsLocked(m_ModelIndex))
{
for (int i=0; i<rageShaderMaterialParam::LIGHTMAP_TYPE_COUNT; i++)
{
m_pMaterial->SetLightmapData(m_LightmapFileNames[i], i);
}
if (m_pobModelData->UpdateShaders(GetMaterial()))
{
m_ShadersNeedsUpdate = false;
}
}
if (m_MeshNeedsUpdate && !m_pobModelData->IsLocked())
{
if (m_pobModelData->SetMeshAtIndex(m_Mesh))
{
m_MeshNeedsUpdate = false;
}
}
if (m_TransformNeedsUpdate)
{
if (m_pobModelData->UpdateMeshTransform(m_Transform))
{
m_TransformNeedsUpdate = false;
}
}
m_Locked = false;
}
///////////////////////////////////////////////////////
// DESCRIPTION:
// The function
//
///////////////////////////////////////////////////////
void rageShaderUpdateData::RefreshViewer()
{
for (int i=0; i<rageShaderMaterialParam::LIGHTMAP_TYPE_COUNT; i++)
{
m_pMaterial->SetLightmapData(m_LightmapFileNames[i], i);
}
// Displayf("%p RefreshViewer() and m_ModelIndex = %d", this, m_ModelIndex);
if(m_ModelIndex < 0)
{
Displayf("Badness");
}
m_pobModelData->UpdateShaders(m_ModelIndex, m_pMaterial);
m_pobModelData->SetMeshAtIndex(m_ModelIndex, m_Mesh);
m_pobModelData->UpdateMeshTransform(m_ModelIndex, m_Transform);
}
///////////////////////////////////////////////////////
// DESCRIPTION:
// The equals operator for the update data do easier first
//
///////////////////////////////////////////////////////
rageShaderUpdateData & rageShaderUpdateData::operator = (const rageShaderUpdateData &d)
{
m_Locked = true;
m_Valid = d.m_Valid;
m_MeshNeedsUpdate = d.m_MeshNeedsUpdate;
m_TransformNeedsUpdate = d.m_TransformNeedsUpdate;
m_ShadersNeedsUpdate = d.m_ShadersNeedsUpdate;
m_NeedsDeleting = d.m_NeedsDeleting;
m_pobModelData = d.m_pobModelData;
m_Mesh = d.m_Mesh;
m_Transform = d.m_Transform;
delete m_pMaterial;
m_pMaterial = new rageShaderMaterial();
m_pMaterial->Copy(*(d.GetMaterial()));
m_Locked = false;
return *this;
}
///////////////////////////////////////////////////////
// DESCRIPTION:
// This function is a static function.
//
// The function exports out the given tif to the viewer diretory
//
///////////////////////////////////////////////////////
bool rageShaderUpdateData::exportTexture(const MString& strInputTifName, const MString& strExportFormat)
{
// As an optimisation bail early if I can.
if((strInputTifName=="") || (strInputTifName == "none") || (strInputTifName == "null"))
{
return false;
}
//static int iNoOfExportTextureCalls = 0;
//iNoOfExportTextureCalls++;
//MGlobal::displayInfo("rageShaderUpdateManager::exportTexture() %d", iNoOfExportTextureCalls);
char outputTextureName[128];
fiAssetManager::BaseName(outputTextureName, sizeof(outputTextureName), fiAssetManager::FileName(strInputTifName.asChar()));
char outputTextureFileName[512];
strcpy(outputTextureFileName, rageShaderUpdateManager::GetInstance()->GetRageShaderAssetDirectory());
strcat(outputTextureFileName, outputTextureName);
strcat(outputTextureFileName, ".dds");
// Check to see if the file exists
u64 time = fiDeviceLocal::GetInstance().GetFileTime(outputTextureFileName);
if (time && time >= fiDeviceLocal::GetInstance().GetFileTime(strInputTifName.asChar()))
{
return false;
}
// Get the export format to use, by default, just use the first format for now
MStringArray astrPlatformAndFormatPairs;
strExportFormat.split(';', astrPlatformAndFormatPairs);
MStringArray astrPlatformAndFormat;
astrPlatformAndFormatPairs[0].split('=', astrPlatformAndFormat);
MString strDestinationFormat = astrPlatformAndFormat[astrPlatformAndFormat.length() - 1];
// Use the texture converter to convert it
MString strArguments("-f "+ strDestinationFormat +" \""+ strInputTifName +"\" \""+ MString(outputTextureFileName) +"\"");
MGlobal::displayInfo("rageTextureConvert.exe "+ strArguments);
_flushall();
// system(strCmd.asChar());
_spawnlp(_P_WAIT, "rageTextureConvert.exe", "rageTextureConvert.exe", strArguments.asChar(), NULL);
return false;
}
///////////////////////////////////////////////////////
// DESCRIPTION:
// This function gets called by updateMesh()
//
// The function fixes all the lightmap texture pointers
//
///////////////////////////////////////////////////////
bool rageShaderUpdateData::fixupLightMaps(MObject& obMayaNode, ConstString * lightmapFileNames)
{
char command[1024];
MFnMesh obFnMeshNode(obMayaNode);
MStringArray bakeSet;
sprintf(command, "listConnections -type textureBakeSet %s", obFnMeshNode.fullPathName().asChar());
MGlobal::executeCommand(command, bakeSet);
if (bakeSet.length() > 0)
{
MString path;
sprintf(command, "getAttr %s.LightMapPath", bakeSet[0].asChar());
MGlobal::executeCommand(command, path);
MString name;
sprintf(command, "getAttr %s.prefix", bakeSet[0].asChar());
MGlobal::executeCommand(command, name);
// Copy the lightmaps to the output directory
char outputTextureFileName[1024];
for (int i=0; i<rageShaderMaterialParam::LIGHTMAP_TYPE_COUNT; i++)
{
lightmapFileNames[i] = rageShaderMaterial::GetLightMapFileName(path.asChar(), name.asChar(), i);
const char* pcRageShaderAssetDirectory = rageShaderUpdateManager::GetInstance()->GetRageShaderAssetDirectory();
const char* pcLightmapPathAndFileName = lightmapFileNames[i];
const char* pcLightmapFileName = fiAssetManager::FileName(pcLightmapPathAndFileName);
sprintf(outputTextureFileName, "%s%s", pcRageShaderAssetDirectory, pcLightmapFileName);
MGlobal::displayInfo(MString("Copying light map ")+ lightmapFileNames[i] +" to "+ outputTextureFileName);
int bSuccess = CopyFile(lightmapFileNames[i], outputTextureFileName, false);
if(!bSuccess)
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
0, // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
// Display the string.
MGlobal::displayInfo("Copy failed because "+ MString((LPTSTR)lpMsgBuf));
// Free the buffer.
LocalFree( lpMsgBuf );
}
}
return true;
}
return false;
}
///////////////////////////////////////////////////////
// DESCRIPTION:
// This function gets called by updateMesh()
//
// The function converts a maya MFnMesh object into a
// rage mshMesh object.
//
///////////////////////////////////////////////////////
bool rageShaderUpdateData::convertMesh(MObject& obMayaNode, const MObject & shaderNode, mshMesh & rageMesh)
{
// Reset the out mesh
rageMesh.Reset();
MFnMesh obFnMeshNode(obMayaNode);
MObjectArray shaders;
MIntArray indices;
if (obFnMeshNode.getConnectedShaders(0,shaders,indices) != MS::kSuccess)
{
return false;
}
MStringArray uvsetnames;
obFnMeshNode.getUVSetNames(uvsetnames);
int uvSetCount = 0;
atArray <ConstString> uvSetNames;
atArray <ConstString> fixedUvSetNames;
uvSetNames.Resize(uvsetnames.length());
for (int i=0; i<uvSetNames.GetCount(); i++)
{
uvSetNames[i] = uvsetnames[i].asChar();
}
GetMaterial()->UpdateUvSetNames(uvSetNames, fixedUvSetNames);
uvSetCount = fixedUvSetNames.GetCount();
atArray <int> aMaterialDataIndices;
atArray <Vector2> aMaterialData;
for (int i=0; i<GetMaterial()->GetParamCount(); i++)
{
int index = GetMaterial()->GetParam(i)->GetMaterialDataUvSetIndex();
if (index >= 0)
{
if (aMaterialDataIndices.Find(index)>=0)
{
char buffer[256];
formatf(buffer, sizeof(buffer), "Invalid param %s more then one material id references uv set %d", GetMaterial()->GetParam(i)->GetUiName(), index);
MGlobal::displayError(buffer);
continue;
}
aMaterialDataIndices.Grow() = index;
GetMaterial()->GetParam(i)->SetMaterialData(aMaterialData.Grow());
uvSetCount = ((index+1) > uvSetCount) ? (index+1) : uvSetCount;
}
}
MStringArray asColorSetNames;
obFnMeshNode.getColorSetNames(asColorSetNames);
MColorArray colors0;
if (asColorSetNames.length() > 0)
obFnMeshNode.getFaceVertexColors(colors0, &asColorSetNames[0]);
MColorArray colors1;
if (asColorSetNames.length() > 1)
obFnMeshNode.getFaceVertexColors(colors1, &asColorSetNames[1]);
MColorArray colors2;
if (asColorSetNames.length() > 2)
obFnMeshNode.getFaceVertexColors(colors2, &asColorSetNames[2]);
// We only need one material per RAGE mesh
char mtlIndexName[32];
rageShaderMaterialGroup::SetMaterialIndex(mtlIndexName, 0);
mshMaterial & rageMtl = rageMesh.NewMtl();
rageMtl.Name = mtlIndexName;
for (int p=0; p<obFnMeshNode.numPolygons(); p++)
{
MIntArray vtxList;
obFnMeshNode.getPolygonVertices(p,vtxList);
if ((u32)p > indices.length() || indices[p] == -1)
{
continue;
}
if (shaders[indices[p]] != shaderNode)
{
continue;
}
MStatus status;
MFnDependencyNode shadingEngineNode(shaders[indices[p]], &status);
if (status.error())
{
continue;
}
MFnSet shaderSet(shaders[indices[p]],&status);
if (status.error())
{
continue;
}
MPlug surfaceShader = shaderSet.findPlug("surfaceShader");
if (surfaceShader.isNull())
{
continue;
}
MPlugArray plugs;
surfaceShader.connectedTo(plugs, true, false);
if (plugs.length() == 0)
{
continue;
}
MObject obj = plugs[0].node();
MFnDependencyNode shaderNode(obj, &status);
if (status.error())
{
continue;
}
mshPrimitive &prim = rageMtl.Prim.Append();
prim.Type = mshPOLYGON;
prim.Priority = rageMtl.Priority;
for (unsigned v=0; v<vtxList.length(); v++)
{
int idx = vtxList[v];
MPoint pos;
obFnMeshNode.getPoint(idx, pos, MSpace::kWorld);
Vector3 P((float)pos.x, (float)pos.y, (float)pos.z);
MVector MN;
obFnMeshNode.getFaceVertexNormal(p, idx, MN, MSpace::kWorld);
Vector3 N(float(MN.x),float(MN.y),float(MN.z));
// We are going to initalize the texture coords
atArray <Vector2> TC;
TC.Resize(uvSetCount);
for (int i=0; i<uvSetCount; i++)
{
bool foundData = false;
for (int j=0; j<aMaterialDataIndices.GetCount(); j++)
{
if (aMaterialDataIndices[j] == i)
{
TC[i] = aMaterialData[j];
foundData = true;
break;
}
}
if (!foundData)
{
MString uvSetName = fixedUvSetNames[i];
float fXTexCoord;
float fYTexCoord;
obFnMeshNode.getPolygonUV(p,v,fXTexCoord,fYTexCoord,&uvSetName);
// Check the values make sense, sometime Maya gives me madness
if(!FPIsFinite(fXTexCoord)) fXTexCoord = 0.0f;
if(!FPIsFinite(fYTexCoord)) fYTexCoord = 0.0f;
TC[i].x = fXTexCoord;
TC[i].y = fYTexCoord;
}
}
int ci = -1;
Vector4 C0(1,1,1,1);
if (colors0.length())
{
obFnMeshNode.getFaceVertexColorIndex(p,v,ci, &asColorSetNames[0]);
if (ci != -1)
{
C0.x = colors0[ci].r;
C0.y = colors0[ci].g;
C0.z = colors0[ci].b;
C0.w = colors0[ci].a;
if (C0.x == -1 && C0.y == -1 && C0.z == -1 && C0.w == -1)
{
C0.Set(1,1,1,1);
}
}
}
Vector4 C1(1,1,1,1);
if (colors1.length())
{
obFnMeshNode.getFaceVertexColorIndex(p,v,ci, &asColorSetNames[1]);
if (ci != -1)
{
C1.x = colors1[ci].r;
C1.y = colors1[ci].g;
C1.z = colors1[ci].b;
C1.w = colors1[ci].a;
if (C1.x == -1 && C1.y == -1 && C1.z == -1 && C1.w == -1)
{
C1.Set(1,1,1,1);
}
}
}
Vector4 C2(1,1,1,1);
if (colors2.length())
{
obFnMeshNode.getFaceVertexColorIndex(p,v,ci, &asColorSetNames[2]);
if (ci != -1)
{
C2.x = colors2[ci].r;
C2.y = colors2[ci].g;
C2.z = colors2[ci].b;
C2.w = colors2[ci].a;
if (C2.x == -1 && C2.y == -1 && C2.z == -1 && C2.w == -1)
{
C2.Set(1,1,1,1);
}
}
}
mshBinding B;
B.Reset();
mshIndex vertIdx = rageMtl.AddVertex(P,B,N,C0,C1,C2, TC.GetCount(),(TC.GetCount()>0) ? &TC[0] : NULL);
prim.Idx.Append() = vertIdx;
}
}
return true;
}