/*********************/ /*** MkLevel Class ***/ /*********************/ #include "stdio.h" #include <misc.hpp> #include <GFName.hpp> #include <conio.h> #include <iostream.h> #include <vector> #include <DaveLib.h> #include "MkLevel.h" #include "Layers\MkLevelLayer.h" #include "Layers\MkLevelLayerTile.h" #include "Layers\MkLevelLayer3d.h" #include "Layers\MkLevelLayerShade.h" #include "Layers\MkLevelLayerCollision.h" #include "Layers\MkLevelLayerActor.h" #include "Layers\MkLevelLayerItem.h" #include "Layers\MkLevelLayerPlatform.h" #include "Layers\MkLevelLayerFX.h" #include "Layers\MkLevelLayerTrigger.h" #include "Layers\MkLevelLayerHazard.h" #define PSX_TILE2D_HEIGHT (12) #define PSX_TILE3D_HEIGHT (16) //*************************************************************************** struct sLayerNameTable { int Type,SubType; char *Name; }; sLayerNameTable LayerNameTable[]= { {LAYER_TYPE_SHADE,LAYER_SUBTYPE_BACK,"Shade"}, {LAYER_TYPE_TILE,LAYER_SUBTYPE_MID,"Mid"}, {LAYER_TYPE_TILE,LAYER_SUBTYPE_ACTION,"Action"}, {LAYER_TYPE_COLLISION,LAYER_SUBTYPE_NONE,"Collision"}, {LAYER_TYPE_ACTOR,LAYER_SUBTYPE_NONE,"Actor List"}, {LAYER_TYPE_ITEM,LAYER_SUBTYPE_NONE,"Item List"}, {LAYER_TYPE_PLATFORM,LAYER_SUBTYPE_NONE,"Platform List"}, {LAYER_TYPE_TRIGGER,LAYER_SUBTYPE_NONE,"Trigger List"}, {LAYER_TYPE_FX,LAYER_SUBTYPE_NONE,"FX List"}, {LAYER_TYPE_HAZARD,LAYER_SUBTYPE_NONE,"Hazard List"}, }; #define LayerNameTableSize sizeof(LayerNameTable)/sizeof(sLayerNameTable) //*************************************************************************** int TSize,QSize,VSize; int Tile2dSize,Tile3dSize; const char *ModelExcludeGroupName="ModelExcludeList"; const char *ModelOtOfsGroupName="ModelOtOfs"; int LocalOptCount=0; //*************************************************************************** const GString ConfigFilename="MkLevel.ini"; sExpLayerTile BlankTile={0,0}; const float InElemXMin=-0.5f; const float InElemXMax=+0.5f; const float InElemYMin=-0.0f; const float InElemYMax=+1.0f; const float InElemZMin=-4.0f; const float InElemZMax=+4.0f; const float OutElemXMin=-0.5f; const float OutElemXMax=+0.5f; const float OutElemYMin=-0.5f; const float OutElemYMax=+0.5f; const float OutElemZMin=-4.0f; const float OutElemZMax=+4.0f; Vector3 DefVtxTable[8]= { Vector3(OutElemXMin,OutElemYMin,OutElemZMin), // FLU Vector3(OutElemXMax,OutElemYMin,OutElemZMin), // FRU Vector3(OutElemXMin,OutElemYMax,OutElemZMin), // FLD Vector3(OutElemXMax,OutElemYMax,OutElemZMin), // FRD Vector3(OutElemXMin,OutElemYMin,OutElemZMax), // BLU Vector3(OutElemXMax,OutElemYMin,OutElemZMax), // BRU Vector3(OutElemXMin,OutElemYMax,OutElemZMax), // BLD Vector3(OutElemXMax,OutElemYMax,OutElemZMax), // BRD }; #define DefVtxTableSize sizeof(DefVtxTable)/sizeof(Vector3) //*************************************************************************** CMkLevel::CMkLevel() { memset(&LevelHdr,0,sizeof(sLevelHdr)); // Add Blanks AddTile2d(BlankTile); AddTile3d(BlankTile); OutElem3d.resize(1); } //*************************************************************************** CMkLevel::~CMkLevel() { } //*************************************************************************** void CMkLevel::SetAppDir(const char *AppPath) { #ifdef _DEBUG AppDir="\\spongebob\\tools\\data\\bin\\"; #else GFName Path=AppPath; Path.File(""); Path.Ext(""); AppDir=Path.FullName(); #endif } //*************************************************************************** void CMkLevel::Init(const char *Filename,const char *OutFilename,const char *IncDir,int TPBase,int TPW,int TPH,int _PakW,int _PakH,bool _LocalGeom,float _SnapThresh) { // Setup filenames and paths GFName Path; char *Ptr; char Buffer[256]; strcpy(Buffer,Filename); Ptr=Buffer; while (*Ptr) { if (*Ptr=='\\' || *Ptr=='/') *Ptr=' '; Ptr++; } while (*Ptr!=' ') Ptr--; *Ptr--=0; while (*Ptr!=' ') Ptr--; Ptr--; while (*Ptr!=' ') Ptr--; Ptr++; LevelName=Ptr; InFilename=Filename; Path=Filename; // LevelName=Path.File(); Path.File(""); Path.Ext(""); InPath=Path.FullName(); Path=OutFilename; Path.Ext(""); LevelFullName=Path.File(); LevelFullName.Upper(); OutName=Path.FullName(); OutIncName=IncDir; OutIncName+=Path.File(); OutIncName+="_INF.h"; // Load ini file Config.LoadAndImport(GString(AppDir+ConfigFilename)); // Setup Texgrab if (TPBase==-1 || TPW==-1 || TPH==-1) GObject::Error(ERR_FATAL,"TPage not set\n"); TexGrab.SetTPage(TPBase,TPW,TPH); TexGrab.SetOutFile(GString(OutName+".Tex")); TexGrab.SetDebug(DebugOn); TexGrab.SetDebugOut(GString(OutName+".Lbm")); TexGrab.NoSort(); TexGrab.AnimatedHeadersOnly(true); TexGrab.DontOutputBoxes(true); TexGrab.AllowRotate(false); TexGrab.ShrinkToFit(false); // Set up other stuph FlatFace[0].vtx[0].x=+0.5f; FlatFace[0].vtx[0].y=+1.0f; FlatFace[0].vtx[0].z=-4.0f; FlatFace[0].vtx[1].x=-0.5f; FlatFace[0].vtx[1].y= 0.0f; FlatFace[0].vtx[1].z=-4.0f; FlatFace[0].vtx[2].x=+0.5f; FlatFace[0].vtx[2].y= 0.0f; FlatFace[0].vtx[2].z=-4.0f; FlatFace[0].uv[0][0]=1; FlatFace[0].uv[0][1]=1; FlatFace[0].uv[1][0]=0; FlatFace[0].uv[1][1]=0; FlatFace[0].uv[2][0]=1; FlatFace[0].uv[2][1]=0; FlatFace[0].Flags=0; FlatFace[1].vtx[0].x=-0.5f; FlatFace[1].vtx[0].y= 0.0f; FlatFace[1].vtx[0].z=-4.0f; FlatFace[1].vtx[1].x=+0.5f; FlatFace[1].vtx[1].y=+1.0f; FlatFace[1].vtx[1].z=-4.0f; FlatFace[1].vtx[2].x=-0.5f; FlatFace[1].vtx[2].y=+1.0f; FlatFace[1].vtx[2].z=-4.0f; FlatFace[1].uv[0][0]=0; FlatFace[1].uv[0][1]=0; FlatFace[1].uv[1][0]=1; FlatFace[1].uv[1][1]=1; FlatFace[1].uv[2][0]=0; FlatFace[1].uv[2][1]=1; FlatFace[1].Flags=0; // Setup Extra Info PakW=_PakW; PakH=_PakH; LocalGeom=_LocalGeom; SnapThresh=_SnapThresh; AddDefVtx(OutVtxList); } //*************************************************************************** void CMkLevel::AddDefVtx(vector<sVtx> &VtxList) { CFaceStore F; for (int i=0; i<DefVtxTableSize; i++) { F.AddVtx(VtxList,DefVtxTable[i]); } } //*************************************************************************** int CMkLevel::AddModel(const char *Name,int TriStart,int TriCount) { sMkLevelModel ThisModel; int ModelID; GString ModelName=Name; ThisModel.Name=Name; ThisModel.TriStart=TriStart; ThisModel.TriCount=TriCount; if (Config.FindKey(ModelExcludeGroupName,Name)!=-1) { ThisModel.TriCount=0; } ModelID=ModelList.Add(ThisModel); return(ModelID); } //*************************************************************************** void CMkLevel::PreProcessModels() { int i,ListSize=ModelList.size(); for (i=0; i<ListSize; i++) { sMkLevelModel &ThisModel=ModelList[i]; int OtOfs=0; Config.GetInt(ModelOtOfsGroupName,ThisModel.Name,OtOfs); if (OtOfs) printf("ModelOTOfs %s %i\n",ThisModel.Name,OtOfs); ThisModel.ElemID=Create3dElem(ThisModel.TriCount,ThisModel.TriStart,false,false,OtOfs); // always all models as global for the moment } } //*************************************************************************** void CMkLevel::ProcessModels() { } //*************************************************************************** //*** Load ****************************************************************** //*************************************************************************** void CMkLevel::Load() { FILE *File; sExpFileHdr *FileHdr; int Size; printf("Load %s\n",LevelName); File=fopen(InFilename,"rb"); if (!File) GObject::Error(ERR_FATAL,"%s Not found\n",InFilename); // Calc File Size fseek(File,0,SEEK_END); Size=ftell(File); fseek(File,0,SEEK_SET); FileHdr=(sExpFileHdr*)malloc(Size); // Load It fread(FileHdr,Size,1,File); fclose(File); LoadTiles(FileHdr); LoadLayers(FileHdr); SnapTiles(); free(FileHdr); } //*************************************************************************** void CMkLevel::LoadStrList(CList<GString> &List,char *TexPtr,int Count) { char FullName[1024]; GString FilePath; for (int i=0; i<Count; i++) { GString InName=InPath; InName+=TexPtr; _fullpath( FullName, InName, 1024); List.push_back(GString(FullName)); TexPtr+=strlen(TexPtr)+1; } } //*************************************************************************** void CMkLevel::LoadTiles(sExpFileHdr *FileHdr) { u8 *ByteHdr=(u8*)FileHdr; int i,ListSize; int RGBSize; TileW=FileHdr->TileW; TileH=FileHdr->TileH; RGBSize=TileW*TileH*3; // Load SetNames LoadStrList(InSetNameList,(char*) &ByteHdr[FileHdr->SetNameOfs],FileHdr->SetNameCount); // Load TexNames LoadStrList(InTexNameList,(char*) &ByteHdr[FileHdr->TexNameOfs],FileHdr->TexNameCount); // Load Tris sExpTri *TriPtr=(sExpTri*) &ByteHdr[FileHdr->TriOfs]; InTriList.resize(FileHdr->TriCount); for (i=0; i<FileHdr->TriCount; i++) { InTriList[i]=TriPtr[i]; } // Load Tiles u8 *TilePtr=(u8*) &ByteHdr[FileHdr->TileOfs]; InTileList.resize(FileHdr->TileCount); for (i=0; i<FileHdr->TileCount; i++) { sExpTile *ThisTilePtr=(sExpTile*)TilePtr; sExpTile &InTile=InTileList[i]; InTile=*ThisTilePtr; // Skip RGB Image, not needed (and too buggy) // InTile.RGB=(u8*)malloc(RGBSize); // memcpy(InTile.RGB,TilePtr+sizeof(sExpTile),RGBSize); InTile.RGB=0; TilePtr+=RGBSize+sizeof(sExpTile); } // Load 2d bitmaps ListSize=InSetNameList.size(); BmpList.resize(ListSize); for (i=0; i<ListSize; i++) { GString Ext=GFName(InSetNameList[i]).Ext(); if (Ext=="BMP") { BmpList[i].LoadBMP(InSetNameList[i]); } } } //*************************************************************************** void CMkLevel::LoadLayers(sExpFileHdr *FileHdr) { u8 *ByteHdr=(u8*)FileHdr; for (int i=0; i<FileHdr->LayerCount; i++) { sExpLayerHdr *LayerHdr=(sExpLayerHdr *)&ByteHdr[FileHdr->LayerOfs[i]]; switch(LayerHdr->Type) { case LAYER_TYPE_TILE: switch (LayerHdr->SubType) { case LAYER_SUBTYPE_ACTION: LayerList.push_back(new CMkLevelLayer3d(LayerHdr)); break; case LAYER_SUBTYPE_MID: LayerList.push_back(new CMkLevelLayerTile(LayerHdr)); break; case LAYER_SUBTYPE_BACK: default: break; } break; case LAYER_TYPE_COLLISION: LayerList.push_back(new CMkLevelLayerCollision(LayerHdr)); break; case LAYER_TYPE_SHADE: LayerList.push_back(new CMkLevelLayerShade(LayerHdr)); break; case LAYER_TYPE_ACTOR: LayerList.push_back(new CMkLevelLayerActor(LayerHdr)); break; case LAYER_TYPE_ITEM: LayerList.push_back(new CMkLevelLayerItem(LayerHdr)); break; case LAYER_TYPE_PLATFORM: LayerList.push_back(new CMkLevelLayerPlatform(LayerHdr)); break; case LAYER_TYPE_TRIGGER: LayerList.push_back(new CMkLevelLayerTrigger(LayerHdr)); break; case LAYER_TYPE_FX: LayerList.push_back(new CMkLevelLayerFX(LayerHdr)); break; case LAYER_TYPE_HAZARD: LayerList.push_back(new CMkLevelLayerHazard(LayerHdr)); break; default: GObject::Error(ERR_FATAL,"Unknown Layer Type\n"); } } } //*************************************************************************** void CMkLevel::SnapTiles() { int i,ListSize=InTileList.size(); float SnapXMin=InElemXMin+SnapThresh; float SnapXMax=InElemXMax-SnapThresh; float SnapYMin=InElemYMin+SnapThresh; float SnapYMax=InElemYMax-SnapThresh; float SnapZMin=InElemZMin+SnapThresh; float SnapZMax=InElemZMax-SnapThresh; for (i=0;i<ListSize;i++) { sExpTile &ThisTile=InTileList[i]; for (int T=0; T<ThisTile.TriCount; T++) { sExpTri &ThisTri=InTriList[ThisTile.TriStart+T]; for (int p=0;p<3; p++) { Vector3 &V=ThisTri.vtx[p]; if (V.x<SnapXMin) V.x=InElemXMin; if (V.x>SnapXMax) V.x=InElemXMax; if (V.y<SnapYMin) V.y=InElemYMin; if (V.y>SnapYMax) V.y=InElemYMax; if (V.z<SnapZMin) V.z=InElemZMin; if (V.z>SnapZMax) V.z=InElemZMax; } } } } //*************************************************************************** //*** Process *************************************************************** //*************************************************************************** void CMkLevel::Process() { printf("PreProcess Layers\n"); PreProcessLayers(); printf("PreProcess ElemBanks\n"); PreProcessElemBank2d(); PreProcessElemBank3d(); printf("PreProcess Models\n"); PreProcessModels(); printf("Process Textures\n"); TexGrab.Process(); printf("Process ElemBanks\n"); ProcessElemBank2d(); ProcessElemBank3d(); printf("Process Layers\n"); ProcessLayers(); printf("Process Models\n"); ProcessModels(); } //*************************************************************************** void CMkLevel::PreProcessLayers() { int LayerCount=LayerList.size(); for (int i=0; i<LayerCount; i++) { LayerList[i]->PreProcess(this); } } //*************************************************************************** void CMkLevel::ProcessLayers() { int LayerCount=LayerList.size(); for (int i=0; i<LayerCount; i++) { LayerList[i]->Process(this); } } //*************************************************************************** int CMkLevel::AddTile2d(sExpLayerTile &InTile) { sUsedTile2d ThisTile; ThisTile.Tile=InTile.Tile; ThisTile.Flags=InTile.Flags; return(UsedTile2dList.Add(ThisTile)); } //*************************************************************************** int CMkLevel::AddTile3d(sExpLayerTile &InTile) { sUsedTile3d ThisTile; ThisTile.Tile=InTile.Tile; ThisTile.Flags=InTile.Flags; int TileID=UsedTile3dList.Add(ThisTile); int TileIdx=(TileID<<2) | (InTile.Flags & PC_TILE_FLAG_MIRROR_XY); return(TileIdx); } //*************************************************************************** void CMkLevel::PreProcessElemBank2d() { int i,ListSize=UsedTile2dList.size(); // Extract Tex data from list for (i=1; i<ListSize; i++) { // Skip blank sUsedTile2d &ThisTile=UsedTile2dList[i]; ThisTile.TexID=Create2dTile(ThisTile.Tile,ThisTile.Flags,PSX_TILE2D_HEIGHT); } } //*************************************************************************** void CMkLevel::ProcessElemBank2d() { int i,ListSize=UsedTile2dList.size(); vector<sTexOutInfo> &TexInfo=TexGrab.GetTexInfo(); OutElem2d.resize(ListSize); for (i=1; i<ListSize; i++) { // Skip blank sUsedTile2d &InTile=UsedTile2dList[i]; sElem2d &OutElem=OutElem2d[i]; SetUpTileUV(OutElem,TexInfo[InTile.TexID]); } } //*************************************************************************** void CMkLevel::PreProcessElemBank3d() { int i,ListSize=UsedTile3dList.size(); for (i=1; i<ListSize; i++) { // Skip Blank sUsedTile3d &ThisTile=UsedTile3dList[i]; ThisTile.Tile=Create3dTile(ThisTile.Tile,ThisTile.Flags); } } //*************************************************************************** int MaxElemTri=0,MaxElemQuad=0,MaxElemVtx=0; void CMkLevel::ProcessElemBank3d() { //int i,ListSize=UsedTile3dList.size(); <--- UsedTile3dList is tiles only!! int i,ListSize=OutElem3d.size(); for (i=0; i<ListSize; i++) { ProcessElem3d(OutElem3d[i]); } printf("Max Elem Tri =%i\tMax Elem Quad =%i\tMax Elem Vtx =%i\n",MaxElemTri,MaxElemQuad,MaxElemVtx); if (LocalGeom) { printf("LocalGeom Optimised %i/%i\n",LocalOptCount,ListSize); } } //*************************************************************************** void CMkLevel::ProcessElem3d(sOutElem3d &ThisElem) { CFaceStore &ThisList=ThisElem.FaceStore; ThisList.setMaxStripLength(StripLength); ThisElem.Elem3d.TriStart=OutTriList.size(); ThisElem.Elem3d.QuadStart=OutQuadList.size(); if (!ThisElem.LocalGeom) { // Global Geom ThisList.Process(OutTriList,OutQuadList,OutVtxList); CalcOtOfs(OutTriList,OutVtxList,ThisElem.Elem3d.TriStart,ThisList.GetTriFaceCount()); CalcOtOfs(OutQuadList,OutVtxList,ThisElem.Elem3d.QuadStart,ThisList.GetQuadFaceCount()); } else { // Local Geom vector<sVtx> LocalVtxList; AddDefVtx(LocalVtxList); ThisList.Process(OutTriList,OutQuadList,LocalVtxList); ThisElem.Elem3d.VtxIdxStart=OutLocalVtxIdxList.size(); int ListSize=LocalVtxList.size(); int LocalVtxCount=0; for (int v=8; v<ListSize; v++) { u16 Idx=CFaceStore::AddVtx(OutVtxList,LocalVtxList[v]); OutLocalVtxIdxList.push_back(Idx); LocalVtxCount++; } if (LocalVtxCount<=0) { LocalOptCount++; LocalVtxCount=0; } ThisElem.Elem3d.VtxTriCount=LocalVtxCount/3; if (LocalVtxCount%3) ThisElem.Elem3d.VtxTriCount++; // printf("%i=%i\n",LocalVtxCount,ThisElem.Elem3d.VtxTriCount); CalcOtOfs(OutTriList,LocalVtxList,ThisElem.Elem3d.TriStart,ThisList.GetTriFaceCount()); CalcOtOfs(OutQuadList,LocalVtxList,ThisElem.Elem3d.QuadStart,ThisList.GetQuadFaceCount()); } ThisElem.Elem3d.TriCount=ThisList.GetTriFaceCount(); ThisElem.Elem3d.QuadCount=ThisList.GetQuadFaceCount(); if (!ThisElem.Model) { // Gen max polys per tile (NOT MODEL) if (MaxElemTri<ThisElem.Elem3d.TriCount) MaxElemTri=ThisElem.Elem3d.TriCount; if (MaxElemQuad<ThisElem.Elem3d.QuadCount) MaxElemQuad=ThisElem.Elem3d.QuadCount; if (MaxElemVtx<ThisElem.Elem3d.VtxTriCount*3) MaxElemVtx=ThisElem.Elem3d.VtxTriCount*3; } } //*************************************************************************** int OTMin=0; int OTMax=16-1; void CMkLevel::CalcOtOfs(vector<sTri> &PList,vector<sVtx> &VtxList,int Start,int Count) { int ZOfs=+4*Scale; int PntCount=3; for (int i=0;i<Count;i++) { sTri &P=PList[Start+i]; float OtOfs=0; int Z[3]; // Get VtxZ Z[0]=VtxList[P.P0].vz+ZOfs; Z[1]=VtxList[P.P1].vz+ZOfs; Z[2]=VtxList[P.P2].vz+ZOfs; for (int p=0; p<PntCount; p++) { OtOfs+=Z[p]*Z[p]; } OtOfs=sqrt(OtOfs/PntCount); OtOfs/=8; // printf("%i\n",P.OTOfs); OtOfs+=P.OTOfs; if (OtOfs>OTMax) OtOfs=OTMax; if (OtOfs<OTMin) OtOfs=OTMin; P.OTOfs=OtOfs; } } //*************************************************************************** void CMkLevel::CalcOtOfs(vector<sQuad> &PList,vector<sVtx> &VtxList,int Start,int Count) { int ZOfs=+4*Scale; int PntCount=4; for (int i=0;i<Count;i++) { sQuad &P=PList[Start+i]; float OtOfs=0; int Z[4]; // Get VtxZ Z[0]=VtxList[P.P0].vz+ZOfs; Z[1]=VtxList[P.P1].vz+ZOfs; Z[2]=VtxList[P.P2].vz+ZOfs; Z[3]=VtxList[P.P3].vz+ZOfs; for (int p=0; p<PntCount; p++) { OtOfs+=Z[p]*Z[p]; } OtOfs=sqrt(OtOfs/PntCount); OtOfs/=8; OtOfs+=P.OTOfs; if (OtOfs>OTMax) OtOfs=OTMax; if (OtOfs<OTMin) OtOfs=OTMin; P.OTOfs=OtOfs; } } //*************************************************************************** void CMkLevel::SetUpTileUV(sElem2d &Out, sTexOutInfo &Info) { int W = Info.w-1; int H = Info.h-1; float Inx0, Iny0; u8 Outx0, Outy0; // Allow for upside textures now :oP Inx0=0; Iny0=1-0; if (Info.Rotated) { GObject::Error(ERR_FATAL,"Rotated Texure, cant cope!\n"); } Outx0 = Info.u + round(Inx0 * W); Outy0 = (Info.v + H) - round(Iny0 * H); Out.u0=Outx0; Out.v0=Outy0; Out.TPage=Info.Tpage; Out.Clut=Info.Clut; } //*************************************************************************** //*************************************************************************** //*************************************************************************** void CMkLevel::ExpTri2Face(sExpTri &ThisTri,CFace &F,bool ImportTex) { if (ImportTex) { F.TexName=InTexNameList[ThisTri.TexID]; F.Mat=-1; } else { F.Mat=ThisTri.TexID; } for (int p=0; p<3; p++) { F.vtx[p]=ThisTri.vtx[p]; F.vtx[p].y=F.vtx[p].y; F.uvs[p].u=ThisTri.uv[p][0]; F.uvs[p].v=ThisTri.uv[p][1]; } } //*************************************************************************** CMkLevelLayer *CMkLevel::FindLayer(int Type,int SubType) { int ListSize=LayerList.size(); for (int i=0; i<ListSize; i++) { if (LayerList[i]->IsType(Type,SubType)) return(LayerList[i]); } return(0); } //*************************************************************************** int CMkLevel::Create3dTile(int Tile,int Flags) { sExpTile &SrcTile=InTileList[Tile]; int ElemID; if (SrcTile.TriCount) { ElemID=Create3dElem(SrcTile.TriCount,SrcTile.TriStart,LocalGeom,true,0); } else { ElemID=Create2dElem(Tile,LocalGeom); } return(ElemID); } //*************************************************************************** int CMkLevel::Create3dElem(int TriCount,int TriStart,bool Local,bool IsTile,int OtOfs) { CFace F; int i,ListSize; CList<sExpTri> SortList; CList<float> ZPosList; int ElemID=OutElem3d.size(); OutElem3d.resize(ElemID+1); sOutElem3d &ThisElem=OutElem3d[ElemID]; CFaceStore &FaceList=ThisElem.FaceStore; FaceList.SetTexGrab(TexGrab); ThisElem.LocalGeom=Local; for (i=0; i<TriCount; i++) { int ListPos; sExpTri &ThisTri=InTriList[TriStart+i]; float ThisZPos; ThisZPos=ThisTri.vtx[0].z; if (ThisZPos<ThisTri.vtx[1].z) ThisZPos=ThisTri.vtx[1].z; if (ThisZPos<ThisTri.vtx[2].z) ThisZPos=ThisTri.vtx[2].z; ListSize=SortList.size(); for (ListPos=0; ListPos<ListSize; ListPos++) { if (ZPosList[ListPos]>ThisZPos) break; } SortList.insert(ListPos,ThisTri); ZPosList.insert(ListPos,ThisZPos); } // Add sorted list to main list for (i=0; i<TriCount; i++) { sExpTri &ThisTri=SortList[i]; CFace F; F.TexName=InTexNameList[ThisTri.TexID]; F.Mat=-1; for (int p=0; p<3; p++) { // F.vtx[p]=ThisTri.vtx[p]; F.vtx[p].x=+ThisTri.vtx[p].x; F.vtx[p].y=-ThisTri.vtx[p].y; F.vtx[p].z=+ThisTri.vtx[p].z; if (IsTile) { F.vtx[p].y+=0.5f; } F.uvs[p].u=ThisTri.uv[p][0]; F.uvs[p].v=ThisTri.uv[p][1]; } F.OtOfs=OtOfs; FaceList.SetTPageFlag(F,ThisTri.Flags); FaceList.AddFace(F,true); } if (IsTile) ThisElem.Model=false; else ThisElem.Model=true; return(ElemID); } //*************************************************************************** int CMkLevel::Create2dElem(int Tile,bool Local) { CFace F; int i; int TexID=Create2dTile(Tile,0,PSX_TILE3D_HEIGHT); int ElemID=OutElem3d.size(); OutElem3d.resize(ElemID+1); sOutElem3d &ThisElem=OutElem3d[ElemID]; CFaceStore &FaceList=ThisElem.FaceStore; FaceList.SetTexGrab(TexGrab); ThisElem.LocalGeom=Local; for (i=0; i<2; i++) { sExpTri &ThisTri=FlatFace[i]; CFace F; F.Mat=TexID; for (int p=0; p<3; p++) { // F.vtx[p]=ThisTri.vtx[p]; F.vtx[p].x=+ThisTri.vtx[p].x; F.vtx[p].y=-ThisTri.vtx[p].y; F.vtx[p].z=+ThisTri.vtx[p].z; F.vtx[p].y+=0.5f; // Adjust for tile offset (2dElems Always Tile) F.uvs[p].u=ThisTri.uv[p][0]; F.uvs[p].v=ThisTri.uv[p][1]; } F.OtOfs=0; FaceList.SetTPageFlag(F,0); FaceList.AddFace(F,true); } return(ElemID); } //*************************************************************************** int CMkLevel::Create2dTile(int Tile,int Flags,int Height) { sExpTile &SrcTile=InTileList[Tile]; sMkLevelTex InTex; int Idx; InTex.Tile=Tile; InTex.Flags=Flags; InTex.Height=Height; Idx=Tex2dList.Find(InTex); if (Idx!=-1) { return(Tex2dList[Idx].TexID); } // Must be new, add it InTex.TexID=BuildTileTex(SrcTile,Flags,InTex.Height); Tex2dList.push_back(InTex); return(InTex.TexID); } //*************************************************************************** int CMkLevel::BuildTileTex(sExpTile &SrcTile,int Flags,int Height) { Frame &InFrame=BmpList[SrcTile.Set]; Frame ThisFrame; Rect ThisRect; GString Name=GFName(InSetNameList[SrcTile.Set]).File(); GString TexName; int BmpW=InFrame.GetWidth(); int BmpH=InFrame.GetHeight(); int TexID; if (SrcTile.XOfs*16>BmpW) { printf("AARGH!!! %s(%i) wants X=%i,tile is only %i Wide\n",Name,SrcTile.Set,SrcTile.XOfs*16,BmpW); SrcTile.XOfs=0; } if (SrcTile.YOfs*16>BmpH) { printf("AARGH!!! %s(%i) wants Y=%i,tile is only %i High\n",Name,SrcTile.Set,SrcTile.YOfs*16,BmpH); SrcTile.YOfs=0; } MakeTexName(SrcTile,Flags,TexName); ThisRect.X=SrcTile.XOfs*16; ThisRect.Y=SrcTile.YOfs*16; ThisRect.W=16; ThisRect.H=16; ThisFrame.Grab(InFrame,ThisRect); if (Flags& PC_TILE_FLAG_MIRROR_X) ThisFrame.FlipX(); if (Flags & PC_TILE_FLAG_MIRROR_Y) ThisFrame.FlipY(); if (Height!=16) { ThisFrame.Resize(16,Height); } TexID=TexGrab.AddMemFrame(TexName,ThisFrame); #ifdef _DEBUG if (0) { if (!ThisFrame.IsBlank()) { char DbgName[256]; sprintf(DbgName,"/x/%s.lbm",TexName); ThisFrame.SaveLbm(DbgName); } } #endif return(TexID); } //*************************************************************************** void CMkLevel::MakeTexName(sExpTile &SrcTile,int Flags,GString &OutStr) { char NewName[256]; GString Name=GFName(InSetNameList[SrcTile.Set]).File(); sprintf(NewName,"%s_%02d_%02d_%01d_",Name,SrcTile.XOfs,SrcTile.YOfs,Flags&PC_TILE_FLAG_MIRROR_XY); OutStr=NewName; } //*************************************************************************** //*** Write ***************************************************************** //*************************************************************************** void CMkLevel::Write() { GString OutFilename=OutName+".Lvl"; File=fopen(OutFilename,"wb"); fwrite(&LevelHdr,1,sizeof(sLevelHdr),File); WriteLevel(); WriteElemBanks(); // rewrite header fseek(File,0,SEEK_SET); fwrite(&LevelHdr,1,sizeof(sLevelHdr),File); fclose(File); // Write Info header File WriteIncFile(); // Write Sizes ReportLayers(); } //*************************************************************************** void CMkLevel::WriteElemBanks() { int i,ListSize; // 2d Elem LevelHdr.ElemBank2d=(sElem2d*)ftell(File); ListSize=OutElem2d.size(); printf("%i 2d Elems\t(%i Bytes)\n",ListSize,ListSize*sizeof(sElem2d)); for (i=0; i<ListSize; i++) { sElem2d &OutElem=OutElem2d[i]; fwrite(&OutElem,1,sizeof(sElem2d),File); } // 3d Elem LevelHdr.ElemBank3d=(sElem3d*)ftell(File); ListSize=OutElem3d.size(); printf("%i 3d Elems\t(%i Bytes)\n",ListSize,ListSize*sizeof(sElem3d)); for (i=0; i<ListSize; i++) { sElem3d &OutElem=OutElem3d[i].Elem3d; fwrite(&OutElem,1,sizeof(sElem3d),File); } // TriList LevelHdr.TriList=(sTri*)WriteTriList(); // QuadList LevelHdr.QuadList=(sQuad*)WriteQuadList(); // VtxList LevelHdr.VtxList=(sVtx*)WriteVtxList(); // VtxIdxList LevelHdr.VtxIdxList=(u16*)ftell(File); ListSize=OutLocalVtxIdxList.size(); for (i=0; i<ListSize; i++) { u16 &ThisIdx=OutLocalVtxIdxList[i]; fwrite(&ThisIdx,1,sizeof(u16),File); } } //*************************************************************************** int CMkLevel::WriteTriList() { int ThisPos=ftell(File); int i,ListSize=OutTriList.size(); for (i=0;i<ListSize;i++) { sTri &T=OutTriList[i]; fwrite(&T,1,sizeof(sTri),File); } printf("%i Tris\t(%i Bytes)\n",ListSize,ListSize*sizeof(sTri)); return(ThisPos); } //*************************************************************************** int CMkLevel::WriteQuadList() { int ThisPos=ftell(File); int i,ListSize=OutQuadList.size(); for (i=0;i<ListSize;i++) { sQuad &Q=OutQuadList[i]; fwrite(&Q,1,sizeof(sQuad),File); } printf("%i Quads\t(%i Bytes)\n",ListSize,ListSize*sizeof(sQuad)); return(ThisPos); } //*************************************************************************** int CMkLevel::WriteVtxList() { int i,ListSize=OutVtxList.size(); int Pos=ftell(File); sVtx Min={+100,+100,+100}; sVtx Max={-100,-100,-100}; for (i=0; i<ListSize; i++) { sVtx const &In=OutVtxList[i]; sVtx Out; Out.vx=+In.vx; Out.vy=+In.vy; Out.vz=+In.vz; Min.vx=__min(Min.vx,Out.vx); Min.vy=__min(Min.vy,Out.vy); Min.vz=__min(Min.vz,Out.vz); Max.vx=__max(Max.vx,Out.vx); Max.vy=__max(Max.vy,Out.vy); Max.vz=__max(Max.vz,Out.vz); fwrite(&Out,1,sizeof(sVtx),File); } printf("%i Vtx\t(%i Bytes)\n",ListSize,ListSize*sizeof(sVtx)); printf("MinX: %i\tMaxX: %i\n",Min.vx,Max.vx); printf("MinY: %i\tMaxY: %i\n",Min.vy,Max.vy); printf("MinZ: %i\tMaxZ: %i\n",Min.vz,Max.vz); // printf("Min %i %i %i\n",Min.vx,Min.vy,Min.vz); // printf("Max %i %i %i\n",Max.vx,Max.vy,Max.vz); return(Pos); } //*************************************************************************** //*** Write ***************************************************************** //*************************************************************************** void CMkLevel::WriteLevel() { WriteLayers(); } //*************************************************************************** void CMkLevel::WriteLayers() { // Back (Shade) LevelHdr.BackLayer=WriteLayer(LAYER_TYPE_SHADE,LAYER_SUBTYPE_BACK); // Mid LevelHdr.MidLayer=WriteLayer(LAYER_TYPE_TILE,LAYER_SUBTYPE_MID); // Action LevelHdr.ActionLayer=WriteLayer(LAYER_TYPE_TILE,LAYER_SUBTYPE_ACTION); // Collision LevelHdr.CollisionLayer=WriteLayer(LAYER_TYPE_COLLISION,LAYER_SUBTYPE_NONE); // Things int ThingStart=ftell(File); LevelHdr.ActorList=WriteThings(LAYER_TYPE_ACTOR); LevelHdr.ItemList=WriteThings(LAYER_TYPE_ITEM); LevelHdr.PlatformList=WriteThings(LAYER_TYPE_PLATFORM); LevelHdr.TriggerList=WriteThings(LAYER_TYPE_TRIGGER); LevelHdr.FXList=WriteThings(LAYER_TYPE_FX); LevelHdr.HazardList=WriteThings(LAYER_TYPE_HAZARD); LevelHdr.ModelList=(sModel*)WriteModelList(); printf("Things =\t(%i Bytes)\n",ftell(File)-ThingStart); } //*************************************************************************** int CMkLevel::WriteLayer(int Type,int SubType,bool Warn) { CMkLevelLayer *ThisLayer=FindLayer(Type,SubType); int Ofs; char *LayerName=GetLayerName(Type,SubType); if (!ThisLayer) { if (Warn) GObject::Error(ERR_WARNING,"No %s Layer Found in %s!!\n",LayerName,LevelName); return(0); } Ofs=ThisLayer->Write(this,File,LayerName); PadFile(File); return(Ofs); } //*************************************************************************** int CMkLevel::WriteThings(int Type,bool Warn) { CMkLevelLayer *ThisLayer=FindLayer(Type,LAYER_SUBTYPE_NONE); int Ofs; char *LayerName=GetLayerName(Type,LAYER_SUBTYPE_NONE); if (!ThisLayer) { GFName Name=InFilename; if (Warn) GObject::Error(ERR_WARNING,"No %s Layer Found in %s!!\n",LayerName,Name.File()); return(0); } Ofs=ThisLayer->Write(this,File,LayerName); // printf("%s %i\n",LayerName,Ofs); PadFile(File); return(Ofs); } //*************************************************************************** int CMkLevel::WriteModelList() { int i,ListSize=ModelList.size(); int Ofs=ftell(File); for (i=0; i<ListSize; i++) { sModel Out; sMkLevelModel &ThisModel=ModelList[i]; sOutElem3d &ThisElem=OutElem3d[ThisModel.ElemID]; sBBox &ElemBBox=ThisElem.FaceStore.GetBBox(); Out.ElemID=ThisModel.ElemID; Out.BBox=ElemBBox; if (ThisModel.TriCount==0) printf("Writing Model E:%i - %s - Dummy --\n",Out.ElemID,ThisModel.Name); else printf("Writing Model E:%i - %s - T:%i Q:%i BBox:%i,%i->%i,%i\n",Out.ElemID,ThisModel.Name,ThisElem.Elem3d.TriCount,ThisElem.Elem3d.QuadCount,Out.BBox.XMin,Out.BBox.YMin,Out.BBox.XMax,Out.BBox.YMax); fwrite(&Out,1,sizeof(sModel),File); } return(Ofs); } //*************************************************************************** //*** Inf File ************************************************************** //*************************************************************************** void CMkLevel::AddInfItem(const char *Name,int Val) { sInfItem Item; GString ReplaceBadFileChars(GString s); // Dodgy extern from TexGrab Lib! Item.Name=ReplaceBadFileChars(Name); Item.Name.Upper(); Item.Val=Val; InfList.Add(Item); } //*************************************************************************** void CMkLevel::WriteIncFile() { GString DefStr; DefStr=LevelFullName+"_INF"; File=fopen(OutIncName,"wt"); fprintf(File,"// %s Info Header\n",LevelFullName); fprintf(File,"\n"); fprintf(File,"#ifndef\t__%s_INF_HEADER__\n",LevelFullName); fprintf(File,"#define\t__%s_INF_HEADER__\n",LevelFullName); fprintf(File,"\n"); fprintf(File,"\n"); fprintf(File,"enum\t%s\n",DefStr); fprintf(File,"{\n"); int ListSize=InfList.size(); for (int i=0; i<ListSize; i++) { sInfItem &ThisItem=InfList[i]; fprintf(File,"\t%s_%s\t\t=%i,\n",DefStr,ThisItem.Name,ThisItem.Val); } fprintf(File,"};\n"); fprintf(File,"\n"); fprintf(File,"#endif\n"); fclose(File); } //*************************************************************************** //*************************************************************************** //*************************************************************************** void CMkLevel::ReportLayers() { int i,ListSize=LayerList.size(); for (i=0; i<ListSize; i++) { CMkLevelLayer *ThisLayer=LayerList[i]; char *LayerName=GetLayerName(ThisLayer->GetType(),ThisLayer->GetSubType()); printf("Layer %s= %i bytes\n",LayerName,ThisLayer->GetSize()); } } //*************************************************************************** char *CMkLevel::GetLayerName(int Type,int SubType) { for (int i=0; i<LayerNameTableSize; i++) { if (LayerNameTable[i].Type==Type && LayerNameTable[i].SubType==SubType) return(LayerNameTable[i].Name); } return(0); }