989 lines
28 KiB
C++
989 lines
28 KiB
C++
#include <algorithm>
|
|
|
|
#include <gfname.hpp>
|
|
#include "gintex.h"
|
|
|
|
#include "vector3.h"
|
|
#include "matrix4x4.h"
|
|
#include "quat.h"
|
|
|
|
using namespace std;
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
// Unconditional string compare
|
|
// REturns 1 on equal
|
|
int IsStrSame(char *Str0,char *Str1,int Len)
|
|
{
|
|
if (Len==-1)
|
|
{
|
|
Len=strlen(Str0);
|
|
if (strlen(Str1)!=Len) return(0);
|
|
}
|
|
for (int Loop=0;Loop<Len;Loop++)
|
|
{
|
|
char C0=Str0[Loop];
|
|
char C1=Str1[Loop];
|
|
if (C0>='a' && C0<='z') C0+='A'-'a';
|
|
if (C1>='a' && C1<='z') C1+='A'-'a';
|
|
if (C0!=C1) return(0);
|
|
}
|
|
return(1);
|
|
}
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
int CMat4::GetTexId(int v)
|
|
{
|
|
int NumOfTextures;
|
|
|
|
NumOfTextures=Mats.size();
|
|
|
|
if (v>=NumOfTextures)
|
|
{
|
|
GObject::Error(ERR_WARNING,"erroneous material id of %d\n",v);
|
|
v = 0;
|
|
}
|
|
|
|
if (v>=NumOfTextures)
|
|
GObject::Error(ERR_FATAL,"material asked for when none exists",v);
|
|
|
|
return Mats[v].TexId;
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
void CMat4::Load(Gifstream & In)
|
|
{
|
|
int m = In.Get32();
|
|
int o = In.Get32();
|
|
|
|
Mats.resize(m);
|
|
for (int i=0; i<m; i++)
|
|
{
|
|
for (int j=0; j<8; j++)
|
|
In.Get32();
|
|
|
|
int tf = (int)In.Get32();
|
|
int temp2 = In.Get32();
|
|
|
|
if (temp2&1 == 0)
|
|
{
|
|
tf = -1;
|
|
}
|
|
Mats[i].TexId = tf;
|
|
Mats[i].Flags = temp2;
|
|
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
void CMesh::Load(Gifstream & In)
|
|
{
|
|
Obj = In.Get32();
|
|
int NbMesh = In.Get32();
|
|
|
|
Chunk.resize(NbMesh);
|
|
|
|
for (int i=0; i<NbMesh; i++)
|
|
{
|
|
|
|
Chunk[i].MatId = s16(In.Get16());
|
|
Chunk[i].NumFace = s16(In.Get16());
|
|
Chunk[i].MeshNum = In.Get32();
|
|
Chunk[i].Attrib = In.Get32();
|
|
Chunk[i].Normals = In.Get32();
|
|
Chunk[i].Vcol = In.Get32();
|
|
Chunk[i].Tex = In.Get32();
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
void CMod4::Load(Gifstream & In)
|
|
{
|
|
Mod4Chunk ThisChunk;
|
|
In.read((char*)&ThisChunk.nCurObj , sizeof(long));
|
|
In.read(ThisChunk.Name, 32);
|
|
In.read((char*)&ThisChunk.Radius, sizeof(float));
|
|
In.read((char*)&ThisChunk.Centre.x, sizeof(float));
|
|
In.read((char*)&ThisChunk.Centre.y, sizeof(float));
|
|
In.read((char*)&ThisChunk.Centre.z, sizeof(float));
|
|
In.read((char*)&ThisChunk.Ap.x, sizeof(float));
|
|
In.read((char*)&ThisChunk.Ap.y, sizeof(float));
|
|
In.read((char*)&ThisChunk.Ap.z, sizeof(float));
|
|
Chunk.push_back(ThisChunk);
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
void CTexName::Load(Gifstream & In)
|
|
{
|
|
int NumOfNames;
|
|
|
|
NumOfNames=In.Get32();
|
|
|
|
for (int f=0;f<NumOfNames;f++)
|
|
{
|
|
vector<char> Str;
|
|
bool Done;
|
|
|
|
Str.reserve(200);
|
|
Done=false;
|
|
|
|
In.Align(4);
|
|
|
|
while (!Done)
|
|
{
|
|
char c;
|
|
c=In.get();
|
|
if (!c)
|
|
Done=true;
|
|
Str.push_back(c);
|
|
}
|
|
|
|
Names.push_back(&Str[0]);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
void CGinTree::Load(Gifstream & In)
|
|
{
|
|
LoadTree(In,-1);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CGinTree::LoadTree(Gifstream & In,int Parent)
|
|
{
|
|
CNode ThisNode;
|
|
|
|
In.Align(4);
|
|
|
|
In.read(ThisNode.Name, 32);
|
|
/* In.read((char*)&ThisNode.XPos, 4);
|
|
In.read((char*)&ThisNode.YPos, 4);
|
|
In.read((char*)&ThisNode.ZPos, 4);
|
|
|
|
In.read((char*)&ThisNode.XAng, 4);
|
|
In.read((char*)&ThisNode.YAng, 4);
|
|
In.read((char*)&ThisNode.ZAng, 4);
|
|
In.read((char*)&ThisNode.WAng, 4);
|
|
|
|
In.read((char*)&ThisNode.Xapk, 4);
|
|
In.read((char*)&ThisNode.Yapk, 4);
|
|
In.read((char*)&ThisNode.Zapk, 4);
|
|
|
|
In.read((char*)&ThisNode.Xapu, 4);
|
|
In.read((char*)&ThisNode.Yapu, 4);
|
|
In.read((char*)&ThisNode.Zapu, 4);
|
|
In.read((char*)&ThisNode.Wapu, 4);
|
|
*/
|
|
In.read((char*)&ThisNode.Pos.x, 4);
|
|
In.read((char*)&ThisNode.Pos.y, 4);
|
|
In.read((char*)&ThisNode.Pos.z, 4);
|
|
|
|
In.read((char*)&ThisNode.Ang.x, 4);
|
|
In.read((char*)&ThisNode.Ang.y, 4);
|
|
In.read((char*)&ThisNode.Ang.z, 4);
|
|
In.read((char*)&ThisNode.Ang.w, 4);
|
|
|
|
In.read((char*)&ThisNode.apk.x, 4);
|
|
In.read((char*)&ThisNode.apk.y, 4);
|
|
In.read((char*)&ThisNode.apk.z, 4);
|
|
|
|
In.read((char*)&ThisNode.apu.x, 4);
|
|
In.read((char*)&ThisNode.apu.y, 4);
|
|
In.read((char*)&ThisNode.apu.z, 4);
|
|
In.read((char*)&ThisNode.apu.w, 4);
|
|
|
|
int ChildCount= In.Get32();
|
|
SceneTree[0].AddChild( SceneTree,ThisNode,Parent);
|
|
|
|
int Idx=ThisNode.Idx;
|
|
for (int Loop=0;Loop<ChildCount;Loop++) LoadTree(In,Idx);
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
void CSkinTree::Load(Gifstream & In)
|
|
{
|
|
In.Get32(); // Skip Obj number
|
|
LoadTree(In,-1);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CSkinTree::LoadTree(Gifstream & In,int Parent)
|
|
{
|
|
CNode ThisNode;
|
|
int WeightCount;
|
|
In.Align(4);
|
|
|
|
In.read(ThisNode.Name, 32);
|
|
WeightCount=In.Get32();
|
|
if (WeightCount)
|
|
{
|
|
ThisNode.Weights.resize(WeightCount);
|
|
for (int Weight=0;Weight<WeightCount;Weight++)
|
|
{
|
|
ThisNode.Weights[Weight].VertNo=In.Get32();
|
|
In.read((char*)&ThisNode.Weights[Weight].Weight, 4);
|
|
In.read((char*)&ThisNode.Weights[Weight].Pos.x, 4);
|
|
In.read((char*)&ThisNode.Weights[Weight].Pos.y, 4);
|
|
In.read((char*)&ThisNode.Weights[Weight].Pos.z, 4);
|
|
}
|
|
}
|
|
|
|
int ChildCount= In.Get32();
|
|
SkinTree[0].AddChild( SkinTree,ThisNode,Parent);
|
|
|
|
int Idx=ThisNode.Idx;
|
|
for (int Loop=0;Loop<ChildCount;Loop++) LoadTree(In,Idx);
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
const int CHANNEL_TYPE_TREE = 7; // NODE ANIMATION
|
|
|
|
void CAnimTree::Load(Gifstream & In)
|
|
{
|
|
int AnimType=In.Get32();
|
|
if (AnimType!=CHANNEL_TYPE_TREE) return;
|
|
|
|
int FrameCount = In.Get32();
|
|
LoadTree(In,-1,FrameCount);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CAnimTree::LoadTree(Gifstream & In,int Parent,int FrameCount)
|
|
{
|
|
CNode ThisNode;
|
|
|
|
In.Align(4);
|
|
|
|
ThisNode.Anim.resize(FrameCount);
|
|
for (int Frame=0;Frame<FrameCount;Frame++)
|
|
{
|
|
/* In.read((char*)&ThisNode.Anim[Frame].XPos, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].YPos, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].ZPos, 4);
|
|
|
|
In.read((char*)&ThisNode.Anim[Frame].XAng, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].YAng, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].ZAng, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].WAng, 4);
|
|
|
|
In.read((char*)&ThisNode.Anim[Frame].kX, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].kY, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].kZ, 4);
|
|
|
|
In.read((char*)&ThisNode.Anim[Frame].uX, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].uY, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].uZ, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].uW, 4);
|
|
*/
|
|
In.read((char*)&ThisNode.Anim[Frame].Pos.x, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].Pos.y, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].Pos.z, 4);
|
|
|
|
In.read((char*)&ThisNode.Anim[Frame].Ang.x, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].Ang.y, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].Ang.z, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].Ang.w, 4);
|
|
|
|
In.read((char*)&ThisNode.Anim[Frame].apk.x, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].apk.y, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].apk.z, 4);
|
|
|
|
In.read((char*)&ThisNode.Anim[Frame].apu.x, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].apu.y, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].apu.z, 4);
|
|
In.read((char*)&ThisNode.Anim[Frame].apu.w, 4);
|
|
|
|
}
|
|
|
|
int ChildCount= In.Get32();
|
|
AnimTree[0].AddChild( AnimTree,ThisNode,Parent);
|
|
|
|
int Idx=ThisNode.Idx;
|
|
for (int Loop=0;Loop<ChildCount;Loop++) LoadTree(In,Idx,FrameCount);
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
void CKeyAnimTree::Load(Gifstream & In)
|
|
{
|
|
int AnimType=In.Get32();
|
|
if (AnimType!=CHANNEL_TYPE_TREE) return;
|
|
AnimType=In.Get32(); // Skip Node type thingy
|
|
|
|
LoadTree(In,-1);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CKeyAnimTree::LoadTree(Gifstream & In,int Parent)
|
|
{
|
|
CNode ThisNode;
|
|
int KeyCount;
|
|
In.Align(4);
|
|
|
|
KeyCount=In.Get32();
|
|
ThisNode.KeyAnim.resize(KeyCount);
|
|
for (int Frame=0;Frame<KeyCount;Frame++)
|
|
{
|
|
ThisNode.KeyAnim[Frame].Frame=In.Get32();
|
|
/* In.read((char*)&ThisNode.KeyAnim[Frame].XPos, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].YPos, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].ZPos, 4);
|
|
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].XAng, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].YAng, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].ZAng, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].WAng, 4);
|
|
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].kX, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].kY, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].kZ, 4);
|
|
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].uX, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].uY, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].uZ, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].uW, 4);
|
|
*/
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].Pos.x, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].Pos.y, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].Pos.z, 4);
|
|
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].Ang.x, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].Ang.y, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].Ang.z, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].Ang.w, 4);
|
|
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].apk.x, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].apk.y, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].apk.z, 4);
|
|
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].apu.x, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].apu.y, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].apu.z, 4);
|
|
In.read((char*)&ThisNode.KeyAnim[Frame].apu.w, 4);
|
|
|
|
}
|
|
|
|
int ChildCount= In.Get32();
|
|
AnimTree[0].AddChild( AnimTree,ThisNode,Parent);
|
|
|
|
int Idx=ThisNode.Idx;
|
|
for (int Loop=0;Loop<ChildCount;Loop++) LoadTree(In,Idx);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
bool CScene::SetPruneNodes(int Idx)
|
|
{
|
|
CNode &ThisNode=GetNode(Idx);
|
|
bool NoPrune=false;
|
|
int ChildCount=ThisNode.GetChildCount();
|
|
|
|
for (int Loop=0;Loop<ChildCount;Loop++) NoPrune|= SetPruneNodes(ThisNode.ChildList[Loop]);
|
|
|
|
int HasData=ThisNode.Weights.size() | ThisNode.Pts.size();
|
|
|
|
if (!NoPrune && !HasData)
|
|
{
|
|
ThisNode.Active=false;
|
|
return(false);
|
|
}
|
|
else
|
|
{
|
|
return(true);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CScene::BuildPruneTree(int Idx, int ParentIdx)
|
|
{
|
|
CNode &ThisNode=GetNode(Idx);
|
|
if (!ThisNode.Active) return;
|
|
|
|
ThisNode.AddPruneChild(SceneTree,PruneTree,ParentIdx);
|
|
|
|
int ChildCount=ThisNode.GetChildCount();
|
|
for (int Loop=0;Loop<ChildCount;Loop++) BuildPruneTree(ThisNode.ChildList[Loop],ThisNode.Idx);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
int IsAnimDiff(sGinAnim const &Frm0,sGinAnim const &Frm1)
|
|
{
|
|
if (Frm0.Pos.x!=Frm1.Pos.x) return(1);
|
|
if (Frm0.Pos.y!=Frm1.Pos.y) return(1);
|
|
if (Frm0.Pos.z!=Frm1.Pos.z) return(1);
|
|
|
|
if (Frm0.Ang.x!=Frm1.Ang.x) return(1);
|
|
if (Frm0.Ang.y!=Frm1.Ang.y) return(1);
|
|
if (Frm0.Ang.z!=Frm1.Ang.z) return(1);
|
|
if (Frm0.Ang.w!=Frm1.Ang.w) return(1);
|
|
return(0);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void LoadAndShrinkAnim(CNode const &KeyNode,CNode const &AnimNode,CNode &OutNode)
|
|
{
|
|
// Calc Extents from Key Frames
|
|
int Key,Frame;
|
|
int StartKey=0,EndKey=KeyNode.KeyAnim.size();
|
|
|
|
if (!EndKey) // No keys, create 1 and return
|
|
{
|
|
sGinAnim ForceKey;
|
|
ForceKey.Frame=0;
|
|
ForceKey.Pos.x=OutNode.Pos.x; ForceKey.Pos.y=OutNode.Pos.y; ForceKey.Pos.z=OutNode.Pos.z;
|
|
ForceKey.Ang.x=OutNode.Ang.x; ForceKey.Ang.y=OutNode.Ang.y; ForceKey.Ang.z=OutNode.Ang.z; ForceKey.Ang.w=OutNode.Ang.w;
|
|
OutNode.KeyAnim.push_back(ForceKey);
|
|
OutNode.ShrunkKeyAnim.push_back(ForceKey);
|
|
EndKey=0;
|
|
OutNode.StartFrame= 0;
|
|
OutNode.EndFrame= 0;
|
|
}
|
|
else
|
|
{
|
|
EndKey--;
|
|
while ((!IsAnimDiff(KeyNode.KeyAnim[StartKey], KeyNode.KeyAnim[StartKey+1])) && StartKey!=EndKey) StartKey++;
|
|
while ((!IsAnimDiff(KeyNode.KeyAnim[EndKey ], KeyNode.KeyAnim[EndKey-1])) && StartKey!=EndKey) EndKey--;
|
|
OutNode.StartFrame= KeyNode.KeyAnim[StartKey].Frame;
|
|
OutNode.EndFrame= KeyNode.KeyAnim[EndKey].Frame;
|
|
EndKey++;
|
|
}
|
|
|
|
OutNode.EndFrame++;
|
|
|
|
// Transfer Key Frames
|
|
int KeyAnimSize=KeyNode.KeyAnim.size();
|
|
for (Key=0;Key<KeyAnimSize;Key++) OutNode.KeyAnim.push_back(KeyNode.KeyAnim[Key]); // Transfer All key frames
|
|
for (Key=StartKey; Key<EndKey; Key++) OutNode.ShrunkKeyAnim.push_back(KeyNode.KeyAnim[Key]); // Transfer Shrunk key frames
|
|
|
|
// Transfer Normal frames
|
|
int AnimSize=AnimNode.Anim.size();
|
|
if (AnimSize)
|
|
{
|
|
for (Frame=0;Frame<AnimSize;Frame++) OutNode.Anim.push_back(AnimNode.Anim[Frame]); // Transfer All Normal Anim
|
|
for (Frame=OutNode.StartFrame; Frame<OutNode.EndFrame; Frame++) OutNode.ShrunkAnim.push_back(AnimNode.Anim[Frame]); // Transfer Shrunk Normal Anim
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
void Gin4File::Load(char const * Name)
|
|
{
|
|
MyFile.Load(Name);
|
|
|
|
MyFile.FindChunks("VERS",VersionChunk);
|
|
MyFile.FindChunks("TEX4",TexNamesChunk);
|
|
MyFile.FindChunks("MAT4",MatChunk);
|
|
MyFile.FindChunks("MOD4",Mod4Chunk);
|
|
MyFile.FindChunks("MESH",MshChunk);
|
|
MyFile.FindChunks("PTS4",PointsChunk);
|
|
MyFile.FindChunks("POLY",TrisChunk);
|
|
MyFile.FindChunks("VCOL",VColTrisChunk);
|
|
MyFile.FindChunks("MAP4",UVtrisChunk);
|
|
MyFile.FindChunks("TREE",SceneTreeChunk);
|
|
MyFile.FindChunks("ANIM",AnimTreeChunk);
|
|
MyFile.FindChunks("KEY4",KeyAnimTreeChunk);
|
|
MyFile.FindChunks("BONE",SkinTreeChunk);
|
|
MyFile.FindChunks("PROP",UserPropChunk);
|
|
MyFile.FindChunks("CAM4",CameraChunk);
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
void CScene::Load(const char *Name)
|
|
{
|
|
|
|
Gin4File GinFile;
|
|
FileName=Name;
|
|
GinFile.Load(Name);
|
|
|
|
std::vector<GinChunk const *> &VersionChunk=GinFile.GetVersionChunk();
|
|
std::vector<GinChunk const *> &TexNamesChunk=GinFile.GetTexNamesChunk();
|
|
std::vector<GinChunk const *> &MatChunk=GinFile.GetMatChunk();
|
|
std::vector<GinChunk const *> &MshChunk=GinFile.GetMshChunk();
|
|
std::vector<GinChunk const *> &PointsChunk=GinFile.GetPointsChunk();
|
|
std::vector<GinChunk const *> &TrisChunk=GinFile.GetTrisChunk();
|
|
std::vector<GinChunk const *> &VColTrisChunk=GinFile.GetVColTrisChunk();
|
|
std::vector<GinChunk const *> &UVtrisChunk=GinFile.GetUVtrisChunk();
|
|
std::vector<GinChunk const *> &SceneTreeChunk=GinFile.GetSceneTreeChunk();
|
|
std::vector<GinChunk const *> &AnimTreeChunk=GinFile.GetAnimTreeChunk();
|
|
std::vector<GinChunk const *> &KeyAnimTreeChunk=GinFile.GetKeyAnimTreeChunk();
|
|
std::vector<GinChunk const *> &SkinTreeChunk=GinFile.GetSkinTreeChunk();
|
|
std::vector<GinChunk const *> &UserPropChunk=GinFile.GetUserPropChunk();
|
|
std::vector<GinChunk const *> &CameraChunk=GinFile.GetCameraChunk();
|
|
|
|
int Node,NodeCount;
|
|
|
|
|
|
// Build Scene Tree
|
|
CGinTree *GT = (CGinTree*)SceneTreeChunk[0];
|
|
std::vector<CNode> const &GinTree=GT->GetTree();
|
|
|
|
NodeCount=GinTree.size();
|
|
for (Node=0;Node<NodeCount;Node++)
|
|
{
|
|
CNode ThisNode=GinTree[Node];
|
|
SceneTree[0].AddChild(SceneTree,ThisNode,ThisNode.ParentIdx);
|
|
}
|
|
|
|
// Build Node Mtx's
|
|
for (Node=0;Node<NodeCount;Node++)
|
|
{
|
|
CNode *ThisNode=&SceneTree[Node];
|
|
int ParentIdx=ThisNode->ParentIdx;
|
|
ThisNode->Mtx.Identity();
|
|
// Build Node Mtx's
|
|
if (ParentIdx!=-1)
|
|
{
|
|
// LocalMtx
|
|
Matrix4x4 ThisMtx;
|
|
CNode *ParentNode=&SceneTree[ParentIdx];
|
|
ThisMtx.Identity();
|
|
ThisNode->Ang.ToMatrix(ThisMtx);
|
|
ThisMtx.SetTranslation(ThisNode->Pos);
|
|
ThisNode->Mtx=ThisMtx*ParentNode->Mtx;
|
|
|
|
// WorldMtx
|
|
ThisNode->WorldMtx=GetWorldMatrix(SceneTree,ParentIdx);
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Load Materials
|
|
int MatN = MatChunk.size();
|
|
if (MatN)
|
|
{
|
|
CMat4 * Materials = (CMat4*)MatChunk[0];
|
|
AllMaterials = Materials->GetMaterials();
|
|
|
|
if (TexNamesChunk.size())
|
|
{
|
|
CTexName * T=(CTexName *)(TexNamesChunk[0]);
|
|
vector<GString> const & Strs=T->GetTexNames();
|
|
TextureList = Strs;
|
|
int NumOfMeshes=MshChunk.size();
|
|
for (int j=0; j<NumOfMeshes; j++)
|
|
{
|
|
CMesh *M = (CMesh*)MshChunk[j];
|
|
vector<MeshChunk> const & Mat4Id = M->GetChunk();
|
|
for (int i=0; i<Mat4Id.size(); i++)
|
|
{
|
|
if (Mat4Id[i].MatId>=0)
|
|
{
|
|
int tid = Materials->GetTexId(Mat4Id[i].MatId);
|
|
if (tid >= Strs.size() || tid < 0)
|
|
{
|
|
GObject::Error(ERR_WARNING,"Texture index odd (aksed for %d, max is %d) adjusting to 0\n",tid,Strs.size());
|
|
tid=0;
|
|
}
|
|
// else
|
|
{
|
|
GString const & TexFile=Strs[tid];
|
|
/* Only add texture to list if it hasn't been on it before */
|
|
if (find(AllTexNames.begin(),AllTexNames.end(),TexFile) == AllTexNames.end()) AllTexNames.push_back(TexFile);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GObject::Error(ERR_WARNING,"No Materials\n");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Load Models and Meshes
|
|
for (int m=0; m<MshChunk.size(); m++)
|
|
{
|
|
CMesh *M = (CMesh*)MshChunk[m];
|
|
int CurMod = M->getObj();
|
|
CNode *ThisNode=GetNodePtr(GinFile.GetModelName(CurMod));
|
|
|
|
if (loadPoints( CurMod, PointsChunk,ThisNode) != -1)
|
|
{
|
|
vector<MeshChunk> const &MeshChunks = M->GetChunk();
|
|
for (int mn=0; mn<MeshChunks.size(); mn++)
|
|
{
|
|
if (loadTris( CurMod, MeshChunks[mn].MeshNum, TrisChunk,ThisNode)!=-1)
|
|
{
|
|
int MatIdx = addMaterialIdx(MeshChunks[mn].MatId);
|
|
for (int i=0; i<MeshChunks[mn].NumFace; i++) ThisNode->TriMaterial.push_back(MatIdx);
|
|
loadVCol( CurMod, MeshChunks[mn].MeshNum, VColTrisChunk,ThisNode);
|
|
loadUV( CurMod, MeshChunks[mn].MeshNum, UVtrisChunk,ThisNode);
|
|
int Size=ThisNode->Tris.size();
|
|
ThisNode->UVTris.resize(Size);
|
|
ThisNode->VColTris.resize(Size);
|
|
ThisNode->TriMaterial.resize(Size);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Load Anims
|
|
// Sort KeyFrame Anims
|
|
CKeyAnimTree *KATC= (CKeyAnimTree*)KeyAnimTreeChunk[0];
|
|
CAnimTree *NATC = (CAnimTree*)AnimTreeChunk[0];
|
|
std::vector<CNode>const &KeyAnimTree=KATC->GetTree();
|
|
std::vector<CNode>const &AnimTree=NATC->GetTree();
|
|
|
|
NodeCount=KeyAnimTree.size();
|
|
for (Node=0;Node<NodeCount;Node++)
|
|
{
|
|
LoadAndShrinkAnim(KeyAnimTree[Node],AnimTree[Node],SceneTree[Node]);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Load Camera(s)
|
|
int CamCount=CameraChunk.size();
|
|
if (CamCount)
|
|
{
|
|
for (int Cam=0;Cam<CamCount;Cam++)
|
|
{
|
|
CCamera *CamC= (CCamera *)CameraChunk[Cam];
|
|
Camera.push_back(CamC->GetCam());
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Load Skin Weight
|
|
if (SkinTreeChunk.size())
|
|
{
|
|
CSkinTree *ST = (CSkinTree*)SkinTreeChunk[0];
|
|
std::vector<CNode> const &SkinTree=ST->GetTree();
|
|
NodeCount=SkinTree.size();
|
|
for (Node=0;Node<NodeCount;Node++)
|
|
{
|
|
int WeightCount=SkinTree[Node].Weights.size();
|
|
if (WeightCount)
|
|
{
|
|
SceneTree[Node].Weights.resize(WeightCount);
|
|
for (int Weight=0;Weight<WeightCount;Weight++) SceneTree[Node].Weights[Weight]=SkinTree[Node].Weights[Weight];
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Load User Props - Loaded as Ini File
|
|
int PropCount=UserPropChunk.size();
|
|
for (int Loop=0;Loop<PropCount;Loop++)
|
|
{
|
|
CUserProp *UP=(CUserProp*)UserPropChunk[Loop];
|
|
if (UP)
|
|
{
|
|
CNode *ThisNode=GetNodePtr(UP->GetModNum()+1); // Skip SceneRoot);
|
|
if (ThisNode)
|
|
{
|
|
std::vector<char> const & Prop=UP->GetUserProp();
|
|
int Size=Prop.size()-1;
|
|
if (Size>0)
|
|
{
|
|
|
|
char *PropPtr=(char*)&Prop[0];
|
|
ThisNode->UserProp.Import(PropPtr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Build Pruned Tree
|
|
ResetPruneTree();
|
|
SetPruneNodes(0);
|
|
BuildPruneTree(0,-1);
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Print Trees
|
|
|
|
// PrintSceneTree();
|
|
// PrintPruneTree();
|
|
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
void CScene::PrintTreeNode(int Idx,const int Tree)
|
|
{
|
|
/*
|
|
CNode &Node=SceneTree[Idx];
|
|
int NodeIdx,NodeParentIdx;
|
|
std::vector<int> ChildList;
|
|
if (Tree==0)
|
|
{
|
|
ChildList=Node.ChildList;
|
|
NodeIdx=Node.Idx;
|
|
NodeParentIdx=Node.ParentIdx;
|
|
}
|
|
else
|
|
{
|
|
ChildList=Node.PruneChildList;
|
|
NodeIdx=Node.PruneIdx;
|
|
NodeParentIdx=Node.PruneParentIdx;
|
|
}
|
|
|
|
int ChildCount=ChildList.size();
|
|
|
|
for (int Sp=0;Sp<PrintTreeSpace;Sp++) printf("| ");
|
|
printf("(P=%i I=%i C=%i) %s - T=%i, V=%i A=%i\n",NodeParentIdx,NodeIdx,ChildCount,Node.Name,Node.Tris.size(),Node.Pts.size(),Node.Anim.size());
|
|
PrintTreeSpace++;
|
|
|
|
for (int Child=0;Child<ChildCount;Child++) PrintTreeNode(ChildList[Child],Tree);
|
|
PrintTreeSpace--;
|
|
*/
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
int CScene::loadPoints( int CurMod, vector<GinChunk const *> &Points ,CNode *ThisNode)
|
|
{
|
|
for (int f=0; f<Points.size(); f++)
|
|
{
|
|
CPts4 * T;
|
|
|
|
T=(CPts4 *)(Points[f]);
|
|
|
|
if (T->GetModNum() == CurMod)
|
|
{
|
|
std::vector<Vector3> const & ThesePts=T->GetPts();
|
|
int Size= ThesePts.size();
|
|
ThisNode->Pts.resize(Size);
|
|
ThisNode->RelPts.resize(Size);
|
|
|
|
Matrix4x4 IMtx=ThisNode->Mtx;
|
|
IMtx.Invert();
|
|
|
|
for (int g=0;g<Size;g++)
|
|
{
|
|
/*Abs Pnt*/ ThisNode->Pts[g] = ThesePts[g];
|
|
/*Rel Pnt*/ ThisNode->RelPts[g]=IMtx*ThesePts[g];
|
|
}
|
|
return (Size);
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
int CScene::loadTris( int CurMod, int CurMesh, vector<GinChunk const *> &Tris,CNode *ThisNode)
|
|
{
|
|
for (int i=0; i<Tris.size(); i++)
|
|
{
|
|
CPoly * T;
|
|
|
|
T=(CPoly *)(Tris[i]);
|
|
if (T->GetModNum() == CurMod && T->GetMeshNum() == CurMesh)
|
|
{
|
|
std::vector<sGinTri> const & TheseTris=T->GetTris();
|
|
int Size = TheseTris.size();
|
|
|
|
ThisNode->TriBase=ThisNode->Tris.size();
|
|
|
|
for (int j=0; j<Size; j++) ThisNode->Tris.push_back(TheseTris[j]);
|
|
return (Size);
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
int CScene::loadUV( int CurMod, int CurMesh, vector<GinChunk const *> &UVTris,CNode *ThisNode)
|
|
{
|
|
for (int i=0; i<UVTris.size(); i++)
|
|
{
|
|
CUVtri *T;
|
|
T = (CUVtri*)UVTris[i];
|
|
if (T->GetModNum() == CurMod && T->GetMeshNum() == CurMesh)
|
|
{
|
|
std::vector<sUVTri> const & TheseTris=T->GetUVTris();
|
|
int Size = TheseTris.size();
|
|
|
|
for (int j=0; j<Size; j++) ThisNode->UVTris.push_back(TheseTris[j]);
|
|
return (Size);
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
int CScene::loadVCol( int CurMod, int CurMesh, vector<GinChunk const *> &VColTris,CNode *ThisNode)
|
|
{
|
|
for (int i=0; i<VColTris.size(); i++)
|
|
{
|
|
CVcol *T;
|
|
T = (CVcol*)VColTris[i];
|
|
if (T->GetModNum() == CurMod && T->GetMeshNum() == CurMesh)
|
|
{
|
|
std::vector<sVColTri> const & TheseTris=T->GetVcolTris();
|
|
int Size = TheseTris.size();
|
|
|
|
for (int j=0; j<Size; j++) ThisNode->VColTris.push_back(TheseTris[j]);
|
|
return (Size);
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
int CScene::addMaterialIdx( int idx )
|
|
{
|
|
int c = UsedMaterials.size();
|
|
for (int i=0; i<c; i++)
|
|
{
|
|
if (UsedMaterials[i] == idx) return i;
|
|
}
|
|
UsedMaterials.push_back(idx);
|
|
return c;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
static GString GetNameAndExtOnly(char const * Name)
|
|
{
|
|
GString Rep(Name);
|
|
|
|
Rep.Filter("/",'\\');
|
|
|
|
GFName FName(Rep);
|
|
|
|
Rep=FName.File();
|
|
Rep+=".";
|
|
Rep+=FName.Ext();
|
|
|
|
Rep.Lower();
|
|
|
|
return(Rep);
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
void CScene::GetNonSharedTextures(vector<GString> const & SharedTextures,vector<GString> & Dest)
|
|
{
|
|
for (int f=0;f<AllTexNames.size();f++)
|
|
{
|
|
bool Found;
|
|
|
|
Found=false;
|
|
|
|
GString NameOnly(GetNameAndExtOnly(AllTexNames[f]));
|
|
|
|
for (int t=0;t<SharedTextures.size() && !Found;t++)
|
|
{
|
|
GString TexNameOnly(GetNameAndExtOnly(SharedTextures[t]));
|
|
Found=TexNameOnly==NameOnly;
|
|
}
|
|
|
|
if (!Found)
|
|
{
|
|
GFName TexName(AllTexNames[f]);
|
|
GFName GinName(FileName);
|
|
GinName.File(TexName.File());
|
|
GinName.Ext(TexName.Ext());
|
|
GString FinalName(GinName.FullName());
|
|
|
|
FinalName.Lower();
|
|
|
|
Dest.push_back(FinalName);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
|
|
Matrix4x4 GetWorldMatrix(std::vector<CNode> const &Tree,int Idx)
|
|
{
|
|
CNode ThisNode=Tree[Idx];
|
|
int ParentIdx=ThisNode.ParentIdx;
|
|
Matrix4x4 ParentMtx, ThisMtx, PosMtx, RotMtx, StrMtx, SclMtx, IStrMtx;
|
|
|
|
ParentMtx.Identity();
|
|
|
|
if (ParentIdx!=-1) ParentMtx=GetWorldMatrix(Tree,ParentIdx);
|
|
|
|
|
|
// ThisMtx.Identity();
|
|
// PosMtx.Identity();
|
|
// RotMtx.Identity();
|
|
// StrMtx.Identity();
|
|
// SclMtx.Identity();
|
|
// IStrMtx.Identity();
|
|
|
|
// Pos
|
|
PosMtx.Identity();
|
|
PosMtx.SetTranslation(ThisNode.Pos);
|
|
|
|
// Rot
|
|
ThisNode.Ang.ToMatrix(RotMtx);
|
|
|
|
// Stretch
|
|
ThisNode.apu.ToMatrix(StrMtx);
|
|
IStrMtx=StrMtx;
|
|
IStrMtx.Invert();
|
|
// Scale
|
|
SclMtx.Identity();
|
|
SclMtx.ApplyScale(ThisNode.apk);
|
|
|
|
ThisMtx= PosMtx*RotMtx*StrMtx*SclMtx*IStrMtx;
|
|
|
|
return(ParentMtx*ThisMtx);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
Vector3 GetWorldPos(std::vector<CNode> const &Tree,int Idx)
|
|
{
|
|
CNode ThisNode=Tree[Idx];
|
|
//Vector3 ThisPos(ThisNode.XPos,ThisNode.YPos,ThisNode.ZPos);
|
|
Matrix4x4 WorldMtx=GetWorldMatrix(Tree,ThisNode.ParentIdx);
|
|
|
|
// if (WorldMtx!=ThisNode.WorldMtx) printf("!!!");
|
|
return(WorldMtx*ThisNode.Pos);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
Vector3 GetWorldPos(Matrix4x4 &WorldMtx,Vector3 &ThisPos)
|
|
{
|
|
return(WorldMtx*ThisPos);
|
|
}
|
|
|
|
Vector3 CNode::GetWorldPos(Vector3 &Pos)
|
|
{
|
|
|
|
return(::GetWorldPos(WorldMtx,Pos));
|
|
}
|