1126 lines
27 KiB
C++
1126 lines
27 KiB
C++
/*********************/
|
|
/*** Elem Stuph ***/
|
|
/*********************/
|
|
|
|
#include "stdafx.h"
|
|
#include <Vector3.h>
|
|
#include <gl\gl.h>
|
|
#include <gl\glu.h>
|
|
#include "GLEnabledView.h"
|
|
#include <Vector>
|
|
#include <GFName.hpp>
|
|
|
|
#include "Core.h"
|
|
#include "TexCache.h"
|
|
#include "Elem.h"
|
|
#include "GinTex.h"
|
|
#include "utils.h"
|
|
|
|
#include "MapEdit.h"
|
|
#include "MapEditDoc.h"
|
|
#include "MapEditView.h"
|
|
#include "MainFrm.h"
|
|
|
|
#include "GUITileBank.h"
|
|
|
|
|
|
const Vector3 DefOfs(+0.5f,0,+4.0f);
|
|
int CElem::BlankID=-1;
|
|
int CElem::InvalidID=-1;
|
|
bool CElem::DefTexFlag=false;
|
|
|
|
/*****************************************************************************/
|
|
// All Elems MUST run from 0,0 ->
|
|
|
|
/*****************************************************************************/
|
|
const float ElemBrowserGap=0.2f;
|
|
const float ElemBrowserX0=0-ElemBrowserGap/2;
|
|
const float ElemBrowserX1=1+ElemBrowserGap/2;
|
|
const float ElemBrowserY0=0-ElemBrowserGap/2;
|
|
const float ElemBrowserY1=1+ElemBrowserGap/2;
|
|
|
|
/*****************************************************************************/
|
|
const float XFlipMtx[]=
|
|
{
|
|
-1, 0, 0, 0,
|
|
0, 1, 0, 0,
|
|
0, 0, 1, 0,
|
|
0, 0, 0, 1,
|
|
};
|
|
|
|
const float YFlipMtx[]=
|
|
{
|
|
1, 0, 0, 0,
|
|
0,-1, 0, 0,
|
|
0, 0, 1, 0,
|
|
0, 0, 0, 1,
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
CElem::CElem(int Width,int Height)
|
|
{
|
|
ElemWidth=Width;
|
|
ElemHeight=Height;
|
|
UnitWidth=ElemWidth/UnitSize;
|
|
UnitHeight=ElemHeight/UnitSize;
|
|
ElemID=-1;
|
|
int AW=AlignSize(ElemWidth);
|
|
int AH=AlignSize(ElemHeight);
|
|
ElemRGB=0;
|
|
ElemRGB=(u8*)MemAlloc(AW*AH*3);
|
|
memset(ElemRGB,0,AW*AH*3);
|
|
Type=ElemType2d;
|
|
TexXOfs=0;
|
|
TexYOfs=0;
|
|
BlankFlag=true;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
// 3d Elem (From Gin File)
|
|
CElem::CElem(CCore *Core,const char *Filename,CScene &ThisScene,int Node)
|
|
{
|
|
CNode &ThisNode=ThisScene.GetNode(Node);
|
|
CTexCache &TexCache=Core->GetTexCache();
|
|
GFName Path=Filename;
|
|
|
|
SetPath=Path.Drive();
|
|
SetPath+=Path.Dir();
|
|
SetPath.Append('\\');
|
|
|
|
Type=ElemType3d;
|
|
TexXOfs=-1;
|
|
TexYOfs=-1;
|
|
ElemRGB=0;
|
|
Ofs.Zero();
|
|
Build3dElem(TexCache,ThisScene,Node);
|
|
Calc3dSize();
|
|
Build3dDrawList(TexCache,DrawList[ElemType3d]);
|
|
Ofs.Zero();
|
|
Create2dTexture(TexCache,Path.File(),Node);
|
|
Build2dDrawList(TexCache,DrawList[ElemType2d]);
|
|
BlankFlag=false;
|
|
// if (!ValidFlag) SetInvalid();
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
// 2d Elem (From Bmp File)
|
|
// 0,0 1,0 1,1 0,1
|
|
CElem::CElem(CCore *Core,const char *Filename,int TexID,int XOfs,int YOfs,int Width,int Height,int CentreMode)
|
|
{
|
|
CTexCache &TexCache=Core->GetTexCache();
|
|
GFName Path=Filename;
|
|
|
|
ElemWidth=Width;
|
|
ElemHeight=Height;
|
|
UnitWidth=ElemWidth/UnitSize;
|
|
UnitHeight=ElemHeight/UnitSize;
|
|
ElemRGB=0;
|
|
|
|
Type=ElemType2d;
|
|
TexXOfs=XOfs;
|
|
TexYOfs=YOfs;
|
|
Ofs.Zero();
|
|
|
|
if (CentreMode & CentreModeL)
|
|
{
|
|
// Nothing to do, already there
|
|
}
|
|
if (CentreMode & CentreModeR)
|
|
{
|
|
Ofs.x-=UnitWidth;
|
|
}
|
|
|
|
if (CentreMode & CentreModeT)
|
|
{
|
|
Ofs.y-=UnitHeight;
|
|
}
|
|
if (CentreMode & CentreModeB)
|
|
{
|
|
// Nothing to do, already there
|
|
}
|
|
|
|
if (CentreMode & CentreModeLR)
|
|
{
|
|
Ofs.x-=(UnitWidth-1.0f)/2;
|
|
}
|
|
if (CentreMode & CentreModeTB)
|
|
{
|
|
Ofs.y-=(UnitHeight-1.0f)/2;
|
|
}
|
|
|
|
Build2dElem(Core,Path.File(),TexID);
|
|
Build3dDrawList(TexCache,DrawList[ElemType3d]);
|
|
Create2dTexture(TexCache,Path.File(),TexID);
|
|
Build2dDrawList(TexCache,DrawList[ElemType2d]);
|
|
BlankFlag=false;
|
|
if (!ValidFlag) SetInvalid();
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElem::CleanUp()
|
|
{
|
|
if (ElemRGB) MemFree(ElemRGB);
|
|
ElemRGB=0;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElem::SetBlank()
|
|
{
|
|
for (int i=0; i<ElemTypeMax; i++) DrawList[i]=BlankID;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElem::SetInvalid()
|
|
{
|
|
Purge(); // Clear whatever is already there
|
|
for (int i=0; i<ElemTypeMax; i++) DrawList[i]=InvalidID;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElem::Build2dElem(CCore *Core,const char *Filename,int TexID)
|
|
{
|
|
float X0=0;
|
|
float X1=+UnitWidth;
|
|
float Y0=0;
|
|
float Y1=+UnitHeight;
|
|
|
|
Vector3 P0(X0,Y0,0);
|
|
Vector3 P1(X1,Y0,0);
|
|
Vector3 P2(X0,Y1,0);
|
|
Vector3 P3(X1,Y1,0);
|
|
|
|
int ListSize=TriList.size();
|
|
TriList.resize(ListSize+2);
|
|
sTriFace &Tri0=TriList[ListSize+0];
|
|
sTriFace &Tri1=TriList[ListSize+1];
|
|
|
|
CTexCache &TexCache=Core->GetTexCache();
|
|
sTex &ThisTex=TexCache.GetTex(TexID);
|
|
|
|
int CountW=ThisTex.OldW/ElemWidth;
|
|
int CountH=ThisTex.OldH/ElemHeight;
|
|
float dU=ThisTex.ScaleU/(float)CountW;
|
|
float dV=ThisTex.ScaleV/(float)CountH;
|
|
|
|
dU=(1.0f/CountW);
|
|
dV=(1.0f/CountH);
|
|
|
|
// dU=ThisTex.ScaleU;
|
|
// dV=ThisTex.ScaleV;
|
|
|
|
float u0=(TexXOfs*dU);
|
|
float u1=u0+dU;
|
|
|
|
float v1=1.0-(TexYOfs*dV);
|
|
float v0=v1-dV;
|
|
|
|
Tri0.Mat=TexID;
|
|
|
|
Tri0.vtx[0]=P0;
|
|
Tri0.vtx[1]=P1;
|
|
Tri0.vtx[2]=P2;
|
|
Tri0.uvs[0].u=u0; Tri0.uvs[0].v=v0;
|
|
Tri0.uvs[1].u=u1; Tri0.uvs[1].v=v0;
|
|
Tri0.uvs[2].u=u0; Tri0.uvs[2].v=v1;
|
|
|
|
Tri1.Mat=TexID;
|
|
Tri1.vtx[0]=P1;
|
|
Tri1.vtx[1]=P2;
|
|
Tri1.vtx[2]=P3;
|
|
Tri1.uvs[0].u=u1; Tri1.uvs[0].v=v0;
|
|
Tri1.uvs[1].u=u0; Tri1.uvs[1].v=v1;
|
|
Tri1.uvs[2].u=u1; Tri1.uvs[2].v=v1;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElem::Build3dElem(CTexCache &TexCache,CScene &ThisScene,int Node)
|
|
{
|
|
CNode &ThisNode=ThisScene.GetNode(Node);
|
|
CNode &ParentNode=ThisScene.GetNode(ThisNode.ParentIdx);
|
|
int ChildCount=ThisNode.GetPruneChildCount();
|
|
std::vector<sGinTri> const &NodeTriList=ThisNode.GetTris();
|
|
std::vector<Vector3>const &NodeVtxList=ThisNode.GetPts();
|
|
std::vector<sUVTri> const &NodeUVList=ThisNode.GetUVTris();
|
|
std::vector<int> const &NodeTriMat=ThisNode.GetTriMaterial();
|
|
|
|
std::vector<GString> const &SceneTexList=ThisScene.GetTexList();
|
|
std::vector<int> const &SceneUsedMatList=ThisScene.GetUsedMaterialIdx();
|
|
std::vector<Material> const &SceneMatList=ThisScene.GetMaterials();
|
|
int TexCount=SceneTexList.size();
|
|
|
|
int TriCount=NodeTriList.size();
|
|
int ListSize=TriList.size();
|
|
|
|
TriList.resize(ListSize+TriCount);
|
|
for (int T=0; T<TriCount; T++)
|
|
{
|
|
sGinTri const &ThisTri=NodeTriList[T];
|
|
sUVTri const &ThisUV=NodeUVList[T];
|
|
sTriFace &Tri=TriList[ListSize+T];
|
|
int ThisMat=NodeTriMat[T];
|
|
int TexID,TexFlags;
|
|
|
|
|
|
// Sort Textures - Only add the ones that are used :o)
|
|
TexID=SceneUsedMatList[ThisMat];
|
|
if (TexID<0 || TexID>=TexCount)
|
|
{
|
|
CString mexstr;
|
|
mexstr.Format("Invalid TexId\n Wanted %i only have %i Id's for %s\nThis is gonna hurt!\n Dont ask me about this error, ask Kev.\n This MUST be fixed.",TexID,TexCount-1,ThisNode.Name);
|
|
AfxMessageBox(mexstr,MB_OK | MB_ICONEXCLAMATION);
|
|
TexID=0;
|
|
}
|
|
// else
|
|
{
|
|
TexFlags=SceneMatList[TexID].Flags;
|
|
GString ThisName;
|
|
GString TexName=SceneTexList[TexID];
|
|
|
|
ThisName=SetPath+TexName;
|
|
// TRACE2("%i !%s!\n",TexID,ThisName);
|
|
TexID=TexCache.ProcessTexture(ThisName);
|
|
}
|
|
// Sort Rest of Tri info
|
|
Matrix4x4 TransMtx;
|
|
TransMtx.Identity();
|
|
|
|
if (ParentNode.GetTris().size() || !ThisNode.ParentIdx)
|
|
{
|
|
TransMtx=ThisNode.Mtx;
|
|
TransMtx.Invert();
|
|
}
|
|
|
|
for (int p=0; p<3; p++)
|
|
{
|
|
Tri.vtx[p]=TransMtx*NodeVtxList[ThisTri.p[p]];
|
|
Tri.uvs[p].u=ThisUV.p[p].u;
|
|
Tri.uvs[p].v=ThisUV.p[p].v;
|
|
Tri.Mat=TexID;
|
|
Tri.Flags=TexFlags;
|
|
}
|
|
}
|
|
for (int Child=0; Child<ChildCount; Child++) Build3dElem(TexCache,ThisScene,ThisNode.PruneChildList[Child]);
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElem::Calc3dSize()
|
|
{
|
|
int i,ListSize=TriList.size();
|
|
Vector3 Min(+32000,+32000,+32000);
|
|
Vector3 Max(-32000,-32000,-32000);
|
|
Vector3 Mid;
|
|
|
|
for (i=0; i<ListSize; i++)
|
|
{
|
|
sTriFace &Tri=TriList[i];
|
|
for (int p=0; p<3; p++)
|
|
{
|
|
if (Min.x>Tri.vtx[p].x) Min.x=Tri.vtx[p].x;
|
|
if (Min.y>Tri.vtx[p].y) Min.y=Tri.vtx[p].y;
|
|
if (Min.z>Tri.vtx[p].z) Min.z=Tri.vtx[p].z;
|
|
if (Max.x<Tri.vtx[p].x) Max.x=Tri.vtx[p].x;
|
|
if (Max.y<Tri.vtx[p].y) Max.y=Tri.vtx[p].y;
|
|
if (Max.z<Tri.vtx[p].z) Max.z=Tri.vtx[p].z;
|
|
}
|
|
}
|
|
|
|
UnitWidth=round(Max.x-Min.x);
|
|
UnitHeight=round(Max.y-Min.y);
|
|
if (UnitWidth<1) UnitWidth=1;
|
|
if (UnitHeight<1) UnitHeight=1;
|
|
ElemWidth=UnitWidth*UnitSize;
|
|
ElemHeight=UnitHeight*UnitSize;
|
|
Min.z=0;
|
|
|
|
Ofs=DefOfs;
|
|
// Ofs.x=+0.5f; Ofs.y=0; Ofs.z=+4.0f;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElem::Build2dDrawList(CTexCache &TexCache,GLint &List)
|
|
{
|
|
float X0=Ofs.x;
|
|
float X1=Ofs.x+UnitWidth;
|
|
float Y0=Ofs.y;
|
|
float Y1=Ofs.y+UnitHeight;
|
|
float Z=Ofs.z;
|
|
sTex &Tex=TexCache.GetTex(ElemID);
|
|
float u0=0;
|
|
float u1=1.0f;//Tex.ScaleU;
|
|
float v0=0;
|
|
float v1=1.0f;//Tex.ScaleU;
|
|
|
|
List=glGenLists(1);
|
|
glNewList(List,GL_COMPILE);
|
|
|
|
TexID=Tex.TexID;
|
|
glBindTexture(GL_TEXTURE_2D, Tex.TexID);
|
|
glBegin (GL_QUADS);
|
|
glTexCoord2f(u0,v0);
|
|
glVertex3f(X0,Y0,Z);
|
|
|
|
glTexCoord2f(u1,v0);
|
|
glVertex3f(X1,Y0,Z);
|
|
|
|
glTexCoord2f(u1,v1);
|
|
glVertex3f(X1,Y1,Z);
|
|
|
|
glTexCoord2f(u0,v1);
|
|
glVertex3f(X0,Y1,Z);
|
|
glEnd();
|
|
glEndList();
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
// Build OpenGL display lists, sorted by material (luckily by gin!!)
|
|
void CElem::Build3dDrawList(CTexCache &TexCache,GLint &List)
|
|
{
|
|
int TriCount=TriList.size();
|
|
int LastMat=-1,ThisMat;
|
|
float ScaleU,ScaleV;
|
|
|
|
List=glGenLists(1);
|
|
glNewList(List,GL_COMPILE);
|
|
|
|
for (int T=0; T<TriCount; T++)
|
|
{
|
|
sTriFace &ThisTri=TriList[T];
|
|
ThisMat=ThisTri.Mat;
|
|
|
|
if (!T || ThisMat!=LastMat) // First Tri or new material
|
|
{
|
|
if (T) glEnd(); // Not first tri, so end previous mat set
|
|
glBindTexture(GL_TEXTURE_2D, TexCache.GetTexGLId(ThisMat));
|
|
glBegin (GL_TRIANGLES);
|
|
LastMat=ThisMat;
|
|
sTex &Tex=TexCache.GetTex(ThisMat);
|
|
ScaleU=Tex.ScaleU;
|
|
ScaleV=Tex.ScaleV;
|
|
}
|
|
|
|
for (int p=0; p<3; p++)
|
|
{
|
|
Vector3 &ThisVtx=ThisTri.vtx[p];
|
|
float u=ThisTri.uvs[p].u*ScaleU;
|
|
float v=ThisTri.uvs[p].v*ScaleV;
|
|
glTexCoord2f(u,v);
|
|
glVertex3f( (ThisVtx.x+Ofs.x), (ThisVtx.y+Ofs.y), -(ThisVtx.z+Ofs.z)); // Neg Z (cos openGL)
|
|
}
|
|
}
|
|
|
|
glEnd();
|
|
glEndList();
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElem::Render(int Flags,bool Render3d)
|
|
{
|
|
if (BlankFlag)
|
|
{
|
|
glCallList(BlankID);
|
|
return;
|
|
}
|
|
glPushMatrix();
|
|
|
|
if (Flags & PC_TILE_FLAG_MIRROR_X)
|
|
{
|
|
glTranslatef(1,0,0);
|
|
glMultMatrixf(XFlipMtx);
|
|
}
|
|
if (Flags & PC_TILE_FLAG_MIRROR_Y)
|
|
{
|
|
glTranslatef(0,1,0);
|
|
glMultMatrixf(YFlipMtx);
|
|
}
|
|
|
|
int ColFlags=Flags >> PC_TILE_FLAG_COLLISION_SHIFT;
|
|
|
|
if (ColFlags)
|
|
{
|
|
switch (ColFlags)
|
|
{
|
|
case PC_TILE_COLLISION_NORMAL: glColor4f(1.0f,1.0f,1.0f,0.5); break;
|
|
case PC_TILE_COLLISION_DAMAGE: glColor4f(1.0f,0.0f,0.0f,0.5); break;
|
|
case PC_TILE_COLLISION_SLIPPERY: glColor4f(0.0f,1.0f,0.0f,0.5); break;
|
|
case PC_TILE_COLLISION_ELECTRIC: glColor4f(1.0f,0.0f,1.0f,0.5); break;
|
|
case PC_TILE_COLLISION_STICKY: glColor4f(1.0f,1.0f,0.0f,0.5); break;
|
|
case PC_TILE_COLLISION_WATER: glColor4f(0.0f,0.0f,1.0f,0.5); break;
|
|
case PC_TILE_COLLISION_SOLID: glColor4f(0.0f,1.0f,1.0f,0.5); break;
|
|
case PC_TILE_COLLISION_DEATH: glColor4f(0.0f,0.5f,0.5f,0.5); break;
|
|
case PC_TILE_COLLISION_DESTRUCTABLE:glColor4f(0.5f,0.7f,0.6f,0.5); break;
|
|
}
|
|
}
|
|
glEnable(GL_TEXTURE_2D);
|
|
if (Render3d)
|
|
{
|
|
glEnable(GL_DEPTH_TEST);
|
|
glCallList(DrawList[ElemType3d]);
|
|
glDisable(GL_DEPTH_TEST);
|
|
}
|
|
else
|
|
{
|
|
glCallList(DrawList[ElemType2d]);
|
|
}
|
|
glDisable(GL_TEXTURE_2D);
|
|
glPopMatrix();
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElem::Purge()
|
|
{
|
|
for (int i=0; i<ElemTypeMax; i++)
|
|
glDeleteLists(DrawList[i],1);
|
|
CleanUp();
|
|
// TriList.clear();
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
// Only created for the tile browser, should NEVER appear in main view
|
|
void CElem::CreateDefaultTileGfx()
|
|
{
|
|
float X0=0;
|
|
float X1=1.0f;
|
|
float Y0=0;
|
|
float Y1=1.0f;
|
|
DefTexFlag=true;
|
|
// Blank
|
|
if (BlankID==-1)
|
|
{
|
|
BlankID=glGenLists(1);
|
|
glNewList(BlankID,GL_COMPILE);
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
glBegin(GL_LINES);
|
|
glColor4f(1,1,1,1);
|
|
|
|
glVertex3f( X0,Y0,0);
|
|
glVertex3f( X1,Y0,0);
|
|
|
|
glVertex3f( X0,Y1,0);
|
|
glVertex3f( X1,Y1,0);
|
|
|
|
glVertex3f( X0,Y0,0);
|
|
glVertex3f( X0,Y1,0);
|
|
|
|
glVertex3f( X1,Y0,0);
|
|
glVertex3f( X1,Y1,0);
|
|
glEnd();
|
|
glEndList();
|
|
}
|
|
// Invalid
|
|
if (InvalidID==-1)
|
|
{
|
|
InvalidID=glGenLists(1);
|
|
glNewList(InvalidID,GL_COMPILE);
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
glBegin(GL_LINES);
|
|
glColor4f(1,1,1,1);
|
|
|
|
glVertex3f( X0,Y0,0);
|
|
glVertex3f( X1,Y1,0);
|
|
|
|
glVertex3f( X1,Y0,0);
|
|
glVertex3f( X0,Y1,0);
|
|
glEnd();
|
|
glEndList();
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
void CElem::RenderElem4Texture(sRGBData &RGBData)
|
|
{
|
|
float W=UnitWidth;
|
|
float H=UnitHeight;
|
|
|
|
glClearColor(1,0,1,1 );
|
|
// glClearColor(1,1,1,1 );
|
|
glPushAttrib(GL_VIEWPORT_BIT);
|
|
glViewport(0,0,RGBData.TexW,RGBData.TexH);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
|
|
glLoadIdentity();
|
|
glOrtho(0, W, 0, H, -16.0f, +16.0f);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glTranslatef(-Ofs.x,-Ofs.y,-Ofs.z);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen
|
|
|
|
glColor3f(1,1,1);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glEnable(GL_DEPTH_TEST);
|
|
glCallList(DrawList[ElemType3d]);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
glPopMatrix();
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
glPopAttrib();
|
|
|
|
glReadPixels(0,0,RGBData.TexW,RGBData.TexH,GL_RGB, GL_UNSIGNED_BYTE,RGBData.RGB);
|
|
glClearColor(0,0,0,1 );
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
// ID used to create unique textures within one set :o)
|
|
void CElem::Create2dTexture(CTexCache &TexCache,const char *Filename,int ID)
|
|
{
|
|
sRGBData RGBData;
|
|
char TexName[256];
|
|
|
|
sprintf(TexName,"_2dPc_%s_%03d",Filename,ID);
|
|
int AW=AlignSize(ElemWidth);
|
|
int AH=AlignSize(ElemHeight);
|
|
ElemRGB=(u8*)MemAlloc(AW*AH*3);
|
|
|
|
RGBData.TexW=AlignSize(ElemWidth);
|
|
RGBData.TexH=AlignSize(ElemHeight);
|
|
RGBData.ScaleU=1.0f;
|
|
RGBData.ScaleV=1.0f;
|
|
RGBData.RGB=ElemRGB;
|
|
RenderElem4Texture(RGBData);
|
|
ElemID=TexCache.ProcessTexture(TexName,&RGBData);
|
|
ValidFlag=CheckHasData(RGBData);
|
|
|
|
#ifdef _DEBUG
|
|
if (0)
|
|
{
|
|
char Filename[256];
|
|
sprintf(Filename,"/x/%s.Tga",TexName);
|
|
SaveTGA(Filename,ElemWidth,ElemHeight,ElemRGB);
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
bool CElem::CheckHasData(sRGBData &RGBData)
|
|
{
|
|
u8 *Src=RGBData.RGB;
|
|
int Size=RGBData.TexW*RGBData.TexH;
|
|
|
|
while (Size--)
|
|
{
|
|
u8 R=*Src++;
|
|
u8 G=*Src++;
|
|
u8 B=*Src++;
|
|
if (R!=255 || G!=0 || B!=255) return(true);
|
|
}
|
|
|
|
return(false);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*** Elem Set ****************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
CElemSet::CElemSet(const char *_Filename,int Idx,int Width,int Height,bool CreateBlank,int Centre)
|
|
{
|
|
GFName FName=_Filename;
|
|
|
|
Filename=_Filename;
|
|
Name=FName.File();
|
|
|
|
MaxWidth=Width;
|
|
MaxHeight=Height;
|
|
CentreMode=Centre;
|
|
Loaded=FALSE;
|
|
SetNumber=Idx;
|
|
|
|
if (CreateBlank)
|
|
{
|
|
ElemList.push_back(CElem(MaxWidth,MaxHeight)); // Insert Blank
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
CElemSet::~CElemSet()
|
|
{
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElemSet::CleanUp()
|
|
{
|
|
int ListSize=ElemList.size();
|
|
|
|
for (int i=0; i<ListSize; i++)
|
|
{
|
|
ElemList[i].CleanUp();
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElemSet::Load(CCore *Core)
|
|
{
|
|
GFName FName=Filename;
|
|
GString Ext=FName.Ext();
|
|
Ext.Upper();
|
|
if (!CElem::DefTexFlag) CElem::CreateDefaultTileGfx();
|
|
|
|
if (!ElemList.size())
|
|
{
|
|
// ElemList[0].SetBlank();
|
|
}
|
|
|
|
if (Ext=="GIN")
|
|
Load3d(Core);
|
|
else
|
|
Load2d(Core);
|
|
Loaded=TRUE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElemSet::Load2d(CCore *Core)
|
|
{
|
|
CTexCache &TexCache=Core->GetTexCache();
|
|
int TexID=TexCache.ProcessTexture(Filename);
|
|
sTex &ThisTex=TexCache.GetTex(TexID);
|
|
int Width,Height;
|
|
|
|
if (MaxWidth==-1) MaxWidth=ThisTex.OldW;
|
|
if (MaxHeight==-1) MaxHeight=ThisTex.OldH;
|
|
|
|
Width=ThisTex.OldW/MaxWidth;
|
|
Height=ThisTex.OldH/MaxHeight;
|
|
|
|
for (int Y=0; Y<Height; Y++)
|
|
{
|
|
for (int X=0; X<Width; X++)
|
|
{
|
|
ElemList.push_back(CElem(Core,Filename,TexID,X,Y,MaxWidth,MaxHeight,CentreMode));
|
|
}
|
|
}
|
|
ElemBrowserWidth=Width;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElemSet::Load3d(CCore *Core)
|
|
{
|
|
CScene Scene;
|
|
|
|
Scene.Load(Filename);
|
|
|
|
CNode &ThisNode=Scene.GetSceneNode(0);
|
|
int ChildCount=ThisNode.GetPruneChildCount();
|
|
|
|
for (int Child=0; Child<ChildCount; Child++)
|
|
{
|
|
ElemList.push_back(CElem(Core,Filename,Scene,ThisNode.PruneChildList[Child]));
|
|
}
|
|
ElemBrowserWidth=DEF_ELEMBROWSWEWIDTH;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElemSet::Purge()
|
|
{
|
|
int i,ListSize=ElemList.size();
|
|
|
|
for (i=0; i<ListSize; i++)
|
|
{
|
|
if (!ElemList[i].IsBlank())
|
|
{
|
|
ElemList[i].Purge();
|
|
}
|
|
}
|
|
|
|
if (ElemList[0].IsBlank())
|
|
{
|
|
ElemList.erase(1,ListSize);
|
|
}
|
|
else
|
|
{
|
|
ElemList.clear();
|
|
}
|
|
Loaded=FALSE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
CPoint CElemSet::GetElemPos(int ID)
|
|
{
|
|
if (ID==0)
|
|
return(CPoint(-1,-1));
|
|
else
|
|
return(IDToPoint(ID-1,ElemBrowserWidth));
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
bool CElemSet::IsValid(int No)
|
|
{
|
|
int ListSize=ElemList.size();
|
|
if (No>=ListSize) return(false);
|
|
return(ElemList[No].IsValid());
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*** Elem Bank ***************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
CElemBank::CElemBank(int W,int H,bool Blank,int Centre)
|
|
{
|
|
MaxWidth=W;
|
|
MaxHeight=H;
|
|
BlankFlag=Blank;
|
|
CentreMode=Centre;
|
|
|
|
LoadFlag=false;
|
|
CurrentSet=0;
|
|
LayerDef.VisibleFlag=true;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
CElemBank::~CElemBank()
|
|
{
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElemBank::CleanUp()
|
|
{
|
|
int ListSize=SetList.size();
|
|
|
|
for (int i=0; i<ListSize; i++)
|
|
{
|
|
SetList[i].CleanUp();
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElemBank::Load(CFile *File,int Version)
|
|
{
|
|
int ListSize;
|
|
GFName RootPath=File->GetFilePath();
|
|
GString FilePath;
|
|
char FixPath[1024];
|
|
|
|
FilePath=RootPath.Drive();
|
|
FilePath+=RootPath.Dir();
|
|
FilePath.Append('\\');
|
|
FilePath.Upper();
|
|
|
|
if (Version>=5)
|
|
{
|
|
File->Read(&CurrentSet,sizeof(int));
|
|
}
|
|
File->Read(&ListSize,sizeof(int));
|
|
|
|
// New Style rel storage
|
|
for (int i=0;i<ListSize;i++)
|
|
{
|
|
char c=1;
|
|
GString FullName;//=FilePath;
|
|
|
|
while (c)
|
|
{
|
|
File->Read(&c,1);
|
|
FullName.Append(c);
|
|
}
|
|
FullName.Upper();
|
|
GFName::makeabsolute(FilePath,FullName,FixPath);
|
|
FullName=FixPath;
|
|
_fullpath( FixPath, FullName, 1024);
|
|
for (int z=0; z<strlen(FixPath); z++)
|
|
{// Invalidate any long name short cackness
|
|
if (FixPath[z]=='~') FixPath[z]='_';
|
|
}
|
|
FullName=FixPath;
|
|
|
|
CheckFilename(FullName);
|
|
FullName.Upper();
|
|
AddSet(FullName);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElemBank::Save(CFile *File)
|
|
{
|
|
int ListSize=SetList.size();
|
|
GFName RootPath=File->GetFilePath();
|
|
GString SavePath;
|
|
|
|
SavePath=RootPath.Drive();
|
|
SavePath+=RootPath.Dir();
|
|
SavePath.Append('\\');
|
|
|
|
SavePath.Upper();
|
|
|
|
File->Write(&CurrentSet,sizeof(int));
|
|
File->Write(&ListSize,sizeof(int));
|
|
|
|
for (int i=0; i<ListSize; i++)
|
|
{
|
|
char Filename[256+64];
|
|
RootPath.makerelative(SavePath,SetList[i].GetFilename(),Filename);
|
|
File->Write(Filename,strlen(Filename)+1);
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
int CElemBank::AddSet(const char *Filename)
|
|
{
|
|
int ListSize=SetList.size();
|
|
CElemSet NewSet(Filename,ListSize,MaxWidth,MaxHeight,BlankFlag,CentreMode);
|
|
|
|
int Idx=SetList.Add(NewSet);
|
|
if (SetList.size()!=ListSize) LoadFlag=TRUE;
|
|
return(Idx);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElemBank::LoadAllSets(CCore *Core)
|
|
{
|
|
int ListSize=SetList.size();
|
|
|
|
if (!LoadFlag) return;
|
|
|
|
for (int i=0;i<ListSize;i++)
|
|
{
|
|
CElemSet &ThisSet=SetList[i];
|
|
|
|
if (!ThisSet.IsLoaded()) ThisSet.Load(Core);
|
|
}
|
|
LoadFlag=false;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElemBank::LoadNewSet(CCore *Core)
|
|
{
|
|
char BASED_CODE GinFilter[]= "All Tile Files (*.Gin; *.Bmp)|*.gin;*.Bmp|3d Tile Files (*.Gin)|*.Gin|2d Tile Files (*.Bmp)|*.Bmp|All Files (*.*)|*.*||";
|
|
CFileDialog Dlg(TRUE,"Gin",NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,GinFilter);
|
|
|
|
if (Dlg.DoModal()!=IDOK) return;
|
|
|
|
char Filename[256];
|
|
sprintf(Filename,"%s",Dlg.GetPathName());
|
|
AddSet(Filename);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElemBank::ReloadAllSets()
|
|
{
|
|
int ListSize=SetList.size();
|
|
|
|
for (int i=0; i<ListSize; i++)
|
|
{
|
|
SetList[i].Purge();
|
|
}
|
|
|
|
LoadFlag=TRUE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElemBank::DeleteSet(int Set)
|
|
{
|
|
SetList.erase(Set);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
bool CElemBank::IsValid(int Set,int Elem)
|
|
{
|
|
if (Set<0 || Elem<0) return(false);
|
|
if (Elem==0) return(true);
|
|
if (Set>=SetList.size()) return(false);
|
|
// if (Set>SetList.size()) return(false);
|
|
ASSERT(Set<SetList.size());
|
|
return(SetList[Set].IsValid(Elem));
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
CPoint CElemBank::GetElemPos(int ID,int Width)
|
|
{
|
|
if (ID==0)
|
|
return(CPoint(-1,-1));
|
|
else
|
|
return(IDToPoint(ID-1,Width));
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElemBank::RenderElem(int Set,int Elem,int Flags,bool Is3d)
|
|
{
|
|
if (IsValid(Set,Elem))
|
|
{
|
|
SetList[Set].RenderElem(Elem,Flags,Is3d);
|
|
}
|
|
else
|
|
{
|
|
RenderInvalid();
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElemBank::RenderGrid(CCore *Core,Vector3 &CamPos,bool Active)
|
|
{
|
|
if (!GetSetCount()) return;
|
|
CElemSet &ThisSet=SetList[CurrentSet];
|
|
int ListSize=ThisSet.GetCount();
|
|
int BrowserWidth=ThisSet.GetBrowserWidth();
|
|
int TileID=1; // Dont bother with blank, its sorted
|
|
float Scale=CamPos.z/(float)BrowserWidth/2.0;
|
|
|
|
if (!ListSize) return;
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
|
|
while(TileID!=ListSize)
|
|
{
|
|
CPoint Pos=GetElemPos(TileID,BrowserWidth);
|
|
float XPos=(float)Pos.x*(1+ElemBrowserGap);
|
|
float YPos=(float)Pos.y*(1+ElemBrowserGap);
|
|
|
|
glLoadIdentity();
|
|
glScalef(Scale,Scale,Scale);
|
|
glTranslatef(-CamPos.x+XPos,CamPos.y-YPos,0);
|
|
|
|
glBegin(GL_LINES);
|
|
glColor3f(1,1,1);
|
|
|
|
glVertex3f( ElemBrowserX0,ElemBrowserY0,0);
|
|
glVertex3f( ElemBrowserX1,ElemBrowserY0,0);
|
|
|
|
glVertex3f( ElemBrowserX0,ElemBrowserY1,0);
|
|
glVertex3f( ElemBrowserX1,ElemBrowserY1,0);
|
|
|
|
glVertex3f( ElemBrowserX0,ElemBrowserY0,0);
|
|
glVertex3f( ElemBrowserX0,ElemBrowserY1,0);
|
|
|
|
glVertex3f( ElemBrowserX1,ElemBrowserY0,0);
|
|
glVertex3f( ElemBrowserX1,ElemBrowserY1,0);
|
|
|
|
glEnd();
|
|
|
|
TileID++;
|
|
}
|
|
glPopMatrix();
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElemBank::FindCursorPos(CCore *Core,Vector3 &CamPos,CPoint &MousePos)
|
|
{
|
|
if (!GetSetCount()) return;
|
|
CElemSet &ThisSet=SetList[CurrentSet];
|
|
int ListSize=ThisSet.GetCount();
|
|
int BrowserWidth=ThisSet.GetBrowserWidth();
|
|
GLint Viewport[4];
|
|
GLuint SelectBuffer[SELECT_BUFFER_SIZE];
|
|
int HitCount;
|
|
int TileID=0;
|
|
float Scale=CamPos.z/(float)BrowserWidth/2.0;
|
|
|
|
if (!ListSize) return;
|
|
glGetIntegerv(GL_VIEWPORT, Viewport);
|
|
glSelectBuffer (SELECT_BUFFER_SIZE, SelectBuffer );
|
|
glRenderMode (GL_SELECT);
|
|
|
|
glInitNames();
|
|
glPushName(-1);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
gluPickMatrix( MousePos.x ,(Viewport[3]-MousePos.y),5.0,5.0,Viewport);
|
|
Core->GetView()->SetupPersMatrix();
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
|
|
while(TileID!=ListSize)
|
|
{
|
|
CPoint Pos=GetElemPos(TileID,BrowserWidth);
|
|
float XPos=(float)Pos.x*(1+ElemBrowserGap);
|
|
float YPos=(float)Pos.y*(1+ElemBrowserGap);
|
|
|
|
glLoadIdentity();
|
|
glScalef(Scale,Scale,Scale);
|
|
glTranslatef(-CamPos.x+XPos,CamPos.y-YPos,0);
|
|
|
|
glLoadName (TileID);
|
|
glBegin (GL_QUADS);
|
|
BuildGLQuad(ElemBrowserX0,ElemBrowserX1,ElemBrowserY0,ElemBrowserY1,0);
|
|
glEnd();
|
|
TileID++;
|
|
}
|
|
|
|
HitCount= glRenderMode (GL_RENDER);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
|
|
// Process hits
|
|
|
|
GLuint *HitPtr=SelectBuffer;
|
|
|
|
TileID=-2;
|
|
if (HitCount) // Just take 1st
|
|
{
|
|
TileID=HitPtr[3];
|
|
}
|
|
glMatrixMode(GL_MODELVIEW); // <-- Prevent arse GL assert
|
|
|
|
CursorPos=TileID;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*** Gui *********************************************************************/
|
|
/*****************************************************************************/
|
|
void CElemBank::GUIInit(CCore *Core)
|
|
{
|
|
Core->GUIAdd(GUIElemList,IDD_ELEMLIST);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElemBank::GUIKill(CCore *Core)
|
|
{
|
|
Core->GUIRemove(GUIElemList,IDD_ELEMLIST);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElemBank::GUIUpdate(CCore *Core)
|
|
{
|
|
int ListSize=GetSetCount();
|
|
bool IsSubView=Core->IsSubView();
|
|
|
|
if (GUIElemList.m_List)
|
|
{
|
|
GUIElemList.m_List.ResetContent();
|
|
if (ListSize)
|
|
{
|
|
for (int i=0; i<ListSize; i++)
|
|
{
|
|
GUIElemList.m_List.AddString(GetSetName(i));
|
|
}
|
|
GUIElemList.m_List.SetCurSel(CurrentSet);
|
|
}
|
|
else
|
|
{
|
|
IsSubView=FALSE;
|
|
}
|
|
GUIElemList.m_List.EnableWindow(IsSubView);
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
void CElemBank::GUIChanged(CCore *Core)
|
|
{
|
|
}
|
|
|
|
/*****************************************************************************/
|