forked from Mirrors/openclonk
Merged default into mesh
commit
6da0846c87
|
@ -398,6 +398,8 @@ add_library(standard STATIC
|
||||||
standard/src/StdGL.cpp
|
standard/src/StdGL.cpp
|
||||||
standard/src/StdGLCtx.cpp
|
standard/src/StdGLCtx.cpp
|
||||||
standard/src/StdMarkup.cpp
|
standard/src/StdMarkup.cpp
|
||||||
|
standard/src/StdMesh.cpp
|
||||||
|
standard/src/StdMeshMaterial.cpp
|
||||||
standard/src/StdNoGfx.cpp
|
standard/src/StdNoGfx.cpp
|
||||||
standard/src/StdPNG.cpp
|
standard/src/StdPNG.cpp
|
||||||
standard/src/StdRegistry.cpp
|
standard/src/StdRegistry.cpp
|
||||||
|
@ -428,6 +430,8 @@ add_library(standard STATIC
|
||||||
standard/inc/StdFont.h
|
standard/inc/StdFont.h
|
||||||
standard/inc/StdGL.h
|
standard/inc/StdGL.h
|
||||||
standard/inc/StdMarkup.h
|
standard/inc/StdMarkup.h
|
||||||
|
standard/inc/StdMesh.h
|
||||||
|
standard/inc/StdMeshMaterial.h
|
||||||
standard/inc/StdNoGfx.h
|
standard/inc/StdNoGfx.h
|
||||||
standard/inc/StdPNG.h
|
standard/inc/StdPNG.h
|
||||||
standard/inc/StdRandom.h
|
standard/inc/StdRandom.h
|
||||||
|
@ -442,6 +446,12 @@ add_library(standard STATIC
|
||||||
standard/inc/StdWindow.h
|
standard/inc/StdWindow.h
|
||||||
standard/zlib/gzio.c
|
standard/zlib/gzio.c
|
||||||
standard/zlib/zutil.h
|
standard/zlib/zutil.h
|
||||||
|
standard/tinyxml/tinystr.cpp
|
||||||
|
standard/tinyxml/tinyxml.cpp
|
||||||
|
standard/tinyxml/tinyxmlparser.cpp
|
||||||
|
standard/tinyxml/tinyxmlerror.cpp
|
||||||
|
standard/tinyxml/tinyxml.h
|
||||||
|
standard/tinyxml/tinystr.h
|
||||||
)
|
)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
|
|
12
Makefile.am
12
Makefile.am
|
@ -434,6 +434,8 @@ libstandard_a_SOURCES = \
|
||||||
standard/src/StdGL.cpp \
|
standard/src/StdGL.cpp \
|
||||||
standard/src/StdGLCtx.cpp \
|
standard/src/StdGLCtx.cpp \
|
||||||
standard/src/StdMarkup.cpp \
|
standard/src/StdMarkup.cpp \
|
||||||
|
standard/src/StdMesh.cpp \
|
||||||
|
standard/src/StdMeshMaterial.cpp \
|
||||||
standard/src/StdNoGfx.cpp \
|
standard/src/StdNoGfx.cpp \
|
||||||
standard/src/StdPNG.cpp \
|
standard/src/StdPNG.cpp \
|
||||||
standard/src/StdRegistry.cpp \
|
standard/src/StdRegistry.cpp \
|
||||||
|
@ -464,6 +466,8 @@ libstandard_a_SOURCES = \
|
||||||
standard/inc/StdFont.h \
|
standard/inc/StdFont.h \
|
||||||
standard/inc/StdGL.h \
|
standard/inc/StdGL.h \
|
||||||
standard/inc/StdMarkup.h \
|
standard/inc/StdMarkup.h \
|
||||||
|
standard/inc/StdMesh.h \
|
||||||
|
standard/inc/StdMeshMaterial.h \
|
||||||
standard/inc/StdNoGfx.h \
|
standard/inc/StdNoGfx.h \
|
||||||
standard/inc/StdPNG.h \
|
standard/inc/StdPNG.h \
|
||||||
standard/inc/StdRandom.h \
|
standard/inc/StdRandom.h \
|
||||||
|
@ -477,7 +481,13 @@ libstandard_a_SOURCES = \
|
||||||
standard/inc/StdVideo.h \
|
standard/inc/StdVideo.h \
|
||||||
standard/inc/StdWindow.h \
|
standard/inc/StdWindow.h \
|
||||||
standard/zlib/gzio.c \
|
standard/zlib/gzio.c \
|
||||||
standard/zlib/zutil.h
|
standard/zlib/zutil.h \
|
||||||
|
standard/tinyxml/tinystr.cpp \
|
||||||
|
standard/tinyxml/tinyxml.cpp \
|
||||||
|
standard/tinyxml/tinyxmlparser.cpp \
|
||||||
|
standard/tinyxml/tinyxmlerror.cpp \
|
||||||
|
standard/tinyxml/tinyxml.h \
|
||||||
|
standard/tinyxml/tinystr.h
|
||||||
|
|
||||||
if WIN32
|
if WIN32
|
||||||
libstandard_a_SOURCES += standard/src/StdWindow.cpp standard/src/StdJoystick.cpp standard/inc/StdJoystick.h
|
libstandard_a_SOURCES += standard/src/StdWindow.cpp standard/src/StdJoystick.cpp standard/inc/StdJoystick.h
|
||||||
|
|
|
@ -85,6 +85,8 @@
|
||||||
#define C4CFN_IconPNG "Icon.png"
|
#define C4CFN_IconPNG "Icon.png"
|
||||||
#define C4CFN_ScenarioObjects "Objects.txt"
|
#define C4CFN_ScenarioObjects "Objects.txt"
|
||||||
#define C4CFN_ScenarioDesc "Desc%s.rtf"
|
#define C4CFN_ScenarioDesc "Desc%s.rtf"
|
||||||
|
#define C4CFN_DefMaterials "*.material"
|
||||||
|
#define C4CFN_DefMesh "Graphics.mesh.xml"
|
||||||
#define C4CFN_DefGraphics "Graphics.bmp"
|
#define C4CFN_DefGraphics "Graphics.bmp"
|
||||||
#define C4CFN_DefGraphicsPNG "Graphics.png"
|
#define C4CFN_DefGraphicsPNG "Graphics.png"
|
||||||
#define C4CFN_ClrByOwnerPNG "Overlay.png"
|
#define C4CFN_ClrByOwnerPNG "Overlay.png"
|
||||||
|
|
|
@ -44,16 +44,31 @@ class C4DefGraphics
|
||||||
|
|
||||||
C4DefGraphics *GetLast(); // get last graphics in list
|
C4DefGraphics *GetLast(); // get last graphics in list
|
||||||
public:
|
public:
|
||||||
C4Surface *Bitmap, *BitmapClr;
|
enum GraphicsType {
|
||||||
|
TYPE_Bitmap,
|
||||||
|
TYPE_Mesh
|
||||||
|
};
|
||||||
|
|
||||||
|
GraphicsType Type;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
C4Surface *Bitmap, *BitmapClr;
|
||||||
|
};
|
||||||
|
StdMesh *Mesh;
|
||||||
|
};
|
||||||
|
|
||||||
bool fColorBitmapAutoCreated; // if set, the color-by-owner-bitmap has been created automatically by all blue shades of the bitmap
|
bool fColorBitmapAutoCreated; // if set, the color-by-owner-bitmap has been created automatically by all blue shades of the bitmap
|
||||||
|
|
||||||
inline C4Surface *GetBitmap(DWORD dwClr=0) { if (BitmapClr) { BitmapClr->SetClr(dwClr); return BitmapClr; } else return Bitmap; }
|
inline C4Surface *GetBitmap(DWORD dwClr=0) { if(Type != TYPE_Bitmap) return NULL; if (BitmapClr) { BitmapClr->SetClr(dwClr); return BitmapClr; } else return Bitmap; }
|
||||||
|
|
||||||
C4DefGraphics(C4Def *pOwnDef=NULL); // ctor
|
C4DefGraphics(C4Def *pOwnDef=NULL); // ctor
|
||||||
virtual ~C4DefGraphics() { Clear(); }; // dtor
|
virtual ~C4DefGraphics() { Clear(); }; // dtor
|
||||||
|
|
||||||
bool LoadBitmap(C4Group &hGroup, const char *szFilename, const char *szFilenamePNG, const char *szOverlayPNG, bool fColorByOwner); // load specified graphics from group
|
bool LoadBitmap(C4Group &hGroup, const char *szFilename, const char *szFilenamePNG, const char *szOverlayPNG, bool fColorByOwner); // load specified graphics from group
|
||||||
bool LoadBitmaps(C4Group &hGroup, bool fColorByOwner); // load graphics from group
|
bool LoadBitmaps(C4Group &hGroup, bool fColorByOwner); // load graphics from group
|
||||||
|
bool LoadMesh(C4Group &hGroup, StdMeshSkeletonLoader& loader);
|
||||||
|
bool Load(C4Group &hGroup, bool fColorByOwner); // load graphics from group
|
||||||
C4DefGraphics *Get(const char *szGrpName); // get graphics by name
|
C4DefGraphics *Get(const char *szGrpName); // get graphics by name
|
||||||
void Clear(); // clear fields; delete additional graphics
|
void Clear(); // clear fields; delete additional graphics
|
||||||
bool IsColorByOwner() // returns whether ColorByOwner-surfaces have been created
|
bool IsColorByOwner() // returns whether ColorByOwner-surfaces have been created
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#ifndef INC_C4Game
|
#ifndef INC_C4Game
|
||||||
#define INC_C4Game
|
#define INC_C4Game
|
||||||
|
|
||||||
|
#include <StdMeshMaterial.h>
|
||||||
#include <C4GameParameters.h>
|
#include <C4GameParameters.h>
|
||||||
#include <C4PlayerInfo.h>
|
#include <C4PlayerInfo.h>
|
||||||
#include <C4RoundResults.h>
|
#include <C4RoundResults.h>
|
||||||
|
@ -82,7 +82,7 @@ class C4Game
|
||||||
|
|
||||||
C4PathFinder PathFinder;
|
C4PathFinder PathFinder;
|
||||||
C4TransferZones TransferZones;
|
C4TransferZones TransferZones;
|
||||||
C4Group ScenarioFile;
|
C4Group ScenarioFile;
|
||||||
C4GroupSet GroupSet;
|
C4GroupSet GroupSet;
|
||||||
C4Group *pParentGroup;
|
C4Group *pParentGroup;
|
||||||
C4Extra Extra;
|
C4Extra Extra;
|
||||||
|
@ -94,6 +94,7 @@ class C4Game
|
||||||
#endif
|
#endif
|
||||||
C4Scoreboard Scoreboard;
|
C4Scoreboard Scoreboard;
|
||||||
C4VideoPlayer VideoPlayer;
|
C4VideoPlayer VideoPlayer;
|
||||||
|
StdMeshMatManager MaterialManager;
|
||||||
class C4Network2Stats *pNetworkStatistics; // may be NULL if no statistics are recorded
|
class C4Network2Stats *pNetworkStatistics; // may be NULL if no statistics are recorded
|
||||||
class C4KeyboardInput &KeyboardInput;
|
class C4KeyboardInput &KeyboardInput;
|
||||||
class C4FileMonitor *pFileMonitor;
|
class C4FileMonitor *pFileMonitor;
|
||||||
|
|
|
@ -173,6 +173,7 @@ class C4Object: public C4PropList
|
||||||
C4NotifyingObjectList Contents;
|
C4NotifyingObjectList Contents;
|
||||||
C4MaterialList *MaterialContents; // SyncClearance-NoSave //
|
C4MaterialList *MaterialContents; // SyncClearance-NoSave //
|
||||||
C4DefGraphics *pGraphics; // currently set object graphics
|
C4DefGraphics *pGraphics; // currently set object graphics
|
||||||
|
StdMeshInstance* pMeshInstance; // Instance for mesh-type objects
|
||||||
C4Effect *pEffects; // linked list of effects
|
C4Effect *pEffects; // linked list of effects
|
||||||
C4ParticleList FrontParticles, BackParticles; // lists of object local particles
|
C4ParticleList FrontParticles, BackParticles; // lists of object local particles
|
||||||
|
|
||||||
|
@ -253,6 +254,7 @@ class C4Object: public C4PropList
|
||||||
void DrawTopFace(C4TargetFacet &cgo, int32_t iByPlayer = -1, DrawMode eDrawMode=ODM_Normal);
|
void DrawTopFace(C4TargetFacet &cgo, int32_t iByPlayer = -1, DrawMode eDrawMode=ODM_Normal);
|
||||||
void DrawActionFace(C4TargetFacet &cgo, float offX, float offY);
|
void DrawActionFace(C4TargetFacet &cgo, float offX, float offY);
|
||||||
void DrawFace(C4TargetFacet &cgo, float offX, float offY, int32_t iPhaseX=0, int32_t iPhaseY=0);
|
void DrawFace(C4TargetFacet &cgo, float offX, float offY, int32_t iPhaseX=0, int32_t iPhaseY=0);
|
||||||
|
void DrawFaceImpl(C4TargetFacet &cgo, bool action, float fx, float fy, float fwdt, float fhgt, float tx, float ty, float twdt, float thgt, C4DrawTransform* transform);
|
||||||
void Execute();
|
void Execute();
|
||||||
void ClearPointers(C4Object *ptr);
|
void ClearPointers(C4Object *ptr);
|
||||||
BOOL ExecMovement();
|
BOOL ExecMovement();
|
||||||
|
|
|
@ -201,6 +201,7 @@ P_InLiquidAction,
|
||||||
P_TurnAction,
|
P_TurnAction,
|
||||||
P_Reverse,
|
P_Reverse,
|
||||||
P_Step,
|
P_Step,
|
||||||
|
P_Animation,
|
||||||
P_LAST };
|
P_LAST };
|
||||||
|
|
||||||
// There is only one Stringtable in Game.ScriptEngine
|
// There is only one Stringtable in Game.ScriptEngine
|
||||||
|
|
|
@ -525,7 +525,7 @@ BOOL C4Def::Load(C4Group &hGroup,
|
||||||
|
|
||||||
// Read surface bitmap
|
// Read surface bitmap
|
||||||
if (dwLoadWhat & C4D_Load_Bitmap)
|
if (dwLoadWhat & C4D_Load_Bitmap)
|
||||||
if (!Graphics.LoadBitmaps(hGroup, !!ColorByOwner))
|
if (!Graphics.Load(hGroup, !!ColorByOwner))
|
||||||
{
|
{
|
||||||
DebugLogF(" Error loading graphics of %s (%s)", hGroup.GetFullName().getData(), C4IdText(id));
|
DebugLogF(" Error loading graphics of %s (%s)", hGroup.GetFullName().getData(), C4IdText(id));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -707,14 +707,31 @@ void C4Def::Draw(C4Facet &cgo, BOOL fSelected, DWORD iColor, C4Object *pObj, int
|
||||||
// if assigned: use object specific rect and graphics
|
// if assigned: use object specific rect and graphics
|
||||||
if (pObj) if(pObj->PictureRect.Wdt) fctPicRect = pObj->PictureRect;
|
if (pObj) if(pObj->PictureRect.Wdt) fctPicRect = pObj->PictureRect;
|
||||||
|
|
||||||
fctPicture.Set((pObj ? *pObj->GetGraphics() : Graphics).GetBitmap(iColor),fctPicRect.x,fctPicRect.y,fctPicRect.Wdt,fctPicRect.Hgt);
|
|
||||||
|
|
||||||
if (fSelected)
|
if (fSelected)
|
||||||
Application.DDraw->DrawBox(cgo.Surface,cgo.X,cgo.Y,cgo.X+cgo.Wdt-1,cgo.Y+cgo.Hgt-1,CRed);
|
Application.DDraw->DrawBox(cgo.Surface,cgo.X,cgo.Y,cgo.X+cgo.Wdt-1,cgo.Y+cgo.Hgt-1,CRed);
|
||||||
|
|
||||||
|
C4DefGraphics* graphics = pObj ? pObj->GetGraphics() : &Graphics;
|
||||||
|
|
||||||
// specific object color?
|
// specific object color?
|
||||||
if (pObj) pObj->PrepareDrawing();
|
if (pObj) pObj->PrepareDrawing();
|
||||||
fctPicture.Draw(cgo,TRUE,iPhaseX,iPhaseY,TRUE);
|
|
||||||
|
switch(graphics->Type)
|
||||||
|
{
|
||||||
|
case C4DefGraphics::TYPE_Bitmap:
|
||||||
|
fctPicture.Set((pObj ? *pObj->GetGraphics() : Graphics).GetBitmap(iColor),fctPicRect.x,fctPicRect.y,fctPicRect.Wdt,fctPicRect.Hgt);
|
||||||
|
fctPicture.Draw(cgo,TRUE,iPhaseX,iPhaseY,TRUE);
|
||||||
|
break;
|
||||||
|
case C4DefGraphics::TYPE_Mesh:
|
||||||
|
{
|
||||||
|
// TODO: Allow rendering of a mesh directly, without instance (to render pose; no animation)
|
||||||
|
StdMeshInstance dummy(*graphics->Mesh);
|
||||||
|
dummy.SetFaceOrdering(StdMeshInstance::FO_NearestToFarthest);
|
||||||
|
// TODO: Keep aspect ratio of mesh dimensions
|
||||||
|
lpDDraw->RenderMesh(dummy, cgo.Surface, cgo.X, cgo.Y, cgo.Wdt, cgo.Hgt, NULL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (pObj) pObj->FinishedDrawing();
|
if (pObj) pObj->FinishedDrawing();
|
||||||
|
|
||||||
// draw overlays
|
// draw overlays
|
||||||
|
|
|
@ -42,6 +42,35 @@
|
||||||
#include <C4GameObjects.h>
|
#include <C4GameObjects.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Helper class to load additional ressources required for meshes from
|
||||||
|
// a C4Group.
|
||||||
|
class AdditionalRessourcesLoader:
|
||||||
|
public StdMeshMaterialTextureLoader, public StdMeshSkeletonLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AdditionalRessourcesLoader(C4Group& hGroup): Group(hGroup) {}
|
||||||
|
|
||||||
|
virtual bool LoadTexture(const char* filename, CPNGFile& dest)
|
||||||
|
{
|
||||||
|
char* buf;
|
||||||
|
size_t size;
|
||||||
|
if(!Group.LoadEntry(filename, &buf, &size, 1)) return false;
|
||||||
|
bool ret = dest.Load(reinterpret_cast<BYTE*>(buf), size);
|
||||||
|
delete[] buf;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual StdStrBuf LoadSkeleton(const char* filename)
|
||||||
|
{
|
||||||
|
StdStrBuf ret;
|
||||||
|
if(!Group.LoadEntryString(filename, ret)) return StdStrBuf();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
C4Group& Group;
|
||||||
|
};
|
||||||
|
|
||||||
//-------------------------------- C4DefGraphics -----------------------------------------------
|
//-------------------------------- C4DefGraphics -----------------------------------------------
|
||||||
|
|
||||||
C4DefGraphics::C4DefGraphics(C4Def *pOwnDef)
|
C4DefGraphics::C4DefGraphics(C4Def *pOwnDef)
|
||||||
|
@ -49,6 +78,7 @@ C4DefGraphics::C4DefGraphics(C4Def *pOwnDef)
|
||||||
// store def
|
// store def
|
||||||
pDef = pOwnDef;
|
pDef = pOwnDef;
|
||||||
// zero fields
|
// zero fields
|
||||||
|
Type = TYPE_Bitmap;
|
||||||
Bitmap = BitmapClr = NULL;
|
Bitmap = BitmapClr = NULL;
|
||||||
pNext = NULL;
|
pNext = NULL;
|
||||||
fColorBitmapAutoCreated = false;
|
fColorBitmapAutoCreated = false;
|
||||||
|
@ -64,8 +94,17 @@ C4DefGraphics *C4DefGraphics::GetLast()
|
||||||
void C4DefGraphics::Clear()
|
void C4DefGraphics::Clear()
|
||||||
{
|
{
|
||||||
// zero own fields
|
// zero own fields
|
||||||
if (BitmapClr) { delete BitmapClr; BitmapClr=NULL; }
|
switch (Type)
|
||||||
if (Bitmap) { delete Bitmap; Bitmap=NULL; }
|
{
|
||||||
|
case TYPE_Bitmap:
|
||||||
|
if (BitmapClr) { delete BitmapClr; BitmapClr=NULL; }
|
||||||
|
if (Bitmap) { delete Bitmap; Bitmap=NULL; }
|
||||||
|
break;
|
||||||
|
case TYPE_Mesh:
|
||||||
|
if (Mesh) { delete Mesh; Mesh = NULL; }
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// delete additonal graphics
|
// delete additonal graphics
|
||||||
C4AdditionalDefGraphics *pGrp2N = pNext, *pGrp2;
|
C4AdditionalDefGraphics *pGrp2N = pNext, *pGrp2;
|
||||||
while (pGrp2=pGrp2N) { pGrp2N = pGrp2->pNext; pGrp2->pNext = NULL; delete pGrp2; }
|
while (pGrp2=pGrp2N) { pGrp2N = pGrp2->pNext; pGrp2->pNext = NULL; delete pGrp2; }
|
||||||
|
@ -116,17 +155,74 @@ bool C4DefGraphics::LoadBitmap(C4Group &hGroup, const char *szFilename, const ch
|
||||||
if (!BitmapClr->CreateColorByOwner(Bitmap)) return false;
|
if (!BitmapClr->CreateColorByOwner(Bitmap)) return false;
|
||||||
fColorBitmapAutoCreated = true;
|
fColorBitmapAutoCreated = true;
|
||||||
}
|
}
|
||||||
|
Type = TYPE_Bitmap;
|
||||||
// success
|
// success
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool C4DefGraphics::LoadBitmaps(C4Group &hGroup, bool fColorByOwner)
|
bool C4DefGraphics::LoadMesh(C4Group &hGroup, StdMeshSkeletonLoader& loader)
|
||||||
|
{
|
||||||
|
char* buf;
|
||||||
|
size_t size;
|
||||||
|
if(!hGroup.LoadEntry(C4CFN_DefMesh, &buf, &size, 1)) return false;
|
||||||
|
|
||||||
|
Mesh = new StdMesh;
|
||||||
|
|
||||||
|
bool result;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
|
Mesh->InitXML(C4CFN_DefMesh, buf, loader, Game.MaterialManager);
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
catch(const StdMeshError& ex)
|
||||||
|
{
|
||||||
|
DebugLogF("Failed to load mesh: %s\n", ex.what());
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] buf;
|
||||||
|
if(!result)
|
||||||
|
{
|
||||||
|
delete Mesh;
|
||||||
|
Mesh = NULL;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type = TYPE_Mesh;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool C4DefGraphics::Load(C4Group &hGroup, bool fColorByOwner)
|
||||||
|
{
|
||||||
|
char Filename[_MAX_PATH+1]; *Filename=0;
|
||||||
|
AdditionalRessourcesLoader loader(hGroup);
|
||||||
|
|
||||||
|
// Load all materials for this definition:
|
||||||
|
hGroup.ResetSearch();
|
||||||
|
while (hGroup.FindNextEntry(C4CFN_DefMaterials, Filename, NULL, NULL, !!*Filename))
|
||||||
|
{
|
||||||
|
StdStrBuf material;
|
||||||
|
if(hGroup.LoadEntryString(Filename, material))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Game.MaterialManager.Parse(material.getData(), Filename, loader);
|
||||||
|
}
|
||||||
|
catch(const StdMeshMaterialError& ex)
|
||||||
|
{
|
||||||
|
DebugLogF("Failed to read material script: %s\n", ex.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try from Mesh first
|
||||||
|
if (LoadMesh(hGroup, loader)) return true;
|
||||||
// load basic graphics
|
// load basic graphics
|
||||||
if (!LoadBitmap(hGroup, C4CFN_DefGraphics, C4CFN_DefGraphicsPNG, C4CFN_ClrByOwnerPNG, fColorByOwner)) return false;
|
if (!LoadBitmap(hGroup, C4CFN_DefGraphics, C4CFN_DefGraphicsPNG, C4CFN_ClrByOwnerPNG, fColorByOwner)) return false;
|
||||||
|
|
||||||
// load additional graphics
|
// load additional graphics
|
||||||
// first, search all png-graphics in NewGfx
|
// first, search all png-graphics in NewGfx
|
||||||
char Filename[_MAX_PATH+1]; *Filename=0;
|
|
||||||
C4DefGraphics *pLastGraphics = this;
|
C4DefGraphics *pLastGraphics = this;
|
||||||
int32_t iWildcardPos;
|
int32_t iWildcardPos;
|
||||||
iWildcardPos = SCharPos('*', C4CFN_DefGraphicsExPNG);
|
iWildcardPos = SCharPos('*', C4CFN_DefGraphicsExPNG);
|
||||||
|
@ -251,6 +347,7 @@ C4PortraitGraphics *C4PortraitGraphics::Get(const char *szGrpName)
|
||||||
|
|
||||||
bool C4DefGraphics::CopyGraphicsFrom(C4DefGraphics &rSource)
|
bool C4DefGraphics::CopyGraphicsFrom(C4DefGraphics &rSource)
|
||||||
{
|
{
|
||||||
|
if (Type != TYPE_Bitmap) return false; // TODO!
|
||||||
// clear previous
|
// clear previous
|
||||||
if (BitmapClr) { delete BitmapClr; BitmapClr=NULL; }
|
if (BitmapClr) { delete BitmapClr; BitmapClr=NULL; }
|
||||||
if (Bitmap) { delete Bitmap; Bitmap=NULL; }
|
if (Bitmap) { delete Bitmap; Bitmap=NULL; }
|
||||||
|
@ -277,6 +374,7 @@ bool C4DefGraphics::CopyGraphicsFrom(C4DefGraphics &rSource)
|
||||||
|
|
||||||
void C4DefGraphics::DrawClr(C4Facet &cgo, BOOL fAspect, DWORD dwClr)
|
void C4DefGraphics::DrawClr(C4Facet &cgo, BOOL fAspect, DWORD dwClr)
|
||||||
{
|
{
|
||||||
|
if(Type != TYPE_Bitmap) return; // TODO
|
||||||
// create facet and draw it
|
// create facet and draw it
|
||||||
C4Surface *pSfc = BitmapClr ? BitmapClr : Bitmap; if (!pSfc) return;
|
C4Surface *pSfc = BitmapClr ? BitmapClr : Bitmap; if (!pSfc) return;
|
||||||
C4Facet fct(pSfc, 0,0,pSfc->Wdt, pSfc->Hgt);
|
C4Facet fct(pSfc, 0,0,pSfc->Wdt, pSfc->Hgt);
|
||||||
|
@ -493,7 +591,7 @@ bool C4Portrait::Link(C4DefGraphics *pGfxPortrait)
|
||||||
bool C4Portrait::SavePNG(C4Group &rGroup, const char *szFilename, const char *szOverlayFN)
|
bool C4Portrait::SavePNG(C4Group &rGroup, const char *szFilename, const char *szOverlayFN)
|
||||||
{
|
{
|
||||||
// safety
|
// safety
|
||||||
if (!pGfxPortrait || !szFilename || !pGfxPortrait->Bitmap) return false;
|
if (!pGfxPortrait || !szFilename || pGfxPortrait->Type != C4DefGraphics::TYPE_Bitmap || !pGfxPortrait->Bitmap) return false;
|
||||||
// save files
|
// save files
|
||||||
if (pGfxPortrait->fColorBitmapAutoCreated)
|
if (pGfxPortrait->fColorBitmapAutoCreated)
|
||||||
{
|
{
|
||||||
|
@ -602,6 +700,7 @@ void C4GraphicsOverlay::UpdateFacet()
|
||||||
if (eMode == MODE_Object) return;
|
if (eMode == MODE_Object) return;
|
||||||
// otherwise, source graphics must be specified
|
// otherwise, source graphics must be specified
|
||||||
if (!pSourceGfx) return;
|
if (!pSourceGfx) return;
|
||||||
|
if (pSourceGfx->Type != C4DefGraphics::TYPE_Bitmap) return;
|
||||||
C4Def *pDef = pSourceGfx->pDef;
|
C4Def *pDef = pSourceGfx->pDef;
|
||||||
assert(pDef);
|
assert(pDef);
|
||||||
fZoomToShape = false;
|
fZoomToShape = false;
|
||||||
|
|
|
@ -594,6 +594,7 @@ void C4Game::Clear()
|
||||||
KeyboardInput.Clear();
|
KeyboardInput.Clear();
|
||||||
SetMusicLevel(100);
|
SetMusicLevel(100);
|
||||||
PlayList.Clear();
|
PlayList.Clear();
|
||||||
|
MaterialManager.Clear();
|
||||||
|
|
||||||
// global fullscreen class is not cleared, because it holds the carrier window
|
// global fullscreen class is not cleared, because it holds the carrier window
|
||||||
// but the menu must be cleared (maybe move Fullscreen.Menu somewhere else?)
|
// but the menu must be cleared (maybe move Fullscreen.Menu somewhere else?)
|
||||||
|
|
|
@ -153,6 +153,7 @@ void C4Object::Default()
|
||||||
pLayer=NULL;
|
pLayer=NULL;
|
||||||
pSolidMaskData=NULL;
|
pSolidMaskData=NULL;
|
||||||
pGraphics=NULL;
|
pGraphics=NULL;
|
||||||
|
pMeshInstance=NULL;
|
||||||
pDrawTransform=NULL;
|
pDrawTransform=NULL;
|
||||||
pEffects=NULL;
|
pEffects=NULL;
|
||||||
pGfxOverlay=NULL;
|
pGfxOverlay=NULL;
|
||||||
|
@ -182,6 +183,15 @@ BOOL C4Object::Init(C4PropList *pDef, C4Object *pCreator,
|
||||||
|
|
||||||
// graphics
|
// graphics
|
||||||
pGraphics = &Def->Graphics;
|
pGraphics = &Def->Graphics;
|
||||||
|
if(pGraphics->Type == C4DefGraphics::TYPE_Mesh)
|
||||||
|
{
|
||||||
|
pMeshInstance = new StdMeshInstance(*pGraphics->Mesh);
|
||||||
|
pMeshInstance->SetFaceOrdering(StdMeshInstance::FO_NearestToFarthest);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pMeshInstance = NULL;
|
||||||
|
}
|
||||||
BlitMode = Def->BlitMode;
|
BlitMode = Def->BlitMode;
|
||||||
|
|
||||||
// Position
|
// Position
|
||||||
|
@ -411,6 +421,18 @@ void C4Object::UpdateGraphics(bool fGraphicsChanged, bool fTemp)
|
||||||
// ensure SolidMask-rect lies within new graphics-rect
|
// ensure SolidMask-rect lies within new graphics-rect
|
||||||
CheckSolidMaskRect();
|
CheckSolidMaskRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete pMeshInstance;
|
||||||
|
if(pGraphics->Type == C4DefGraphics::TYPE_Mesh)
|
||||||
|
{
|
||||||
|
pMeshInstance = new StdMeshInstance(*pGraphics->Mesh);
|
||||||
|
pMeshInstance->SetFaceOrdering(StdMeshInstance::FO_NearestToFarthest);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pMeshInstance = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// update face - this also puts any SolidMask
|
// update face - this also puts any SolidMask
|
||||||
UpdateFace(false);
|
UpdateFace(false);
|
||||||
}
|
}
|
||||||
|
@ -452,6 +474,25 @@ void C4Object::UpdateFlipDir()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void C4Object::DrawFaceImpl(C4TargetFacet &cgo, bool action, float fx, float fy, float fwdt, float fhgt, float tx, float ty, float twdt, float thgt, C4DrawTransform* transform)
|
||||||
|
{
|
||||||
|
CSurface* sfc;
|
||||||
|
switch(GetGraphics()->Type)
|
||||||
|
{
|
||||||
|
case C4DefGraphics::TYPE_Bitmap:
|
||||||
|
sfc = action ? Action.Facet.Surface : GetGraphics()->GetBitmap(Color);
|
||||||
|
|
||||||
|
lpDDraw->Blit(sfc,
|
||||||
|
fx, fy, fwdt, fhgt,
|
||||||
|
cgo.Surface, tx, ty, twdt, thgt,
|
||||||
|
TRUE, transform);
|
||||||
|
break;
|
||||||
|
case C4DefGraphics::TYPE_Mesh:
|
||||||
|
lpDDraw->RenderMesh(*pMeshInstance, cgo.Surface, tx, ty, twdt, thgt, transform);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void C4Object::DrawFace(C4TargetFacet &cgo, float offX, float offY, int32_t iPhaseX, int32_t iPhaseY)
|
void C4Object::DrawFace(C4TargetFacet &cgo, float offX, float offY, int32_t iPhaseX, int32_t iPhaseY)
|
||||||
{
|
{
|
||||||
const float swdt = float(Def->Shape.Wdt);
|
const float swdt = float(Def->Shape.Wdt);
|
||||||
|
@ -481,10 +522,11 @@ void C4Object::DrawFace(C4TargetFacet &cgo, float offX, float offY, int32_t iPha
|
||||||
// Straight
|
// Straight
|
||||||
if ((!Def->Rotateable || (r==0)) && !pDrawTransform)
|
if ((!Def->Rotateable || (r==0)) && !pDrawTransform)
|
||||||
{
|
{
|
||||||
lpDDraw->Blit(GetGraphics()->GetBitmap(Color),
|
DrawFaceImpl(cgo, false, fx, fy, fwdt, fhgt, tx, ty, twdt, thgt, NULL);
|
||||||
|
/* lpDDraw->Blit(GetGraphics()->GetBitmap(Color),
|
||||||
fx, fy, fwdt, fhgt,
|
fx, fy, fwdt, fhgt,
|
||||||
cgo.Surface, tx, ty, twdt, thgt,
|
cgo.Surface, tx, ty, twdt, thgt,
|
||||||
TRUE, NULL);
|
TRUE, NULL);*/
|
||||||
}
|
}
|
||||||
// Rotated or transformed
|
// Rotated or transformed
|
||||||
else
|
else
|
||||||
|
@ -499,10 +541,11 @@ void C4Object::DrawFace(C4TargetFacet &cgo, float offX, float offY, int32_t iPha
|
||||||
{
|
{
|
||||||
rot.SetRotate(r * 100, offX, offY);
|
rot.SetRotate(r * 100, offX, offY);
|
||||||
}
|
}
|
||||||
lpDDraw->Blit(GetGraphics()->GetBitmap(Color),
|
DrawFaceImpl(cgo, false, fx, fy, fwdt, fhgt, tx, ty, twdt, thgt, &rot);
|
||||||
|
/* lpDDraw->Blit(GetGraphics()->GetBitmap(Color),
|
||||||
fx, fy, fwdt, fhgt,
|
fx, fy, fwdt, fhgt,
|
||||||
cgo.Surface, tx, ty, twdt, thgt,
|
cgo.Surface, tx, ty, twdt, thgt,
|
||||||
TRUE, &rot);
|
TRUE, &rot);*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,10 +590,11 @@ void C4Object::DrawActionFace(C4TargetFacet &cgo, float offX, float offY)
|
||||||
// Straight
|
// Straight
|
||||||
if ((!Def->Rotateable || (r==0)) && !pDrawTransform)
|
if ((!Def->Rotateable || (r==0)) && !pDrawTransform)
|
||||||
{
|
{
|
||||||
lpDDraw->Blit(Action.Facet.Surface,
|
DrawFaceImpl(cgo, true, fx, fy, fwdt, fhgt, tx, ty, twdt, thgt, NULL);
|
||||||
|
/*lpDDraw->Blit(Action.Facet.Surface,
|
||||||
fx, fy, fwdt, fhgt,
|
fx, fy, fwdt, fhgt,
|
||||||
cgo.Surface, tx, ty, twdt, thgt,
|
cgo.Surface, tx, ty, twdt, thgt,
|
||||||
TRUE, NULL);
|
TRUE, NULL);*/
|
||||||
}
|
}
|
||||||
// Rotated or transformed
|
// Rotated or transformed
|
||||||
else
|
else
|
||||||
|
@ -567,10 +611,11 @@ void C4Object::DrawActionFace(C4TargetFacet &cgo, float offX, float offY)
|
||||||
{
|
{
|
||||||
rot.SetRotate(r * 100, offX, offY);
|
rot.SetRotate(r * 100, offX, offY);
|
||||||
}
|
}
|
||||||
lpDDraw->Blit(Action.Facet.Surface,
|
DrawFaceImpl(cgo, true, fx, fy, fwdt, fhgt, tx, ty, twdt, thgt, &rot);
|
||||||
|
/* lpDDraw->Blit(Action.Facet.Surface,
|
||||||
fx, fy, fwdt, fhgt,
|
fx, fy, fwdt, fhgt,
|
||||||
cgo.Surface, tx, ty, twdt, thgt,
|
cgo.Surface, tx, ty, twdt, thgt,
|
||||||
TRUE, &rot);
|
TRUE, &rot);*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2204,7 +2249,21 @@ C4Value C4Object::Call(const char *szFunctionCall, C4AulParSet *pPars, bool fPas
|
||||||
BOOL C4Object::SetPhase(int32_t iPhase)
|
BOOL C4Object::SetPhase(int32_t iPhase)
|
||||||
{
|
{
|
||||||
if (!Action.pActionDef) return FALSE;
|
if (!Action.pActionDef) return FALSE;
|
||||||
Action.Phase=BoundBy<int32_t>(iPhase,0,Action.pActionDef->GetPropertyInt(P_Length));
|
|
||||||
|
const int32_t length = Action.pActionDef->GetPropertyInt(P_Length);
|
||||||
|
const int32_t delay = Action.pActionDef->GetPropertyInt(P_Delay);
|
||||||
|
|
||||||
|
Action.Phase=BoundBy<int32_t>(iPhase,0,length);
|
||||||
|
Action.PhaseDelay = 0;
|
||||||
|
|
||||||
|
if(pMeshInstance)
|
||||||
|
{
|
||||||
|
if(delay)
|
||||||
|
pMeshInstance->SetPosition(static_cast<float>(Action.Phase * delay + Action.PhaseDelay) / (delay * length) * pMeshInstance->GetAnimation()->Length);
|
||||||
|
else
|
||||||
|
pMeshInstance->SetPosition(static_cast<float>(Action.Phase) / length * pMeshInstance->GetAnimation()->Length);
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2253,7 +2312,8 @@ void C4Object::Draw(C4TargetFacet &cgo, int32_t iByPlayer, DrawMode eDrawMode)
|
||||||
{ if (FrontParticles && !Contained) FrontParticles.Draw(cgo,this); return; }
|
{ if (FrontParticles && !Contained) FrontParticles.Draw(cgo,this); return; }
|
||||||
|
|
||||||
// ensure correct color is set
|
// ensure correct color is set
|
||||||
if (GetGraphics()->BitmapClr) GetGraphics()->BitmapClr->SetClr(Color);
|
if (GetGraphics()->Type == C4DefGraphics::TYPE_Bitmap)
|
||||||
|
if (GetGraphics()->BitmapClr) GetGraphics()->BitmapClr->SetClr(Color);
|
||||||
|
|
||||||
// Debug Display //////////////////////////////////////////////////////////////////////
|
// Debug Display //////////////////////////////////////////////////////////////////////
|
||||||
if (::GraphicsSystem.ShowCommand && !eDrawMode)
|
if (::GraphicsSystem.ShowCommand && !eDrawMode)
|
||||||
|
@ -2405,7 +2465,7 @@ void C4Object::Draw(C4TargetFacet &cgo, int32_t iByPlayer, DrawMode eDrawMode)
|
||||||
(fixtof(Action.Target->fix_y) + Action.Target->Shape.GetY()) - (fixtof(fix_y) + Shape.GetY() + Action.FacetY),
|
(fixtof(Action.Target->fix_y) + Action.Target->Shape.GetY()) - (fixtof(fix_y) + Shape.GetY() + Action.FacetY),
|
||||||
TRUE);
|
TRUE);
|
||||||
}
|
}
|
||||||
else if (Action.Facet.Surface)
|
else if (Action.Facet.Surface || GetGraphics()->Type != C4DefGraphics::TYPE_Bitmap)
|
||||||
DrawActionFace(cgo, offX, offY);
|
DrawActionFace(cgo, offX, offY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3161,7 +3221,7 @@ void C4Object::Clear()
|
||||||
if (pEffects) { delete pEffects; pEffects=NULL; }
|
if (pEffects) { delete pEffects; pEffects=NULL; }
|
||||||
if (FrontParticles) FrontParticles.Clear();
|
if (FrontParticles) FrontParticles.Clear();
|
||||||
if (BackParticles) BackParticles.Clear();
|
if (BackParticles) BackParticles.Clear();
|
||||||
if (pSolidMaskData) { delete pSolidMaskData; pSolidMaskData=NULL; }
|
if (pSolidMaskData) { delete pSolidMaskData; pSolidMaskData=NULL; }
|
||||||
if (Menu) delete Menu; Menu=NULL;
|
if (Menu) delete Menu; Menu=NULL;
|
||||||
if (MaterialContents) delete MaterialContents; MaterialContents=NULL;
|
if (MaterialContents) delete MaterialContents; MaterialContents=NULL;
|
||||||
// clear commands!
|
// clear commands!
|
||||||
|
@ -3172,6 +3232,7 @@ void C4Object::Clear()
|
||||||
}
|
}
|
||||||
if (pDrawTransform) { delete pDrawTransform; pDrawTransform=NULL; }
|
if (pDrawTransform) { delete pDrawTransform; pDrawTransform=NULL; }
|
||||||
if (pGfxOverlay) { delete pGfxOverlay; pGfxOverlay=NULL; }
|
if (pGfxOverlay) { delete pGfxOverlay; pGfxOverlay=NULL; }
|
||||||
|
if (pMeshInstance) { delete pMeshInstance; pMeshInstance = NULL; }
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL C4Object::ContainedControl(BYTE byCom)
|
BOOL C4Object::ContainedControl(BYTE byCom)
|
||||||
|
@ -3731,6 +3792,9 @@ void C4Object::SetSolidMask(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt,
|
||||||
|
|
||||||
bool C4Object::CheckSolidMaskRect()
|
bool C4Object::CheckSolidMaskRect()
|
||||||
{
|
{
|
||||||
|
// SolidMasks are only supported for bitmap graphics
|
||||||
|
if(GetGraphics()->Type != C4DefGraphics::TYPE_Bitmap) return false;
|
||||||
|
|
||||||
// check NewGfx only, because invalid SolidMask-rects are OK in OldGfx
|
// check NewGfx only, because invalid SolidMask-rects are OK in OldGfx
|
||||||
// the bounds-check is done in CStdDDraw::GetPixel()
|
// the bounds-check is done in CStdDDraw::GetPixel()
|
||||||
CSurface *sfcGraphics = GetGraphics()->GetBitmap();
|
CSurface *sfcGraphics = GetGraphics()->GetBitmap();
|
||||||
|
@ -4028,6 +4092,16 @@ BOOL C4Object::SetAction(C4PropList * Act, C4Object *pTarget, C4Object *pTarget2
|
||||||
if (LastAction->GetPropertyInt(P_NoOtherAction) && !fForce)
|
if (LastAction->GetPropertyInt(P_NoOtherAction) && !fForce)
|
||||||
if (Act != LastAction)
|
if (Act != LastAction)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
// Set animation on instance. Abort if the mesh does not have
|
||||||
|
// such an animation.
|
||||||
|
if(pMeshInstance)
|
||||||
|
{
|
||||||
|
C4String* Animation = Act ? Act->GetPropertyStr(P_Animation) : NULL;
|
||||||
|
if(!Animation || Animation->GetData() == "")
|
||||||
|
pMeshInstance->UnsetAnimation();
|
||||||
|
else if(!pMeshInstance->SetAnimationByName(Animation->GetData()))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
// Stop previous act sound
|
// Stop previous act sound
|
||||||
if (LastAction)
|
if (LastAction)
|
||||||
if (Act != LastAction)
|
if (Act != LastAction)
|
||||||
|
@ -5301,6 +5375,7 @@ void C4Object::ExecAction()
|
||||||
if (pAction->GetPropertyInt(P_Delay))
|
if (pAction->GetPropertyInt(P_Delay))
|
||||||
{
|
{
|
||||||
Action.PhaseDelay+=iPhaseAdvance;
|
Action.PhaseDelay+=iPhaseAdvance;
|
||||||
|
bool set_new_action = false;
|
||||||
if (Action.PhaseDelay >= pAction->GetPropertyInt(P_Delay))
|
if (Action.PhaseDelay >= pAction->GetPropertyInt(P_Delay))
|
||||||
{
|
{
|
||||||
// Advance Phase
|
// Advance Phase
|
||||||
|
@ -5316,15 +5391,25 @@ void C4Object::ExecAction()
|
||||||
{
|
{
|
||||||
// set new action if it's not Hold
|
// set new action if it's not Hold
|
||||||
if (pAction->GetPropertyStr(P_NextAction) == Strings.P[P_Hold])
|
if (pAction->GetPropertyStr(P_NextAction) == Strings.P[P_Hold])
|
||||||
|
{
|
||||||
Action.Phase = pAction->GetPropertyInt(P_Length)-1;
|
Action.Phase = pAction->GetPropertyInt(P_Length)-1;
|
||||||
|
Action.PhaseDelay = pAction->GetPropertyInt(P_Delay)-1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Set new action
|
// Set new action
|
||||||
|
set_new_action = true;
|
||||||
SetActionByName(pAction->GetPropertyStr(P_NextAction), NULL, NULL, SAC_StartCall | SAC_EndCall);
|
SetActionByName(pAction->GetPropertyStr(P_NextAction), NULL, NULL, SAC_StartCall | SAC_EndCall);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update animation on mesh instance. If a new action was set,
|
||||||
|
// then will already have happened for the new action.
|
||||||
|
if(pMeshInstance && pMeshInstance->GetAnimation() && !set_new_action)
|
||||||
|
pMeshInstance->SetPosition(static_cast<float>(Action.Phase * pAction->GetPropertyInt(P_Delay) + Action.PhaseDelay) / (pAction->GetPropertyInt(P_Delay) * pAction->GetPropertyInt(P_Length)) * pMeshInstance->GetAnimation()->Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -227,7 +227,7 @@ struct C4ValueConv<Nillable<T> >
|
||||||
inline static Nillable<T> FromC4V(C4Value &v) { return Nillable<T>(v.GetType() == C4V_Any, C4ValueConv<T>::FromC4V(v)); }
|
inline static Nillable<T> FromC4V(C4Value &v) { return Nillable<T>(v.GetType() == C4V_Any, C4ValueConv<T>::FromC4V(v)); }
|
||||||
inline static Nillable<T> _FromC4V(C4Value &v) { return Nillable<T>(v.GetType() == C4V_Any, C4ValueConv<T>::_FromC4V(v)); }
|
inline static Nillable<T> _FromC4V(C4Value &v) { return Nillable<T>(v.GetType() == C4V_Any, C4ValueConv<T>::_FromC4V(v)); }
|
||||||
inline static C4V_Type Type() { return C4ValueConv<T>::Type(); }
|
inline static C4V_Type Type() { return C4ValueConv<T>::Type(); }
|
||||||
inline static C4Value ToC4V(Nillable<T> &v) { if(v.IsNil()) return C4VNull; else return C4ValueConv<T>::ToC4V(v.operator T()) }
|
inline static C4Value ToC4V(Nillable<T> &v) { if(v.IsNil()) return C4VNull; else return C4ValueConv<T>::ToC4V(v.operator T()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -114,6 +114,7 @@ C4StringTable::C4StringTable()
|
||||||
P[P_TurnAction] = RegString("TurnAction");
|
P[P_TurnAction] = RegString("TurnAction");
|
||||||
P[P_Reverse] = RegString("Reverse");
|
P[P_Reverse] = RegString("Reverse");
|
||||||
P[P_Step] = RegString("Step");
|
P[P_Step] = RegString("Step");
|
||||||
|
P[P_Animation] = RegString("Animation");
|
||||||
P[P_Visibility] = RegString("Visibility");
|
P[P_Visibility] = RegString("Visibility");
|
||||||
P[P_Parallaxity] = RegString("Parallaxity");
|
P[P_Parallaxity] = RegString("Parallaxity");
|
||||||
P[P_LineColors] = RegString("LineColors");
|
P[P_LineColors] = RegString("LineColors");
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
[DefCore]
|
||||||
|
id=MONS
|
||||||
|
Version=4,9,8
|
||||||
|
Category=C4D_Living|C4D_SelectAnimal
|
||||||
|
MaxUserSelect=5
|
||||||
|
TimerCall=Activity
|
||||||
|
ContactCalls=1
|
||||||
|
Width=48
|
||||||
|
Height=34
|
||||||
|
Offset=-24,-17
|
||||||
|
Vertices=7
|
||||||
|
VertexX=-1,1,0,-6,-2,7,2
|
||||||
|
VertexY=-7,-7,12,-3,6,-3,6
|
||||||
|
VertexCNAT=5,6,8,1,1,2,2
|
||||||
|
VertexFriction=100,100,100,100,100,100
|
||||||
|
Value=35
|
||||||
|
Mass=100
|
||||||
|
Components=MONS=1
|
||||||
|
Picture=576,68,64,64
|
||||||
|
Growth=15
|
||||||
|
Float=1
|
||||||
|
BorderBound=1
|
||||||
|
StretchGrowth=1
|
||||||
|
NoBurnDecay=1
|
||||||
|
IncompleteActivity=1
|
||||||
|
VehicleControl=2
|
||||||
|
Pathfinder=1
|
||||||
|
ClosedContainer=2
|
||||||
|
NoFight=1
|
||||||
|
Rotate=1
|
||||||
|
|
||||||
|
[Physical]
|
||||||
|
Energy=250000
|
||||||
|
Breath=50000
|
||||||
|
Walk=71000
|
||||||
|
Jump=50000
|
||||||
|
Scale=30000
|
||||||
|
Hangle=30000
|
||||||
|
Dig=40000
|
||||||
|
Swim=60000
|
||||||
|
Throw=50000
|
||||||
|
Push=40000
|
||||||
|
Fight=50000
|
||||||
|
CorrosionResist=1
|
|
@ -0,0 +1 @@
|
||||||
|
Friedliebende grüne Zeitgenossen.
|
|
@ -0,0 +1 @@
|
||||||
|
They want no harm.
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,2 @@
|
||||||
|
DE:Monster
|
||||||
|
US:Monster
|
|
@ -0,0 +1,14 @@
|
||||||
|
material Material.002
|
||||||
|
{
|
||||||
|
receive_shadows on
|
||||||
|
technique
|
||||||
|
{
|
||||||
|
pass
|
||||||
|
{
|
||||||
|
ambient 0.500000 0.500000 0.500000 1.000000
|
||||||
|
diffuse 0.000000 0.800000 0.169670 1.000000
|
||||||
|
specular 0.342542 0.500000 0.000000 1.000000 12.500000
|
||||||
|
emissive 0.000000 0.000000 0.000000 1.000000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,325 @@
|
||||||
|
/*-- Monster --*/
|
||||||
|
|
||||||
|
#strict 2
|
||||||
|
//#include ANIM
|
||||||
|
|
||||||
|
public func IsPossessible() { return 1; }
|
||||||
|
|
||||||
|
/* Initialisierung */
|
||||||
|
|
||||||
|
protected func Initialize() { SetAction("Walk"); }
|
||||||
|
|
||||||
|
/* TimerCall mit KI-Steuerung */
|
||||||
|
|
||||||
|
private func Activity()
|
||||||
|
{
|
||||||
|
// Die KI-Steuerung wird bei Besessenheit nicht gebraucht
|
||||||
|
if (GetEffect("PossessionSpell", this)) return;
|
||||||
|
|
||||||
|
// Nichts machen
|
||||||
|
if (Random(2) || (GetAction() != "Walk" && GetAction() != "Swim")) return 1;
|
||||||
|
|
||||||
|
// Springen
|
||||||
|
/* if (GetAction() == "Walk")
|
||||||
|
if (!Random(3)) return DoJump();
|
||||||
|
|
||||||
|
// Umsehen
|
||||||
|
if (GetAction() == "Walk")
|
||||||
|
if (!Random(8)) return SetAction("LookUp");*/
|
||||||
|
|
||||||
|
// Umdrehen
|
||||||
|
if (Random(2)) return TurnRight();
|
||||||
|
return TurnLeft();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Kontakte */
|
||||||
|
|
||||||
|
protected func ContactLeft()
|
||||||
|
{
|
||||||
|
// Die KI-Steuerung wird bei Besessenheit nicht gebraucht
|
||||||
|
if (GetEffect("PossessionSpell", this)) return;
|
||||||
|
|
||||||
|
return TurnRight();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected func ContactRight()
|
||||||
|
{
|
||||||
|
// Die KI-Steuerung wird bei Besessenheit nicht gebraucht
|
||||||
|
if (GetEffect("PossessionSpell", this)) return;
|
||||||
|
|
||||||
|
return TurnLeft();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Aktionen */
|
||||||
|
|
||||||
|
public func TurnRight()
|
||||||
|
{
|
||||||
|
if (Stuck() || (GetAction() != "Walk" && GetAction() != "Swim")) return;
|
||||||
|
if (GetXDir() < 0) SetXDir(0);
|
||||||
|
SetDir(DIR_Right);
|
||||||
|
SetComDir(COMD_Right);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public func TurnLeft()
|
||||||
|
{
|
||||||
|
if (Stuck() || (GetAction() != "Walk" && GetAction() != "Swim")) return;
|
||||||
|
if (GetXDir() > 0) SetXDir(0);
|
||||||
|
SetDir(DIR_Left);
|
||||||
|
SetComDir(COMD_Left);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private func HitCheck()
|
||||||
|
{
|
||||||
|
/* var obj;
|
||||||
|
if (obj = FindObject(0, +1,0,0,0, OCF_Prey, 0,0, NoContainer()))
|
||||||
|
Punch(obj, 10);*/
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public func DoJump()
|
||||||
|
{
|
||||||
|
if (GetAction() != "Walk") return;
|
||||||
|
if (Random(2)) Sound("Growl*");
|
||||||
|
Jump();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Einwirkungen */
|
||||||
|
|
||||||
|
protected func Death()
|
||||||
|
{
|
||||||
|
Sound("DeathGrowl");
|
||||||
|
SetDir(DIR_Left);
|
||||||
|
ChangeDef(DMNS);
|
||||||
|
SetAction("Dead");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Vermehrung */
|
||||||
|
|
||||||
|
private func ReproductionRate() { return 2000; } // Die Chance, dass in einem Timerintervall eine Vermehrung stattfindet
|
||||||
|
private func MaxAnimalCount() { return 4; } // Maximale Tieranzahl im Umkreis
|
||||||
|
|
||||||
|
/* Steuerung durch Besessenheit */
|
||||||
|
|
||||||
|
protected func ControlCommand(szCommand, pTarget, iTx, iTy)
|
||||||
|
{
|
||||||
|
// Bewegungskommando
|
||||||
|
if (szCommand == "MoveTo")
|
||||||
|
return SetCommand(this,szCommand, pTarget, iTx, iTy);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected func ContainedLeft(object caller)
|
||||||
|
{
|
||||||
|
[$TxtMovement$]
|
||||||
|
SetCommand(this, "None");
|
||||||
|
if(!GetPlrCoreJumpAndRunControl(caller->GetController()))
|
||||||
|
TurnLeft();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected func ContainedRight(object caller)
|
||||||
|
{
|
||||||
|
[$TxtMovement$]
|
||||||
|
SetCommand(this, "None");
|
||||||
|
if(!GetPlrCoreJumpAndRunControl(caller->GetController()))
|
||||||
|
TurnRight();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected func ContainedUp(object caller)
|
||||||
|
{
|
||||||
|
[$TxtMovement$]
|
||||||
|
SetCommand(this, "None");
|
||||||
|
if(Contained()) return SetCommand(this, "Exit");
|
||||||
|
if (GetAction() == "Swim")
|
||||||
|
{
|
||||||
|
if(!GetPlrCoreJumpAndRunControl(caller->GetController()))
|
||||||
|
SetComDir(COMD_Up);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DoJump();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected func ContainedDown(object caller)
|
||||||
|
{
|
||||||
|
[$TxtMovement$]
|
||||||
|
SetCommand(this, "None");
|
||||||
|
|
||||||
|
if (GetAction() == "Swim")
|
||||||
|
{
|
||||||
|
if(!GetPlrCoreJumpAndRunControl(caller->GetController()))
|
||||||
|
SetComDir(COMD_Down);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAction() == "Walk")
|
||||||
|
SetAction("LookUp");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* JumpAndRun Steuerung */
|
||||||
|
|
||||||
|
private func ClearDir(bool fX)
|
||||||
|
{
|
||||||
|
if(fX && GetXDir())
|
||||||
|
{
|
||||||
|
if(GetXDir() > 0) SetXDir(Max(GetXDir() - 2, 0));
|
||||||
|
else SetXDir(Min(GetXDir() + 2, 0));
|
||||||
|
}
|
||||||
|
if(!fX && GetYDir())
|
||||||
|
{
|
||||||
|
if(GetYDir() > 0) SetYDir(Max(GetYDir() - 2, 0));
|
||||||
|
else SetYDir(Min(GetYDir() + 2, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func ContainedUpdate(object self, int comdir)
|
||||||
|
{
|
||||||
|
if(GetAction() == "Swim")
|
||||||
|
{
|
||||||
|
SetComDir(comdir);
|
||||||
|
ClearScheduleCall(this, "ClearDir");
|
||||||
|
if(comdir == COMD_Down || comdir == COMD_Up) ScheduleCall(this, "ClearDir", 1, (Abs(GetXDir())+1)/2, true);
|
||||||
|
if(comdir == COMD_Left || comdir == COMD_Right) ScheduleCall(this, "ClearDir", 1, (Abs(GetYDir())+1)/2, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(comdir == COMD_UpRight || comdir == COMD_DownRight) comdir = COMD_Right;
|
||||||
|
if(comdir == COMD_Up || comdir == COMD_Down) comdir = COMD_Stop;
|
||||||
|
if(comdir == COMD_UpLeft || comdir == COMD_DownLeft) comdir = COMD_Left;
|
||||||
|
SetComDir(comdir);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected func ContainedThrow() { return 1; }
|
||||||
|
|
||||||
|
protected func ContainedDigDouble()
|
||||||
|
{
|
||||||
|
[$TxtLeave$]
|
||||||
|
RemoveEffect("PossessionSpell", this);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
func Definition(def) {
|
||||||
|
SetProperty("ActMap", {
|
||||||
|
Walk = {
|
||||||
|
Prototype = Action,
|
||||||
|
Name = "Walk",
|
||||||
|
Procedure = DFA_WALK,
|
||||||
|
Directions = 2,
|
||||||
|
FlipDir = 1,
|
||||||
|
Length = 16,
|
||||||
|
Delay = 5,
|
||||||
|
X = 0,
|
||||||
|
Y = 0,
|
||||||
|
Wdt = 48,
|
||||||
|
Hgt = 34,
|
||||||
|
NextAction = "Walk",
|
||||||
|
TurnAction = "Turn",
|
||||||
|
StartCall = "HitCheck",
|
||||||
|
InLiquidAction = "Swim",
|
||||||
|
Animation = "Walk",
|
||||||
|
},
|
||||||
|
Turn = {
|
||||||
|
Prototype = Action,
|
||||||
|
Name = "Turn",
|
||||||
|
Procedure = DFA_NONE,
|
||||||
|
Directions = 2,
|
||||||
|
FlipDir = 1,
|
||||||
|
Length = 7,
|
||||||
|
Delay = 2,
|
||||||
|
X = 0,
|
||||||
|
Y = 68,
|
||||||
|
Wdt = 48,
|
||||||
|
Hgt = 34,
|
||||||
|
NextAction = "Walk",
|
||||||
|
},
|
||||||
|
Jump = {
|
||||||
|
Prototype = Action,
|
||||||
|
Name = "Jump",
|
||||||
|
Procedure = DFA_FLIGHT,
|
||||||
|
Directions = 2,
|
||||||
|
FlipDir = 1,
|
||||||
|
Length = 17,
|
||||||
|
Delay = 1,
|
||||||
|
X = 0,
|
||||||
|
Y = 34,
|
||||||
|
Wdt = 48,
|
||||||
|
Hgt = 34,
|
||||||
|
NextAction = "Hold",
|
||||||
|
InLiquidAction = "Swim",
|
||||||
|
},
|
||||||
|
Swim = {
|
||||||
|
Prototype = Action,
|
||||||
|
Name = "Swim",
|
||||||
|
Procedure = DFA_SWIM,
|
||||||
|
Directions = 2,
|
||||||
|
FlipDir = 1,
|
||||||
|
Length = 16,
|
||||||
|
Delay = 5,
|
||||||
|
X = 0,
|
||||||
|
Y = 0,
|
||||||
|
Wdt = 48,
|
||||||
|
Hgt = 34,
|
||||||
|
NextAction = "Swim",
|
||||||
|
TurnAction = "Turn",
|
||||||
|
StartCall = "HitCheck",
|
||||||
|
},
|
||||||
|
LookUp = {
|
||||||
|
Prototype = Action,
|
||||||
|
Name = "LookUp",
|
||||||
|
Procedure = DFA_NONE,
|
||||||
|
Attach = 8,
|
||||||
|
Directions = 2,
|
||||||
|
FlipDir = 1,
|
||||||
|
Length = 12,
|
||||||
|
Delay = 1,
|
||||||
|
X = 0,
|
||||||
|
Y = 102,
|
||||||
|
Wdt = 48,
|
||||||
|
Hgt = 34,
|
||||||
|
NextAction = "Look",
|
||||||
|
InLiquidAction = "Swim",
|
||||||
|
},
|
||||||
|
Look = {
|
||||||
|
Prototype = Action,
|
||||||
|
Name = "Look",
|
||||||
|
Attach = 8,
|
||||||
|
Procedure = DFA_NONE,
|
||||||
|
Directions = 2,
|
||||||
|
FlipDir = 1,
|
||||||
|
Delay = 15,
|
||||||
|
X = 528,
|
||||||
|
Y = 102,
|
||||||
|
Wdt = 48,
|
||||||
|
Hgt = 34,
|
||||||
|
NextAction = "LookAway",
|
||||||
|
InLiquidAction = "Swim",
|
||||||
|
},
|
||||||
|
LookAway = {
|
||||||
|
Prototype = Action,
|
||||||
|
Name = "LookAway",
|
||||||
|
Attach = 8,
|
||||||
|
Procedure = DFA_NONE,
|
||||||
|
Directions = 2,
|
||||||
|
FlipDir = 1,
|
||||||
|
Length = 12,
|
||||||
|
Delay = 1,
|
||||||
|
Reverse = 1,
|
||||||
|
X = 0,
|
||||||
|
Y = 102,
|
||||||
|
Wdt = 48,
|
||||||
|
Hgt = 34,
|
||||||
|
NextAction = "Walk",
|
||||||
|
InLiquidAction = "Swim",
|
||||||
|
}, }, def);
|
||||||
|
SetProperty("Name", "$Name$", def);
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
TxtMovement=Bewegen
|
||||||
|
TxtLeave=Zurückverwandeln
|
||||||
|
Name=Monster
|
|
@ -0,0 +1,3 @@
|
||||||
|
TxtMovement=Move
|
||||||
|
TxtLeave=Retransform
|
||||||
|
Name=Monster
|
|
@ -0,0 +1,5 @@
|
||||||
|
#strict 2
|
||||||
|
func Initialize()
|
||||||
|
{
|
||||||
|
CreateObject(MONS, LandscapeWidth()/2, LandscapeHeight()/2);
|
||||||
|
}
|
|
@ -539,7 +539,7 @@ public:
|
||||||
operator const void *() const { return getData(); }
|
operator const void *() const { return getData(); }
|
||||||
|
|
||||||
// less-than operation for map
|
// less-than operation for map
|
||||||
inline bool operator <(const StdStrBuf &v2)
|
inline bool operator <(const StdStrBuf &v2) const
|
||||||
{
|
{
|
||||||
int iLen = getLength(), iLen2 = v2.getLength();
|
int iLen = getLength(), iLen2 = v2.getLength();
|
||||||
if (iLen == iLen2)
|
if (iLen == iLen2)
|
||||||
|
@ -676,6 +676,16 @@ public:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// const char* + StdStrBuf
|
||||||
|
inline StdStrBuf operator + (const char* szString, const StdStrBuf& Buf2)
|
||||||
|
{
|
||||||
|
StdStrBuf Buf(szString);
|
||||||
|
Buf.Append(Buf2);
|
||||||
|
return Buf;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Wrappers
|
// Wrappers
|
||||||
extern StdStrBuf FormatString(const char *szFmt, ...) GNUC_FORMAT_ATTRIBUTE;
|
extern StdStrBuf FormatString(const char *szFmt, ...) GNUC_FORMAT_ATTRIBUTE;
|
||||||
extern StdStrBuf FormatStringV(const char *szFmt, va_list args);
|
extern StdStrBuf FormatStringV(const char *szFmt, va_list args);
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <StdSurface8.h>
|
#include <StdSurface8.h>
|
||||||
#include <StdFont.h>
|
#include <StdFont.h>
|
||||||
#include <StdBuf.h>
|
#include <StdBuf.h>
|
||||||
|
#include <StdMesh.h>
|
||||||
|
|
||||||
// texref-predef
|
// texref-predef
|
||||||
class CStdDDraw;
|
class CStdDDraw;
|
||||||
|
@ -287,7 +288,9 @@ class CStdDDraw
|
||||||
BOOL Blit(SURFACE sfcSource, float fx, float fy, float fwdt, float fhgt,
|
BOOL Blit(SURFACE sfcSource, float fx, float fy, float fwdt, float fhgt,
|
||||||
SURFACE sfcTarget, float tx, float ty, float twdt, float thgt,
|
SURFACE sfcTarget, float tx, float ty, float twdt, float thgt,
|
||||||
BOOL fSrcColKey=FALSE, CBltTransform *pTransform=NULL);
|
BOOL fSrcColKey=FALSE, CBltTransform *pTransform=NULL);
|
||||||
|
BOOL RenderMesh(StdMeshInstance &instance, SURFACE sfcTarget, float tx, float ty, float twdt, float thgt, CBltTransform* pTransform);
|
||||||
virtual void PerformBlt(CBltData &rBltData, CTexRef *pTex, DWORD dwModClr, bool fMod2, bool fExact) = 0;
|
virtual void PerformBlt(CBltData &rBltData, CTexRef *pTex, DWORD dwModClr, bool fMod2, bool fExact) = 0;
|
||||||
|
virtual void PerformMesh(StdMeshInstance &instance, float tx, float ty, float twdt, float thgt, CBltTransform* pTransform) = 0;
|
||||||
BOOL Blit8(SURFACE sfcSource, int fx, int fy, int fwdt, int fhgt, // force 8bit-blit (inline)
|
BOOL Blit8(SURFACE sfcSource, int fx, int fy, int fwdt, int fhgt, // force 8bit-blit (inline)
|
||||||
SURFACE sfcTarget, int tx, int ty, int twdt, int thgt,
|
SURFACE sfcTarget, int tx, int ty, int twdt, int thgt,
|
||||||
BOOL fSrcColKey=FALSE, CBltTransform *pTransform=NULL);
|
BOOL fSrcColKey=FALSE, CBltTransform *pTransform=NULL);
|
||||||
|
|
|
@ -113,7 +113,8 @@ class CStdGL : public CStdDDraw
|
||||||
#endif
|
#endif
|
||||||
// Blit
|
// Blit
|
||||||
void SetupTextureEnv(bool fMod2, bool landscape);
|
void SetupTextureEnv(bool fMod2, bool landscape);
|
||||||
void PerformBlt(CBltData &rBltData, CTexRef *pTex, DWORD dwModClr, bool fMod2, bool fExact);
|
virtual void PerformBlt(CBltData &rBltData, CTexRef *pTex, DWORD dwModClr, bool fMod2, bool fExact);
|
||||||
|
virtual void PerformMesh(StdMeshInstance &instance, float tx, float ty, float twdt, float thgt, CBltTransform* pTransform);
|
||||||
virtual void BlitLandscape(SURFACE sfcSource, float fx, float fy,
|
virtual void BlitLandscape(SURFACE sfcSource, float fx, float fy,
|
||||||
SURFACE sfcTarget, float tx, float ty, float wdt, float hgt, const SURFACE textures[]);
|
SURFACE sfcTarget, float tx, float ty, float wdt, float hgt, const SURFACE textures[]);
|
||||||
void FillBG(DWORD dwClr=0);
|
void FillBG(DWORD dwClr=0);
|
||||||
|
|
|
@ -0,0 +1,271 @@
|
||||||
|
/*
|
||||||
|
* OpenClonk, http://www.openclonk.org
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Armin Burgmeier
|
||||||
|
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
|
||||||
|
*
|
||||||
|
* Portions might be copyrighted by other authors who have contributed
|
||||||
|
* to OpenClonk.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
* See isc_license.txt for full license and disclaimer.
|
||||||
|
*
|
||||||
|
* "Clonk" is a registered trademark of Matthes Bender.
|
||||||
|
* See clonk_trademark_license.txt for full license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_StdMesh
|
||||||
|
#define INC_StdMesh
|
||||||
|
|
||||||
|
#include <StdMeshMaterial.h>
|
||||||
|
|
||||||
|
// Loader for OGRE meshes. Currently supports XML files only.
|
||||||
|
|
||||||
|
class StdMeshError: public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StdMeshError(const StdStrBuf& message, const char* file, unsigned int line);
|
||||||
|
virtual ~StdMeshError() throw() {}
|
||||||
|
|
||||||
|
virtual const char* what() const throw() { return Buf.getData(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
StdStrBuf Buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Interface to load skeleton files. Given a filename occuring in the
|
||||||
|
// mesh file, this should load the skeleton file from wherever the mesh file
|
||||||
|
// was loaded from, for example from a C4Group. Return default-construted
|
||||||
|
// StdStrBuf with NULL data in case of error.
|
||||||
|
class StdMeshSkeletonLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual StdStrBuf LoadSkeleton(const char* filename) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StdMeshMatrix
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void SetIdentity();
|
||||||
|
void SetTranslate(float dx, float dy, float dz);
|
||||||
|
void SetScale(float sx, float sy, float sz);
|
||||||
|
void SetRotate(float angle, float rx, float ry, float rz);
|
||||||
|
|
||||||
|
float& operator()(int i, int j) { return a[i][j]; }
|
||||||
|
float operator()(int i, int j) const { return a[i][j]; }
|
||||||
|
|
||||||
|
// *this *= other
|
||||||
|
void Mul(const StdMeshMatrix& other);
|
||||||
|
void Mul(float f);
|
||||||
|
// *this += other
|
||||||
|
void Add(const StdMeshMatrix& other);
|
||||||
|
|
||||||
|
// *this = other * *this
|
||||||
|
void Transform(const StdMeshMatrix& other);
|
||||||
|
private:
|
||||||
|
// 3x3 orthogonal + translation in last column
|
||||||
|
float a[3][4];
|
||||||
|
};
|
||||||
|
|
||||||
|
class StdMeshBone
|
||||||
|
{
|
||||||
|
friend class StdMesh;
|
||||||
|
public:
|
||||||
|
StdMeshBone() {}
|
||||||
|
|
||||||
|
unsigned int Index; // Index in master bone table
|
||||||
|
int ID; // Bone ID
|
||||||
|
StdStrBuf Name; // Bone name
|
||||||
|
|
||||||
|
// Bone transformation
|
||||||
|
StdMeshMatrix Trans;
|
||||||
|
// Inverse transformation
|
||||||
|
StdMeshMatrix InverseTrans;
|
||||||
|
|
||||||
|
const StdMeshBone* GetParent() const { return Parent; }
|
||||||
|
|
||||||
|
const StdMeshBone& GetChild(unsigned int i) const { return *Children[i]; }
|
||||||
|
unsigned int GetNumChildren() const { return Children.size(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
StdMeshBone* Parent; // Parent bone
|
||||||
|
std::vector<StdMeshBone*> Children; // Children. Not owned.
|
||||||
|
|
||||||
|
StdMeshBone(const StdMeshBone&); // non-copyable
|
||||||
|
StdMeshBone& operator=(const StdMeshBone&); // non-assignable
|
||||||
|
};
|
||||||
|
|
||||||
|
class StdMeshVertexBoneAssignment
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
unsigned int BoneIndex;
|
||||||
|
float Weight;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StdMeshVertex
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
float x, y, z;
|
||||||
|
float nx, ny, nz;
|
||||||
|
float u, v;
|
||||||
|
|
||||||
|
// *this = trans * *this
|
||||||
|
void Transform(const StdMeshMatrix& trans);
|
||||||
|
|
||||||
|
// *this *= f;
|
||||||
|
void Mul(float f);
|
||||||
|
// *this += other;
|
||||||
|
void Add(const StdMeshVertex& other);
|
||||||
|
};
|
||||||
|
|
||||||
|
class StdMeshFace
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
unsigned int Vertices[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Keyframe, specifies transformation for one bone in a particular frame
|
||||||
|
class StdMeshKeyFrame
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StdMeshMatrix Trans;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Animation track, specifies transformation for one bone for each keyframe
|
||||||
|
class StdMeshTrack
|
||||||
|
{
|
||||||
|
friend class StdMesh;
|
||||||
|
public:
|
||||||
|
StdMeshMatrix GetTransformAt(float time) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<float, StdMeshKeyFrame> Frames;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Animation, consists of one Track for each animated Bone
|
||||||
|
class StdMeshAnimation
|
||||||
|
{
|
||||||
|
friend class StdMesh;
|
||||||
|
friend class StdMeshInstance;
|
||||||
|
public:
|
||||||
|
StdMeshAnimation() {}
|
||||||
|
StdMeshAnimation(const StdMeshAnimation& other);
|
||||||
|
~StdMeshAnimation();
|
||||||
|
|
||||||
|
StdMeshAnimation& operator=(const StdMeshAnimation& other);
|
||||||
|
|
||||||
|
StdStrBuf Name;
|
||||||
|
float Length;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<StdMeshTrack*> Tracks; // bone-indexed
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StdMeshBox
|
||||||
|
{
|
||||||
|
float x1, y1, z1;
|
||||||
|
float x2, y2, z2;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StdMesh
|
||||||
|
{
|
||||||
|
friend class StdMeshInstance;
|
||||||
|
public:
|
||||||
|
StdMesh();
|
||||||
|
~StdMesh();
|
||||||
|
|
||||||
|
// filename is only used to show it in error messages. The model is
|
||||||
|
// loaded from xml_data.
|
||||||
|
// Throws StdMeshError.
|
||||||
|
void InitXML(const char* filename, const char* xml_data, StdMeshSkeletonLoader& skel_loader, const StdMeshMatManager& manager);
|
||||||
|
|
||||||
|
const StdMeshVertex& GetVertex(unsigned int i) const { return Vertices[i]; }
|
||||||
|
unsigned int GetNumVertices() const { return Vertices.size(); }
|
||||||
|
|
||||||
|
const StdMeshFace& GetFace(unsigned int i) const { return Faces[i]; }
|
||||||
|
unsigned int GetNumFaces() const { return Faces.size(); }
|
||||||
|
|
||||||
|
const StdMeshBone& GetBone(unsigned int i) const { return *Bones[i]; }
|
||||||
|
unsigned int GetNumBones() const { return Bones.size(); }
|
||||||
|
|
||||||
|
const StdMeshAnimation* GetAnimationByName(const StdStrBuf& name) const;
|
||||||
|
const StdMeshMaterial& GetMaterial() const { return *Material; }
|
||||||
|
|
||||||
|
const StdMeshBox& GetBoundingBox() const { return BoundingBox; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void AddMasterBone(StdMeshBone* bone);
|
||||||
|
|
||||||
|
StdMesh(const StdMesh& other); // non-copyable
|
||||||
|
StdMesh& operator=(const StdMesh& other); // non-assignable
|
||||||
|
|
||||||
|
// Remember bone assignments for vertices
|
||||||
|
class Vertex: public StdMeshVertex
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<StdMeshVertexBoneAssignment> BoneAssignments;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Vertex> Vertices;
|
||||||
|
std::vector<StdMeshFace> Faces;
|
||||||
|
std::vector<StdMeshBone*> Bones; // Master Bone Table
|
||||||
|
|
||||||
|
std::map<StdStrBuf, StdMeshAnimation> Animations;
|
||||||
|
|
||||||
|
StdMeshBox BoundingBox;
|
||||||
|
const StdMeshMaterial* Material;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StdMeshInstance
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StdMeshInstance(const StdMesh& mesh);
|
||||||
|
|
||||||
|
enum FaceOrdering {
|
||||||
|
FO_Fixed, // don't reorder, keep faces as in mesh
|
||||||
|
FO_FarthestToNearest,
|
||||||
|
FO_NearestToFarthest
|
||||||
|
};
|
||||||
|
|
||||||
|
FaceOrdering GetFaceOrdering() const { return CurrentFaceOrdering; }
|
||||||
|
void SetFaceOrdering(FaceOrdering ordering);
|
||||||
|
|
||||||
|
bool SetAnimationByName(const StdStrBuf& animation_name);
|
||||||
|
void SetAnimation(const StdMeshAnimation& animation);
|
||||||
|
void UnsetAnimation();
|
||||||
|
|
||||||
|
const StdMeshAnimation* GetAnimation() const { return Animation; }
|
||||||
|
|
||||||
|
void SetPosition(float position);
|
||||||
|
float GetPosition() const { return Position; }
|
||||||
|
|
||||||
|
// Get vertex of instance, with current animation applied. This needs to
|
||||||
|
// go elsewhere if/when we want to calculate this on the hardware.
|
||||||
|
const StdMeshVertex& GetVertex(unsigned int i) const { return Vertices[i]; }
|
||||||
|
unsigned int GetNumVertices() const { return Vertices.size(); }
|
||||||
|
|
||||||
|
// Get face of instance. The instance faces are the same as the mesh faces,
|
||||||
|
// with the exception that they are differently ordered, depending on the
|
||||||
|
// current FaceOrdering. See also SetFaceOrdering.
|
||||||
|
const StdMeshFace& GetFace(unsigned int i) const { return *Faces[i]; }
|
||||||
|
unsigned int GetNumFaces() const { return Faces.size(); }
|
||||||
|
|
||||||
|
const StdMesh& Mesh;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void ReorderFaces();
|
||||||
|
|
||||||
|
FaceOrdering CurrentFaceOrdering;
|
||||||
|
const StdMeshAnimation* Animation;
|
||||||
|
float Position;
|
||||||
|
|
||||||
|
std::vector<StdMeshMatrix> BoneTransforms;
|
||||||
|
std::vector<StdMeshVertex> Vertices;
|
||||||
|
std::vector<const StdMeshFace*> Faces;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// vim: et ts=2 sw=2
|
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* OpenClonk, http://www.openclonk.org
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Armin Burgmeier
|
||||||
|
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
|
||||||
|
*
|
||||||
|
* Portions might be copyrighted by other authors who have contributed
|
||||||
|
* to OpenClonk.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
* See isc_license.txt for full license and disclaimer.
|
||||||
|
*
|
||||||
|
* "Clonk" is a registered trademark of Matthes Bender.
|
||||||
|
* See clonk_trademark_license.txt for full license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_StdMeshMaterial
|
||||||
|
#define INC_StdMeshMaterial
|
||||||
|
|
||||||
|
#include <Standard.h>
|
||||||
|
#include <StdBuf.h>
|
||||||
|
#include <StdPNG.h>
|
||||||
|
#include <StdSurface2.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
// TODO: Support more features of OGRE material scripts
|
||||||
|
// Refer to http://www.ogre3d.org/docs/manual/manual_14.html
|
||||||
|
|
||||||
|
class StdMeshMaterialParserCtx;
|
||||||
|
|
||||||
|
class StdMeshMaterialError: public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StdMeshMaterialError(const StdStrBuf& message, const char* file, unsigned int line);
|
||||||
|
virtual ~StdMeshMaterialError() throw() {}
|
||||||
|
|
||||||
|
virtual const char* what() const throw() { return Buf.getData(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
StdStrBuf Buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Interface to load textures. Given a texture filename occuring in the
|
||||||
|
// material script, this should load the texture from wherever the material
|
||||||
|
// script is actually loaded, for example from a C4Group.
|
||||||
|
class StdMeshMaterialTextureLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual bool LoadTexture(const char* filename, CPNGFile& dest) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StdMeshMaterialTextureUnit
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Ref-counted texture. When a meterial inherits from one which contains
|
||||||
|
// a TextureUnit, then they will share the same CTexRef.
|
||||||
|
class TexRef
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TexRef(unsigned int size);
|
||||||
|
~TexRef();
|
||||||
|
|
||||||
|
unsigned int RefCount;
|
||||||
|
CTexRef Tex;
|
||||||
|
};
|
||||||
|
|
||||||
|
StdMeshMaterialTextureUnit();
|
||||||
|
StdMeshMaterialTextureUnit(const StdMeshMaterialTextureUnit& other);
|
||||||
|
~StdMeshMaterialTextureUnit();
|
||||||
|
|
||||||
|
StdMeshMaterialTextureUnit& operator=(const StdMeshMaterialTextureUnit&);
|
||||||
|
|
||||||
|
void Load(StdMeshMaterialParserCtx& ctx);
|
||||||
|
|
||||||
|
const CTexRef& GetTexture() const { return Texture->Tex; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
TexRef* Texture;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StdMeshMaterialPass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StdMeshMaterialPass();
|
||||||
|
void Load(StdMeshMaterialParserCtx& ctx);
|
||||||
|
|
||||||
|
std::vector<StdMeshMaterialTextureUnit> TextureUnits;
|
||||||
|
|
||||||
|
float Ambient[4];
|
||||||
|
float Diffuse[4];
|
||||||
|
float Specular[4];
|
||||||
|
float Emissive[4];
|
||||||
|
float Shininess;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StdMeshMaterialTechnique
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Load(StdMeshMaterialParserCtx& ctx);
|
||||||
|
|
||||||
|
std::vector<StdMeshMaterialPass> Passes;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StdMeshMaterial
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StdMeshMaterial();
|
||||||
|
void Load(StdMeshMaterialParserCtx& ctx);
|
||||||
|
|
||||||
|
// Location the Material was loaded from
|
||||||
|
StdStrBuf FileName;
|
||||||
|
unsigned int Line;
|
||||||
|
|
||||||
|
// Material name
|
||||||
|
StdStrBuf Name;
|
||||||
|
|
||||||
|
// Not currently used in Clonk, but don't fail when we see this in a
|
||||||
|
// Material script:
|
||||||
|
bool ReceiveShadows;
|
||||||
|
|
||||||
|
// Available techniques
|
||||||
|
std::vector<StdMeshMaterialTechnique> Techniques;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StdMeshMatManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Remove all materials from manager. Make sure there is no StdMesh
|
||||||
|
// referencing any out there before calling this.
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
// Parse a material script file, and add the materials to the manager.
|
||||||
|
// filename may be NULL if the source is not a file. It will only be used
|
||||||
|
// for error messages.
|
||||||
|
// Throws StdMeshMaterialError.
|
||||||
|
void Parse(const char* mat_script, const char* filename, StdMeshMaterialTextureLoader& tex_loader);
|
||||||
|
|
||||||
|
// Get material by name. NULL if there is no such material with this name.
|
||||||
|
const StdMeshMaterial* GetMaterial(const char* material_name) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<StdStrBuf, StdMeshMaterial> Materials;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// vim: et ts=2 sw=2
|
|
@ -40,6 +40,7 @@ public:
|
||||||
virtual bool PrepareRendering(SURFACE) { return true; }
|
virtual bool PrepareRendering(SURFACE) { return true; }
|
||||||
virtual void FillBG(DWORD dwClr=0) { }
|
virtual void FillBG(DWORD dwClr=0) { }
|
||||||
virtual void PerformBlt(CBltData &, CTexRef *, DWORD, bool, bool) { }
|
virtual void PerformBlt(CBltData &, CTexRef *, DWORD, bool, bool) { }
|
||||||
|
virtual void PerformMesh(StdMeshInstance &, float, float, float, float, CBltTransform* pTransform) { }
|
||||||
virtual void PerformLine(SURFACE, float, float, float, float, DWORD) { }
|
virtual void PerformLine(SURFACE, float, float, float, float, DWORD) { }
|
||||||
virtual void DrawQuadDw(SURFACE, float *, DWORD, DWORD, DWORD, DWORD) { }
|
virtual void DrawQuadDw(SURFACE, float *, DWORD, DWORD, DWORD, DWORD) { }
|
||||||
virtual void PerformPix(SURFACE, float, float, DWORD) { }
|
virtual void PerformPix(SURFACE, float, float, DWORD) { }
|
||||||
|
|
|
@ -1028,6 +1028,22 @@ BOOL CStdDDraw::Blit(SURFACE sfcSource, float fx, float fy, float fwdt, float fh
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL CStdDDraw::RenderMesh(StdMeshInstance &instance, SURFACE sfcTarget, float tx, float ty, float twdt, float thgt, CBltTransform* pTransform)
|
||||||
|
{
|
||||||
|
// TODO: Emulate rendering
|
||||||
|
if (!sfcTarget->IsRenderTarget()) return FALSE;
|
||||||
|
|
||||||
|
// TODO: Clip
|
||||||
|
|
||||||
|
// prepare rendering to surface
|
||||||
|
if (!PrepareRendering(sfcTarget)) return FALSE;
|
||||||
|
|
||||||
|
PerformMesh(instance, tx, ty, twdt, thgt, pTransform);
|
||||||
|
|
||||||
|
// success
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
BOOL CStdDDraw::Blit8(SURFACE sfcSource, int fx, int fy, int fwdt, int fhgt,
|
BOOL CStdDDraw::Blit8(SURFACE sfcSource, int fx, int fy, int fwdt, int fhgt,
|
||||||
SURFACE sfcTarget, int tx, int ty, int twdt, int thgt,
|
SURFACE sfcTarget, int tx, int ty, int twdt, int thgt,
|
||||||
BOOL fSrcColKey, CBltTransform *pTransform)
|
BOOL fSrcColKey, CBltTransform *pTransform)
|
||||||
|
|
|
@ -307,6 +307,150 @@ void CStdGL::PerformBlt(CBltData &rBltData, CTexRef *pTex, DWORD dwModClr, bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
void RenderMeshVertex(const StdMeshVertex& vtx, const StdMeshMaterialPass& pass, CBltTransform* pTransform, CClrModAddMap* pClrModMap, DWORD dwModClr)
|
||||||
|
{
|
||||||
|
// TODO: We might also want to modulate emissive
|
||||||
|
float Ambient[4];
|
||||||
|
float Diffuse[4];
|
||||||
|
float Specular[4];
|
||||||
|
|
||||||
|
float x = vtx.x;
|
||||||
|
float y = vtx.y;
|
||||||
|
pTransform->TransformPoint(x, y);
|
||||||
|
DWORD dwClr = pClrModMap ? pClrModMap->GetModAt(x, y) : 0xffffff;
|
||||||
|
ModulateClr(dwClr, dwModClr);
|
||||||
|
|
||||||
|
Ambient[0] = pass.Ambient[0] * ((dwClr >> 16) & 0xff) / 255.0f;
|
||||||
|
Ambient[1] = pass.Ambient[1] * ((dwClr >> 8) & 0xff) / 255.0f;
|
||||||
|
Ambient[2] = pass.Ambient[2] * ((dwClr ) & 0xff) / 255.0f;
|
||||||
|
Ambient[3] = 1 - ((1-pass.Ambient[3]) * (1-((dwClr >> 24) & 0xff) / 255.0f));
|
||||||
|
|
||||||
|
Diffuse[0] = pass.Diffuse[0] * ((dwClr >> 16) & 0xff) / 255.0f;
|
||||||
|
Diffuse[1] = pass.Diffuse[1] * ((dwClr >> 8) & 0xff) / 255.0f;
|
||||||
|
Diffuse[2] = pass.Diffuse[2] * ((dwClr ) & 0xff) / 255.0f;
|
||||||
|
Diffuse[3] = 1 - ((1-pass.Diffuse[3]) * (1-((dwClr >> 24) & 0xff) / 255.0f));
|
||||||
|
|
||||||
|
Specular[0] = pass.Specular[0] * ((dwClr >> 16) & 0xff) / 255.0f;
|
||||||
|
Specular[1] = pass.Specular[1] * ((dwClr >> 8) & 0xff) / 255.0f;
|
||||||
|
Specular[2] = pass.Specular[2] * ((dwClr ) & 0xff) / 255.0f;
|
||||||
|
Specular[3] = 1 - ((1-pass.Specular[3]) * (1-((dwClr >> 24) & 0xff) / 255.0f));
|
||||||
|
|
||||||
|
glMaterialfv(GL_FRONT, GL_AMBIENT, Ambient);
|
||||||
|
glMaterialfv(GL_FRONT, GL_DIFFUSE, Diffuse);
|
||||||
|
glMaterialfv(GL_FRONT, GL_SPECULAR, Specular);
|
||||||
|
|
||||||
|
glTexCoord2f(vtx.u, vtx.v);
|
||||||
|
glTexCoord2f(vtx.u, vtx.v);
|
||||||
|
glNormal3f(vtx.nx, vtx.ny, vtx.nz);
|
||||||
|
glVertex3f(vtx.x, vtx.y, vtx.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStdGL::PerformMesh(StdMeshInstance &instance, float tx, float ty, float twdt, float thgt, CBltTransform* pTransform)
|
||||||
|
{
|
||||||
|
const StdMesh& mesh = instance.Mesh;
|
||||||
|
const StdMeshBox& box = mesh.GetBoundingBox();
|
||||||
|
|
||||||
|
glPushMatrix();
|
||||||
|
glShadeModel(GL_SMOOTH);
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glEnable(GL_LIGHTING);
|
||||||
|
|
||||||
|
// Apply zoom
|
||||||
|
glTranslatef(ZoomX, ZoomY, 0.0f);
|
||||||
|
glScalef(Zoom, Zoom, 1.0f);
|
||||||
|
glTranslatef(-ZoomX, -ZoomY, 0.0f);
|
||||||
|
|
||||||
|
if(pTransform)
|
||||||
|
{
|
||||||
|
const GLfloat transform[16] = { pTransform->mat[0], pTransform->mat[3], 0, pTransform->mat[6], pTransform->mat[1], pTransform->mat[4], 0, pTransform->mat[7], 0, 0, 1, 0, pTransform->mat[2], pTransform->mat[5], 0, pTransform->mat[8] };
|
||||||
|
glMultMatrixf(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale so that the mesh fits in (tx,ty,twdt,thgt)
|
||||||
|
const float rx = -box.x1 / (box.x2 - box.x1);
|
||||||
|
const float ry = -box.y1 / (box.y2 - box.y1);
|
||||||
|
const float dx = tx + rx*twdt;
|
||||||
|
const float dy = ty + ry*thgt;
|
||||||
|
const float scx = twdt/(box.x2 - box.x1);
|
||||||
|
const float scy = thgt/(box.y2 - box.y1);
|
||||||
|
// Keep aspect ratio:
|
||||||
|
//if(scx < scy) scy = scx;
|
||||||
|
//else scx = scy;
|
||||||
|
glTranslatef(dx, dy, 0.0f);
|
||||||
|
glScalef(scx, scy, 1.0f);
|
||||||
|
|
||||||
|
// Put a light source in front of the object
|
||||||
|
const GLfloat light_position[] = { 0.0f, 0.0f, 15.0f*Zoom, 1.0f };
|
||||||
|
glEnable(GL_LIGHT0);
|
||||||
|
|
||||||
|
// TODO: Find a working technique, we currently always use the
|
||||||
|
// first one:
|
||||||
|
const StdMeshMaterial& material = mesh.GetMaterial();
|
||||||
|
const StdMeshMaterialTechnique& technique = material.Techniques[0];
|
||||||
|
|
||||||
|
// Create a transformation which transfers a vertex from mesh
|
||||||
|
// coordinates to screen coordinates. This is basically the same
|
||||||
|
// as the current GL modelview matrix, but we need it to access the
|
||||||
|
// ClrModMap for each vertex with the correct coordinates.
|
||||||
|
CBltTransform Transform;
|
||||||
|
Transform.SetMoveScale(dx, dy, scx, scy);
|
||||||
|
if(pTransform) Transform *= *pTransform;
|
||||||
|
|
||||||
|
CClrModAddMap* ClrModMap = fUseClrModMap ? pClrModMap : NULL;
|
||||||
|
DWORD dwModClr = BlitModulated ? BlitModulateClr : 0xffffff;
|
||||||
|
|
||||||
|
// Render each pass
|
||||||
|
for(unsigned int i = 0; i < technique.Passes.size(); ++i)
|
||||||
|
{
|
||||||
|
const StdMeshMaterialPass& pass = technique.Passes[i];
|
||||||
|
|
||||||
|
// Set up material
|
||||||
|
#if 0
|
||||||
|
glMaterialfv(GL_FRONT, GL_AMBIENT, pass.Ambient);
|
||||||
|
glMaterialfv(GL_FRONT, GL_DIFFUSE, pass.Diffuse);
|
||||||
|
glMaterialfv(GL_FRONT, GL_SPECULAR, pass.Specular);
|
||||||
|
#endif
|
||||||
|
glMaterialfv(GL_FRONT, GL_EMISSION, pass.Emissive);
|
||||||
|
glMaterialf(GL_FRONT, GL_SHININESS, pass.Shininess);
|
||||||
|
|
||||||
|
// TODO: Set up texture units
|
||||||
|
|
||||||
|
// Render mesh
|
||||||
|
// TODO: Use glInterleavedArrays? Hm, might be impossible as
|
||||||
|
// we need to set material for each vertex. Can't use
|
||||||
|
// glMaterialColor either, because we set all diffuse, ambient
|
||||||
|
// and specular material...
|
||||||
|
// TODO: We might not want to calculate the material for each
|
||||||
|
// vertex separately. This looks odd when the mesh is moving
|
||||||
|
// at FoW borders anyway.
|
||||||
|
glBegin(GL_TRIANGLES);
|
||||||
|
for(unsigned int j = 0; j < instance.GetNumFaces(); ++j)
|
||||||
|
{
|
||||||
|
const StdMeshFace& face = instance.GetFace(j);
|
||||||
|
const StdMeshVertex& vtx1 = instance.GetVertex(face.Vertices[0]);
|
||||||
|
const StdMeshVertex& vtx2 = instance.GetVertex(face.Vertices[1]);
|
||||||
|
const StdMeshVertex& vtx3 = instance.GetVertex(face.Vertices[2]);
|
||||||
|
|
||||||
|
RenderMeshVertex(vtx1, pass, &Transform, ClrModMap, dwModClr);
|
||||||
|
RenderMeshVertex(vtx2, pass, &Transform, ClrModMap, dwModClr);
|
||||||
|
RenderMeshVertex(vtx3, pass, &Transform, ClrModMap, dwModClr);
|
||||||
|
}
|
||||||
|
glEnd(); // GL_TRIANGLES
|
||||||
|
}
|
||||||
|
|
||||||
|
glDisable(GL_LIGHT0);
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glShadeModel(GL_FLAT);
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
// TODO: glScissor, so that we only clear the area the mesh covered.
|
||||||
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
void CStdGL::BlitLandscape(SURFACE sfcSource, float fx, float fy,
|
void CStdGL::BlitLandscape(SURFACE sfcSource, float fx, float fy,
|
||||||
SURFACE sfcTarget, float tx, float ty, float wdt, float hgt, const SURFACE mattextures[])
|
SURFACE sfcTarget, float tx, float ty, float wdt, float hgt, const SURFACE mattextures[])
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,6 +36,7 @@ void CStdGLCtx::SelectCommon()
|
||||||
pGL->lpPrimary->Wdt=cx; pGL->lpPrimary->Hgt=cy;
|
pGL->lpPrimary->Wdt=cx; pGL->lpPrimary->Hgt=cy;
|
||||||
// set some default states
|
// set some default states
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDepthFunc(GL_LESS);
|
||||||
glShadeModel(GL_FLAT);
|
glShadeModel(GL_FLAT);
|
||||||
glDisable(GL_ALPHA_TEST);
|
glDisable(GL_ALPHA_TEST);
|
||||||
glDisable(GL_CULL_FACE);
|
glDisable(GL_CULL_FACE);
|
||||||
|
|
|
@ -0,0 +1,843 @@
|
||||||
|
/*
|
||||||
|
* OpenClonk, http://www.openclonk.org
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Armin Burgmeier
|
||||||
|
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
|
||||||
|
*
|
||||||
|
* Portions might be copyrighted by other authors who have contributed
|
||||||
|
* to OpenClonk.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
* See isc_license.txt for full license and disclaimer.
|
||||||
|
*
|
||||||
|
* "Clonk" is a registered trademark of Matthes Bender.
|
||||||
|
* See clonk_trademark_license.txt for full license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <StdMesh.h>
|
||||||
|
|
||||||
|
#include <tinyxml/tinyxml.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// Helper to sort faces for FaceOrdering
|
||||||
|
struct StdMeshInstanceFaceOrderingCmpPred
|
||||||
|
{
|
||||||
|
const StdMeshInstance& m_inst;
|
||||||
|
StdMeshInstanceFaceOrderingCmpPred(const StdMeshInstance& inst):
|
||||||
|
m_inst(inst) {}
|
||||||
|
|
||||||
|
bool operator()(const StdMeshFace* face1, const StdMeshFace* face2) const
|
||||||
|
{
|
||||||
|
switch(m_inst.GetFaceOrdering())
|
||||||
|
{
|
||||||
|
case StdMeshInstance::FO_Fixed:
|
||||||
|
// Faces are in a vector, thus contiuous in memory
|
||||||
|
return face1 < face2; // TODO: face1 > face2?
|
||||||
|
case StdMeshInstance::FO_FarthestToNearest:
|
||||||
|
case StdMeshInstance::FO_NearestToFarthest:
|
||||||
|
{
|
||||||
|
float z1 = m_inst.GetVertex(face1->Vertices[0]).z + m_inst.GetVertex(face1->Vertices[1]).z + m_inst.GetVertex(face1->Vertices[2]).z;
|
||||||
|
float z2 = m_inst.GetVertex(face2->Vertices[0]).z + m_inst.GetVertex(face2->Vertices[1]).z + m_inst.GetVertex(face2->Vertices[2]).z;
|
||||||
|
if(m_inst.GetFaceOrdering() == StdMeshInstance::FO_FarthestToNearest)
|
||||||
|
return z1 < z2;
|
||||||
|
else
|
||||||
|
return z2 < z1;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate matrix to convert the mesh from Ogre coordinate system to Clonk
|
||||||
|
// coordinate system. When making changes here, don't forget to make
|
||||||
|
// corresponding changes for the inverse matrix below.
|
||||||
|
StdMeshMatrix CoordCorrectionMatrix()
|
||||||
|
{
|
||||||
|
StdMeshMatrix matrix;
|
||||||
|
StdMeshMatrix helper;
|
||||||
|
|
||||||
|
//matrix.SetIdentity();
|
||||||
|
matrix.SetScale(-1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
|
//helper.SetRotate(M_PI/2.0f, 1.0f, 0.0f, 0.0f);
|
||||||
|
helper.SetRotate(M_PI/2.0f, 1.0f, 0.0f, 0.0f);
|
||||||
|
matrix.Mul(helper);
|
||||||
|
|
||||||
|
helper.SetRotate(M_PI/2.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
matrix.Mul(helper);
|
||||||
|
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
StdMeshMatrix CoordCorrectionMatrixInverse()
|
||||||
|
{
|
||||||
|
StdMeshMatrix matrix;
|
||||||
|
StdMeshMatrix helper;
|
||||||
|
|
||||||
|
matrix.SetRotate(-M_PI/2.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
//helper.SetRotate(-M_PI/2.0f, 1.0f, 0.0f, 0.0f);
|
||||||
|
helper.SetRotate(-M_PI/2.0f, 1.0f, 0.0f, 0.0f);
|
||||||
|
matrix.Mul(helper);
|
||||||
|
|
||||||
|
//helper.SetIdentity();
|
||||||
|
helper.SetScale(-1.0f, 1.0f, 1.0f);
|
||||||
|
matrix.Mul(helper);
|
||||||
|
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
StdMeshMatrix CoordCorrection = CoordCorrectionMatrix();
|
||||||
|
StdMeshMatrix CoordCorrectionInverse = CoordCorrectionMatrixInverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
StdMeshError::StdMeshError(const StdStrBuf& message, const char* file, unsigned int line)
|
||||||
|
{
|
||||||
|
Buf.Format("%s:%u: %s", file, line, message.getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper class to load things from an XML file with error checking
|
||||||
|
class StdMeshXML
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StdMeshXML(const char* filename, const char* xml_data);
|
||||||
|
|
||||||
|
const char* RequireStrAttribute(TiXmlElement* element, const char* attribute) const;
|
||||||
|
int RequireIntAttribute(TiXmlElement* element, const char* attribute) const;
|
||||||
|
float RequireFloatAttribute(TiXmlElement* element, const char* attribute) const;
|
||||||
|
|
||||||
|
TiXmlElement* RequireFirstChild(TiXmlElement* element, const char* child);
|
||||||
|
|
||||||
|
void Error(const StdStrBuf& message, TiXmlElement* element) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TiXmlDocument Document;
|
||||||
|
StdStrBuf FileName;
|
||||||
|
};
|
||||||
|
|
||||||
|
StdMeshXML::StdMeshXML(const char* filename, const char* xml_data):
|
||||||
|
FileName(filename)
|
||||||
|
{
|
||||||
|
Document.Parse(xml_data);
|
||||||
|
if(Document.Error())
|
||||||
|
throw StdMeshError(StdStrBuf(Document.ErrorDesc()), FileName.getData(), Document.ErrorRow());
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* StdMeshXML::RequireStrAttribute(TiXmlElement* element, const char* attribute) const
|
||||||
|
{
|
||||||
|
const char* value = element->Attribute(attribute);
|
||||||
|
if(!value) Error(FormatString("Element '%s' does not have attribute '%s'", element->Value(), attribute), element);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int StdMeshXML::RequireIntAttribute(TiXmlElement* element, const char* attribute) const
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
if(element->QueryIntAttribute(attribute, &retval) != TIXML_SUCCESS)
|
||||||
|
Error(FormatString("Element '%s' does not have integer attribute '%s'", element->Value(), attribute), element);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
float StdMeshXML::RequireFloatAttribute(TiXmlElement* element, const char* attribute) const
|
||||||
|
{
|
||||||
|
float retval;
|
||||||
|
if(element->QueryFloatAttribute(attribute, &retval) != TIXML_SUCCESS)
|
||||||
|
Error(FormatString("Element '%s' does not have integer attribute '%s'", element->Value(), attribute), element);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
TiXmlElement* StdMeshXML::RequireFirstChild(TiXmlElement* element, const char* child)
|
||||||
|
{
|
||||||
|
TiXmlElement* retval;
|
||||||
|
|
||||||
|
if(element)
|
||||||
|
{
|
||||||
|
retval = element->FirstChildElement(child);
|
||||||
|
if(!retval)
|
||||||
|
Error(FormatString("Element '%s' does not contain '%s' child", element->Value(), child), element);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retval = Document.RootElement();
|
||||||
|
if(strcmp(retval->Value(), child) != 0)
|
||||||
|
Error(FormatString("Root element is not '%s'", child), retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshXML::Error(const StdStrBuf& message, TiXmlElement* element) const
|
||||||
|
{
|
||||||
|
throw StdMeshError(message, FileName.getData(), element->Row());
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshMatrix::SetIdentity()
|
||||||
|
{
|
||||||
|
a[0][0] = 1.0f; a[0][1] = 0.0f; a[0][2] = 0.0f; a[0][3] = 0.0f;
|
||||||
|
a[1][0] = 0.0f; a[1][1] = 1.0f; a[1][2] = 0.0f; a[1][3] = 0.0f;
|
||||||
|
a[2][0] = 0.0f; a[2][1] = 0.0f; a[2][2] = 1.0f; a[2][3] = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshMatrix::SetTranslate(float dx, float dy, float dz)
|
||||||
|
{
|
||||||
|
a[0][0] = 1.0f; a[0][1] = 0.0f; a[0][2] = 0.0f; a[0][3] = dx;
|
||||||
|
a[1][0] = 0.0f; a[1][1] = 1.0f; a[1][2] = 0.0f; a[1][3] = dy;
|
||||||
|
a[2][0] = 0.0f; a[2][1] = 0.0f; a[2][2] = 1.0f; a[2][3] = dz;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshMatrix::SetScale(float sx, float sy, float sz)
|
||||||
|
{
|
||||||
|
a[0][0] = sx; a[0][1] = 0.0f; a[0][2] = 0.0f; a[0][3] = 0.0f;
|
||||||
|
a[1][0] = 0.0f; a[1][1] = sy; a[1][2] = 0.0f; a[1][3] = 0.0f;
|
||||||
|
a[2][0] = 0.0f; a[2][1] = 0.0f; a[2][2] = sz; a[2][3] = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshMatrix::SetRotate(float angle, float rx, float ry, float rz)
|
||||||
|
{
|
||||||
|
// We do normalize the rx,ry,rz vector here: This is only required for
|
||||||
|
// precalculations anyway, thus not time-critical.
|
||||||
|
float abs = sqrt(rx*rx+ry*ry+rz*rz);
|
||||||
|
rx/=abs; ry/=abs; rz/=abs;
|
||||||
|
float c = cos(angle), s = sin(angle);
|
||||||
|
|
||||||
|
a[0][0] = rx*rx*(1-c)+c; a[0][1] = rx*ry*(1-c)-rz*s; a[0][2] = rx*rz*(1-c)+ry*s; a[0][3] = 0.0f;
|
||||||
|
a[1][0] = ry*rx*(1-c)+rz*s; a[1][1] = ry*ry*(1-c)+c; a[1][2] = ry*rz*(1-c)-rx*s; a[1][3] = 0.0f;
|
||||||
|
a[2][0] = rz*rx*(1-c)-ry*s; a[2][1] = ry*rz*(1-c)+rx*s; a[2][2] = rz*rz*(1-c)+c; a[2][3] = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshMatrix::Mul(const StdMeshMatrix& other)
|
||||||
|
{
|
||||||
|
StdMeshMatrix old(*this);
|
||||||
|
|
||||||
|
a[0][0] = old.a[0][0]*other.a[0][0] + old.a[0][1]*other.a[1][0] + old.a[0][2]*other.a[2][0];
|
||||||
|
a[1][0] = old.a[1][0]*other.a[0][0] + old.a[1][1]*other.a[1][0] + old.a[1][2]*other.a[2][0];
|
||||||
|
a[2][0] = old.a[2][0]*other.a[0][0] + old.a[2][1]*other.a[1][0] + old.a[2][2]*other.a[2][0];
|
||||||
|
|
||||||
|
a[0][1] = old.a[0][0]*other.a[0][1] + old.a[0][1]*other.a[1][1] + old.a[0][2]*other.a[2][1];
|
||||||
|
a[1][1] = old.a[1][0]*other.a[0][1] + old.a[1][1]*other.a[1][1] + old.a[1][2]*other.a[2][1];
|
||||||
|
a[2][1] = old.a[2][0]*other.a[0][1] + old.a[2][1]*other.a[1][1] + old.a[2][2]*other.a[2][1];
|
||||||
|
|
||||||
|
a[0][2] = old.a[0][0]*other.a[0][2] + old.a[0][1]*other.a[1][2] + old.a[0][2]*other.a[2][2];
|
||||||
|
a[1][2] = old.a[1][0]*other.a[0][2] + old.a[1][1]*other.a[1][2] + old.a[1][2]*other.a[2][2];
|
||||||
|
a[2][2] = old.a[2][0]*other.a[0][2] + old.a[2][1]*other.a[1][2] + old.a[2][2]*other.a[2][2];
|
||||||
|
|
||||||
|
a[0][3] = old.a[0][0]*other.a[0][3] + old.a[0][1]*other.a[1][3] + old.a[0][2]*other.a[2][3] + old.a[0][3];
|
||||||
|
a[1][3] = old.a[1][0]*other.a[0][3] + old.a[1][1]*other.a[1][3] + old.a[1][2]*other.a[2][3] + old.a[1][3];
|
||||||
|
a[2][3] = old.a[2][0]*other.a[0][3] + old.a[2][1]*other.a[1][3] + old.a[2][2]*other.a[2][3] + old.a[2][3];
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshMatrix::Mul(float f)
|
||||||
|
{
|
||||||
|
a[0][0] *= f;
|
||||||
|
a[0][1] *= f;
|
||||||
|
a[0][2] *= f;
|
||||||
|
a[0][3] *= f;
|
||||||
|
a[1][0] *= f;
|
||||||
|
a[1][1] *= f;
|
||||||
|
a[1][2] *= f;
|
||||||
|
a[1][3] *= f;
|
||||||
|
a[2][0] *= f;
|
||||||
|
a[2][1] *= f;
|
||||||
|
a[2][2] *= f;
|
||||||
|
a[2][3] *= f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshMatrix::Add(const StdMeshMatrix& other)
|
||||||
|
{
|
||||||
|
a[0][0] += other.a[0][0];
|
||||||
|
a[0][1] += other.a[0][1];
|
||||||
|
a[0][2] += other.a[0][2];
|
||||||
|
a[0][3] += other.a[0][3];
|
||||||
|
a[1][0] += other.a[1][0];
|
||||||
|
a[1][1] += other.a[1][1];
|
||||||
|
a[1][2] += other.a[1][2];
|
||||||
|
a[1][3] += other.a[1][3];
|
||||||
|
a[2][0] += other.a[2][0];
|
||||||
|
a[2][1] += other.a[2][1];
|
||||||
|
a[2][2] += other.a[2][2];
|
||||||
|
a[2][3] += other.a[2][3];
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshMatrix::Transform(const StdMeshMatrix& other)
|
||||||
|
{
|
||||||
|
StdMeshMatrix old(*this);
|
||||||
|
|
||||||
|
a[0][0] = other.a[0][0]*old.a[0][0] + other.a[0][1]*old.a[1][0] + other.a[0][2]*old.a[2][0];
|
||||||
|
a[1][0] = other.a[1][0]*old.a[0][0] + other.a[1][1]*old.a[1][0] + other.a[1][2]*old.a[2][0];
|
||||||
|
a[2][0] = other.a[2][0]*old.a[0][0] + other.a[2][1]*old.a[1][0] + other.a[2][2]*old.a[2][0];
|
||||||
|
|
||||||
|
a[0][1] = other.a[0][0]*old.a[0][1] + other.a[0][1]*old.a[1][1] + other.a[0][2]*old.a[2][1];
|
||||||
|
a[1][1] = other.a[1][0]*old.a[0][1] + other.a[1][1]*old.a[1][1] + other.a[1][2]*old.a[2][1];
|
||||||
|
a[2][1] = other.a[2][0]*old.a[0][1] + other.a[2][1]*old.a[1][1] + other.a[2][2]*old.a[2][1];
|
||||||
|
|
||||||
|
a[0][2] = other.a[0][0]*old.a[0][2] + other.a[0][1]*old.a[1][2] + other.a[0][2]*old.a[2][2];
|
||||||
|
a[1][2] = other.a[1][0]*old.a[0][2] + other.a[1][1]*old.a[1][2] + other.a[1][2]*old.a[2][2];
|
||||||
|
a[2][2] = other.a[2][0]*old.a[0][2] + other.a[2][1]*old.a[1][2] + other.a[2][2]*old.a[2][2];
|
||||||
|
|
||||||
|
a[0][3] = other.a[0][0]*old.a[0][3] + other.a[0][1]*old.a[1][3] + other.a[0][2]*old.a[2][3] + other.a[0][3];
|
||||||
|
a[1][3] = other.a[1][0]*old.a[0][3] + other.a[1][1]*old.a[1][3] + other.a[1][2]*old.a[2][3] + other.a[1][3];
|
||||||
|
a[2][3] = other.a[2][0]*old.a[0][3] + other.a[2][1]*old.a[1][3] + other.a[2][2]*old.a[2][3] + other.a[2][3];
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshVertex::Transform(const StdMeshMatrix& trans)
|
||||||
|
{
|
||||||
|
StdMeshVertex old(*this);
|
||||||
|
|
||||||
|
x = trans(0,0)*old.x + trans(0,1)*old.y + trans(0,2)*old.z + trans(0,3);
|
||||||
|
y = trans(1,0)*old.x + trans(1,1)*old.y + trans(1,2)*old.z + trans(1,3);
|
||||||
|
z = trans(2,0)*old.x + trans(2,1)*old.y + trans(2,2)*old.z + trans(2,3);
|
||||||
|
nx = trans(0,0)*old.nx + trans(0,1)*old.ny + trans(0,2)*old.nz;
|
||||||
|
ny = trans(1,0)*old.nx + trans(1,1)*old.ny + trans(0,2)*old.nz;
|
||||||
|
nz = trans(2,0)*old.nx + trans(2,1)*old.ny + trans(2,2)*old.nz;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshVertex::Mul(float f)
|
||||||
|
{
|
||||||
|
x *= f;
|
||||||
|
y *= f;
|
||||||
|
z *= f;
|
||||||
|
|
||||||
|
// We also multiplicate normals because we expect this to happen in
|
||||||
|
// an expression such as a*v1 + (1-a)*v2 which would ensure normalization
|
||||||
|
// of the normals again.
|
||||||
|
nx *= f;
|
||||||
|
ny *= f;
|
||||||
|
nz *= f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshVertex::Add(const StdMeshVertex& other)
|
||||||
|
{
|
||||||
|
x += other.x;
|
||||||
|
y += other.y;
|
||||||
|
z += other.z;
|
||||||
|
|
||||||
|
nx += other.nx;
|
||||||
|
ny += other.ny;
|
||||||
|
nz += other.nz;
|
||||||
|
}
|
||||||
|
|
||||||
|
StdMeshMatrix StdMeshTrack::GetTransformAt(float time) const
|
||||||
|
{
|
||||||
|
std::map<float, StdMeshKeyFrame>::const_iterator iter = Frames.lower_bound(time);
|
||||||
|
|
||||||
|
// If this points to end(), then either
|
||||||
|
// a) time > animation length
|
||||||
|
// b) The track does not include a frame for the very end of the animation
|
||||||
|
// Both is considered an error
|
||||||
|
assert(iter != Frames.end());
|
||||||
|
|
||||||
|
if(iter == Frames.begin())
|
||||||
|
return iter->second.Trans;
|
||||||
|
|
||||||
|
std::map<float, StdMeshKeyFrame>::const_iterator prev_iter = iter;
|
||||||
|
-- prev_iter;
|
||||||
|
|
||||||
|
float dt = iter->first - prev_iter->first;
|
||||||
|
float weight1 = (time - prev_iter->first) / dt;
|
||||||
|
float weight2 = (iter->first - time) / dt;
|
||||||
|
|
||||||
|
assert(weight1 >= 0 && weight2 >= 0 && weight1 <= 1 && weight2 <= 1);
|
||||||
|
assert(fabs(weight1 + weight2 - 1) < 1e-6);
|
||||||
|
|
||||||
|
StdMeshMatrix trans1 = iter->second.Trans;
|
||||||
|
StdMeshMatrix trans2 = prev_iter->second.Trans;
|
||||||
|
trans1.Mul(weight1);
|
||||||
|
trans2.Mul(weight2);
|
||||||
|
|
||||||
|
trans1.Add(trans2);
|
||||||
|
return trans1;
|
||||||
|
}
|
||||||
|
|
||||||
|
StdMeshAnimation::StdMeshAnimation(const StdMeshAnimation& other):
|
||||||
|
Name(other.Name), Length(other.Length), Tracks(other.Tracks.size())
|
||||||
|
{
|
||||||
|
// Note that all Tracks are already default-initialized to zero
|
||||||
|
for(unsigned int i = 0; i < Tracks.size(); ++i)
|
||||||
|
if(other.Tracks[i])
|
||||||
|
Tracks[i] = new StdMeshTrack(*other.Tracks[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
StdMeshAnimation::~StdMeshAnimation()
|
||||||
|
{
|
||||||
|
for(unsigned int i = 0; i < Tracks.size(); ++i)
|
||||||
|
delete Tracks[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
StdMeshAnimation& StdMeshAnimation::operator=(const StdMeshAnimation& other)
|
||||||
|
{
|
||||||
|
if(this == &other) return *this;
|
||||||
|
|
||||||
|
Name = other.Name;
|
||||||
|
Length = other.Length;
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < Tracks.size(); ++i)
|
||||||
|
delete Tracks[i];
|
||||||
|
|
||||||
|
Tracks.resize(other.Tracks.size());
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < Tracks.size(); ++i)
|
||||||
|
if(other.Tracks[i])
|
||||||
|
Tracks[i] = new StdMeshTrack(*other.Tracks[i]);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
StdMesh::StdMesh():
|
||||||
|
Material(NULL)
|
||||||
|
{
|
||||||
|
BoundingBox.x1 = BoundingBox.y1 = BoundingBox.z1 = 0.0f;
|
||||||
|
BoundingBox.x2 = BoundingBox.y2 = BoundingBox.z2 = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
StdMesh::~StdMesh()
|
||||||
|
{
|
||||||
|
for(unsigned int i = 0; i < Bones.size(); ++i)
|
||||||
|
delete Bones[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMesh::InitXML(const char* filename, const char* xml_data, StdMeshSkeletonLoader& skel_loader, const StdMeshMatManager& manager)
|
||||||
|
{
|
||||||
|
StdMeshXML mesh(filename, xml_data);
|
||||||
|
|
||||||
|
TiXmlElement* mesh_elem = mesh.RequireFirstChild(NULL, "mesh");
|
||||||
|
TiXmlElement* submeshes_elem = mesh.RequireFirstChild(mesh_elem, "submeshes");
|
||||||
|
// Load first submesh only for now
|
||||||
|
TiXmlElement* submesh_elem = mesh.RequireFirstChild(submeshes_elem, "submesh");
|
||||||
|
TiXmlElement* geometry_elem = mesh.RequireFirstChild(submesh_elem, "geometry");
|
||||||
|
|
||||||
|
const char* material = mesh.RequireStrAttribute(submesh_elem, "material");
|
||||||
|
Material = manager.GetMaterial(material);
|
||||||
|
if(!Material)
|
||||||
|
mesh.Error(FormatString("There is no such material named '%s'", material), submesh_elem);
|
||||||
|
|
||||||
|
int VertexCount = mesh.RequireIntAttribute(geometry_elem, "vertexcount");
|
||||||
|
Vertices.resize(VertexCount);
|
||||||
|
|
||||||
|
TiXmlElement* buffer_elem = mesh.RequireFirstChild(geometry_elem, "vertexbuffer");
|
||||||
|
|
||||||
|
unsigned int i = 0;
|
||||||
|
for(TiXmlElement* vertex_elem = buffer_elem->FirstChildElement("vertex"); vertex_elem != NULL && i < Vertices.size(); vertex_elem = vertex_elem->NextSiblingElement("vertex"), ++i)
|
||||||
|
{
|
||||||
|
TiXmlElement* position_elem = mesh.RequireFirstChild(vertex_elem, "position");
|
||||||
|
TiXmlElement* normal_elem = mesh.RequireFirstChild(vertex_elem, "normal");
|
||||||
|
TiXmlElement* texcoord_elem = mesh.RequireFirstChild(vertex_elem, "texcoord");
|
||||||
|
|
||||||
|
Vertices[i].x = mesh.RequireFloatAttribute(position_elem, "x");
|
||||||
|
Vertices[i].y = mesh.RequireFloatAttribute(position_elem, "y");
|
||||||
|
Vertices[i].z = mesh.RequireFloatAttribute(position_elem, "z");
|
||||||
|
Vertices[i].nx = mesh.RequireFloatAttribute(normal_elem, "x");
|
||||||
|
Vertices[i].ny = mesh.RequireFloatAttribute(normal_elem, "y");
|
||||||
|
Vertices[i].nz = mesh.RequireFloatAttribute(normal_elem, "z");
|
||||||
|
Vertices[i].u = mesh.RequireFloatAttribute(texcoord_elem, "u");
|
||||||
|
Vertices[i].v = mesh.RequireFloatAttribute(texcoord_elem, "v");
|
||||||
|
|
||||||
|
// Convert to Clonk coordinate system
|
||||||
|
Vertices[i].Transform(CoordCorrection);
|
||||||
|
|
||||||
|
// Construct BoundingBox
|
||||||
|
if(i == 0)
|
||||||
|
{
|
||||||
|
BoundingBox.x1 = BoundingBox.x2 = Vertices[i].x;
|
||||||
|
BoundingBox.y1 = BoundingBox.y2 = Vertices[i].y;
|
||||||
|
BoundingBox.z1 = BoundingBox.z2 = Vertices[i].z;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BoundingBox.x1 = Min(Vertices[i].x, BoundingBox.x1);
|
||||||
|
BoundingBox.x2 = Max(Vertices[i].x, BoundingBox.x2);
|
||||||
|
BoundingBox.y1 = Min(Vertices[i].y, BoundingBox.y1);
|
||||||
|
BoundingBox.y2 = Max(Vertices[i].y, BoundingBox.y2);
|
||||||
|
BoundingBox.z1 = Min(Vertices[i].z, BoundingBox.z1);
|
||||||
|
BoundingBox.z2 = Max(Vertices[i].z, BoundingBox.z2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TiXmlElement* faces_elem = mesh.RequireFirstChild(submesh_elem, "faces");
|
||||||
|
int FaceCount = mesh.RequireIntAttribute(faces_elem, "count");
|
||||||
|
Faces.resize(FaceCount);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
for(TiXmlElement* face_elem = faces_elem->FirstChildElement("face"); face_elem != NULL && i < Faces.size(); face_elem = face_elem->NextSiblingElement("face"), ++i)
|
||||||
|
{
|
||||||
|
int v[3];
|
||||||
|
|
||||||
|
v[0] = mesh.RequireIntAttribute(face_elem, "v1");
|
||||||
|
v[1] = mesh.RequireIntAttribute(face_elem, "v2");
|
||||||
|
v[2] = mesh.RequireIntAttribute(face_elem, "v3");
|
||||||
|
|
||||||
|
for(unsigned int j = 0; j < 3; ++j)
|
||||||
|
{
|
||||||
|
if(v[j] < 0 || static_cast<unsigned int>(v[j]) >= Vertices.size())
|
||||||
|
mesh.Error(FormatString("Vertex index v%u (%d) is out of range", j+1, v[j]), face_elem);
|
||||||
|
Faces[i].Vertices[j] = v[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read skeleton
|
||||||
|
TiXmlElement* skeletonlink_elem = mesh.RequireFirstChild(mesh_elem, "skeletonlink");
|
||||||
|
const char* name = mesh.RequireStrAttribute(skeletonlink_elem, "name");
|
||||||
|
StdStrBuf xml_filename(name); xml_filename.Append(".xml");
|
||||||
|
|
||||||
|
StdStrBuf skeleton_xml_data = skel_loader.LoadSkeleton(xml_filename.getData());
|
||||||
|
if(skeleton_xml_data.isNull()) mesh.Error(FormatString("Failed to load '%s'", xml_filename.getData()), skeletonlink_elem);
|
||||||
|
|
||||||
|
StdMeshXML skeleton(xml_filename.getData(), skeleton_xml_data.getData());
|
||||||
|
TiXmlElement* skeleton_elem = skeleton.RequireFirstChild(NULL, "skeleton");
|
||||||
|
TiXmlElement* bones_elem = skeleton.RequireFirstChild(skeleton_elem, "bones");
|
||||||
|
|
||||||
|
// Read bones. Don't insert into Master bone table yet, as the master bone
|
||||||
|
// table is sorted hierarchically, and we will read the hierarchy only
|
||||||
|
// afterwards.
|
||||||
|
std::vector<StdMeshBone*> bones;
|
||||||
|
for(TiXmlElement* bone_elem = bones_elem->FirstChildElement("bone"); bone_elem != NULL; bone_elem = bone_elem->NextSiblingElement("bone"))
|
||||||
|
{
|
||||||
|
StdMeshBone* bone = new StdMeshBone;
|
||||||
|
bones.push_back(bone);
|
||||||
|
|
||||||
|
bone->ID = skeleton.RequireIntAttribute(bone_elem, "id");
|
||||||
|
bone->Name = skeleton.RequireStrAttribute(bone_elem, "name");
|
||||||
|
|
||||||
|
// TODO: Make sure ID and name are unique
|
||||||
|
|
||||||
|
TiXmlElement* position_elem = skeleton.RequireFirstChild(bone_elem, "position");
|
||||||
|
TiXmlElement* rotation_elem = skeleton.RequireFirstChild(bone_elem, "rotation");
|
||||||
|
TiXmlElement* axis_elem = skeleton.RequireFirstChild(rotation_elem, "axis");
|
||||||
|
|
||||||
|
float dx = skeleton.RequireFloatAttribute(position_elem, "x");
|
||||||
|
float dy = skeleton.RequireFloatAttribute(position_elem, "y");
|
||||||
|
float dz = skeleton.RequireFloatAttribute(position_elem, "z");
|
||||||
|
float angle = skeleton.RequireFloatAttribute(rotation_elem, "angle");
|
||||||
|
float rx = skeleton.RequireFloatAttribute(axis_elem, "x");
|
||||||
|
float ry = skeleton.RequireFloatAttribute(axis_elem, "y");
|
||||||
|
float rz = skeleton.RequireFloatAttribute(axis_elem, "z");
|
||||||
|
|
||||||
|
StdMeshMatrix helper;
|
||||||
|
helper.SetTranslate(dx, dy, dz);
|
||||||
|
bone->Trans.SetRotate(angle, rx, ry, rz);
|
||||||
|
bone->Trans.Transform(helper);
|
||||||
|
|
||||||
|
// Transform to Clonk coordinate system
|
||||||
|
bone->Trans.Mul(CoordCorrectionInverse);
|
||||||
|
bone->Trans.Transform(CoordCorrection);
|
||||||
|
|
||||||
|
helper.SetRotate(-angle, rx, ry, rz);
|
||||||
|
bone->InverseTrans.SetTranslate(-dx, -dy, -dz);
|
||||||
|
bone->InverseTrans.Transform(helper);
|
||||||
|
|
||||||
|
// Transform to Clonk coordinate system
|
||||||
|
bone->InverseTrans.Mul(CoordCorrectionInverse);
|
||||||
|
bone->InverseTrans.Transform(CoordCorrection);
|
||||||
|
|
||||||
|
bone->Parent = NULL;
|
||||||
|
|
||||||
|
// Index of bone will be set when building Master Bone Table later
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bone hierarchy
|
||||||
|
TiXmlElement* bonehierarchy_elem = skeleton.RequireFirstChild(skeleton_elem, "bonehierarchy");
|
||||||
|
for(TiXmlElement* boneparent_elem = bonehierarchy_elem->FirstChildElement("boneparent"); boneparent_elem != NULL; boneparent_elem = boneparent_elem->NextSiblingElement("boneparent"))
|
||||||
|
{
|
||||||
|
const char* child_name = skeleton.RequireStrAttribute(boneparent_elem, "bone");
|
||||||
|
const char* parent_name = skeleton.RequireStrAttribute(boneparent_elem, "parent");
|
||||||
|
|
||||||
|
// Lookup the two bones
|
||||||
|
StdMeshBone* child = NULL;
|
||||||
|
StdMeshBone* parent = NULL;
|
||||||
|
for(unsigned int i = 0; i < bones.size() && (!child || !parent); ++i)
|
||||||
|
{
|
||||||
|
if(!child && bones[i]->Name == child_name)
|
||||||
|
child = bones[i];
|
||||||
|
if(!parent && bones[i]->Name == parent_name)
|
||||||
|
parent = bones[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!child) skeleton.Error(FormatString("There is no such bone with name '%s'", child_name), boneparent_elem);
|
||||||
|
if(!parent) skeleton.Error(FormatString("There is no such bone with name '%s'", parent_name), boneparent_elem);
|
||||||
|
|
||||||
|
child->Parent = parent;
|
||||||
|
parent->Children.push_back(child);
|
||||||
|
|
||||||
|
// Apply parent transformation
|
||||||
|
child->Trans.Transform(parent->Trans);
|
||||||
|
child->InverseTrans.Mul(parent->InverseTrans);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill master bone table in hierarchical order:
|
||||||
|
for(unsigned int i = 0; i < bones.size(); ++i)
|
||||||
|
if(bones[i]->Parent == NULL)
|
||||||
|
AddMasterBone(bones[i]);
|
||||||
|
|
||||||
|
// Vertex<->Bone assignments
|
||||||
|
TiXmlElement* boneassignments_elem = mesh.RequireFirstChild(submesh_elem, "boneassignments");
|
||||||
|
for(TiXmlElement* vertexboneassignment_elem = boneassignments_elem->FirstChildElement("vertexboneassignment"); vertexboneassignment_elem != NULL; vertexboneassignment_elem = vertexboneassignment_elem->NextSiblingElement("vertexboneassignment"))
|
||||||
|
{
|
||||||
|
int BoneID = mesh.RequireIntAttribute(vertexboneassignment_elem, "boneindex");
|
||||||
|
int VertexIndex = mesh.RequireIntAttribute(vertexboneassignment_elem, "vertexindex");
|
||||||
|
float weight = mesh.RequireFloatAttribute(vertexboneassignment_elem, "weight");
|
||||||
|
|
||||||
|
if(VertexIndex < 0 || static_cast<unsigned int>(VertexIndex) >= Vertices.size())
|
||||||
|
mesh.Error(FormatString("Vertex index in bone assignment (%d) is out of range", VertexIndex), vertexboneassignment_elem);
|
||||||
|
|
||||||
|
StdMeshBone* bone = NULL;
|
||||||
|
for(unsigned int i = 0; !bone && i < bones.size(); ++i)
|
||||||
|
if(bones[i]->ID == BoneID)
|
||||||
|
bone = bones[i];
|
||||||
|
|
||||||
|
if(!bone) mesh.Error(FormatString("There is no such bone with index %d", BoneID), vertexboneassignment_elem);
|
||||||
|
|
||||||
|
Vertex& vertex = Vertices[VertexIndex];
|
||||||
|
vertex.BoneAssignments.push_back(StdMeshVertexBoneAssignment());
|
||||||
|
StdMeshVertexBoneAssignment& assignment = vertex.BoneAssignments.back();
|
||||||
|
assignment.BoneIndex = bone->Index;
|
||||||
|
assignment.Weight = weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize vertex bone assignment weights (this is not guaranteed in the
|
||||||
|
// Ogre file format).
|
||||||
|
for(unsigned int i = 0; i < Vertices.size(); ++i)
|
||||||
|
{
|
||||||
|
Vertex& vertex = Vertices[i];
|
||||||
|
float sum = 0.0f;
|
||||||
|
for(unsigned int j = 0; j < vertex.BoneAssignments.size(); ++j)
|
||||||
|
sum += vertex.BoneAssignments[j].Weight;
|
||||||
|
for(unsigned int j = 0; j < vertex.BoneAssignments.size(); ++j)
|
||||||
|
vertex.BoneAssignments[j].Weight /= sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load Animations
|
||||||
|
TiXmlElement* animations_elem = skeleton.RequireFirstChild(skeleton_elem, "animations");
|
||||||
|
for(TiXmlElement* animation_elem = animations_elem->FirstChildElement("animation"); animation_elem != NULL; animation_elem = animation_elem->NextSiblingElement("animation"))
|
||||||
|
{
|
||||||
|
StdStrBuf name(skeleton.RequireStrAttribute(animation_elem, "name"));
|
||||||
|
if(Animations.find(name) != Animations.end())
|
||||||
|
skeleton.Error(FormatString("There is already an animation with name '%s'", name.getData()), animation_elem);
|
||||||
|
|
||||||
|
StdMeshAnimation& animation = Animations.insert(std::make_pair(name, StdMeshAnimation())).first->second;
|
||||||
|
animation.Name = name;
|
||||||
|
animation.Length = skeleton.RequireFloatAttribute(animation_elem, "length");
|
||||||
|
animation.Tracks.resize(Bones.size());
|
||||||
|
|
||||||
|
TiXmlElement* tracks_elem = skeleton.RequireFirstChild(animation_elem, "tracks");
|
||||||
|
for(TiXmlElement* track_elem = tracks_elem->FirstChildElement("track"); track_elem != NULL; track_elem = track_elem->NextSiblingElement("track"))
|
||||||
|
{
|
||||||
|
const char* bone_name = skeleton.RequireStrAttribute(track_elem, "bone");
|
||||||
|
StdMeshBone* bone = NULL;
|
||||||
|
for(unsigned int i = 0; !bone && i < Bones.size(); ++i)
|
||||||
|
if(Bones[i]->Name == bone_name)
|
||||||
|
bone = Bones[i];
|
||||||
|
if(!bone) skeleton.Error(FormatString("There is no such bone with name '%s'", bone_name), track_elem);
|
||||||
|
|
||||||
|
if(animation.Tracks[bone->Index] != NULL) skeleton.Error(FormatString("There is already a track for bone '%s' in animation '%s'", bone_name, animation.Name.getData()), track_elem);
|
||||||
|
|
||||||
|
StdMeshTrack* track = new StdMeshTrack;
|
||||||
|
animation.Tracks[bone->Index] = track;
|
||||||
|
|
||||||
|
TiXmlElement* keyframes_elem = skeleton.RequireFirstChild(track_elem, "keyframes");
|
||||||
|
for(TiXmlElement* keyframe_elem = keyframes_elem->FirstChildElement("keyframe"); keyframe_elem != NULL; keyframe_elem = keyframe_elem->NextSiblingElement("keyframe"))
|
||||||
|
{
|
||||||
|
float time = skeleton.RequireFloatAttribute(keyframe_elem, "time");
|
||||||
|
StdMeshKeyFrame& frame = track->Frames[time];
|
||||||
|
|
||||||
|
TiXmlElement* translate_elem = skeleton.RequireFirstChild(keyframe_elem, "translate");
|
||||||
|
TiXmlElement* rotate_elem = skeleton.RequireFirstChild(keyframe_elem, "rotate");
|
||||||
|
TiXmlElement* scale_elem = skeleton.RequireFirstChild(keyframe_elem, "scale");
|
||||||
|
TiXmlElement* axis_elem = skeleton.RequireFirstChild(rotate_elem, "axis");
|
||||||
|
|
||||||
|
float dx = skeleton.RequireFloatAttribute(translate_elem, "x");
|
||||||
|
float dy = skeleton.RequireFloatAttribute(translate_elem, "y");
|
||||||
|
float dz = skeleton.RequireFloatAttribute(translate_elem, "z");
|
||||||
|
float sx = skeleton.RequireFloatAttribute(scale_elem, "x");
|
||||||
|
float sy = skeleton.RequireFloatAttribute(scale_elem, "y");
|
||||||
|
float sz = skeleton.RequireFloatAttribute(scale_elem, "z");
|
||||||
|
float angle = skeleton.RequireFloatAttribute(rotate_elem, "angle");
|
||||||
|
float rx = skeleton.RequireFloatAttribute(axis_elem, "x");
|
||||||
|
float ry = skeleton.RequireFloatAttribute(axis_elem, "y");
|
||||||
|
float rz = skeleton.RequireFloatAttribute(axis_elem, "z");
|
||||||
|
|
||||||
|
// TODO: Make sure the order is correct here - I am not sure about scale
|
||||||
|
StdMeshMatrix helper;
|
||||||
|
frame.Trans.SetRotate(angle, rx, ry, rz);
|
||||||
|
helper.SetScale(sx, sy, sz);
|
||||||
|
frame.Trans.Transform(helper);
|
||||||
|
helper.SetTranslate(-dx, -dy, -dz);
|
||||||
|
frame.Trans.Transform(helper);
|
||||||
|
|
||||||
|
// Transform into Clonk coordinate system
|
||||||
|
frame.Trans.Transform(CoordCorrection);
|
||||||
|
frame.Trans.Mul(CoordCorrectionInverse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply bone transformation on animation frames. We need to do this
|
||||||
|
// after the actual loading because we need to walk the bone list
|
||||||
|
// hierarchically.
|
||||||
|
for(unsigned int i = 0; i < Bones.size(); ++i)
|
||||||
|
{
|
||||||
|
if(animation.Tracks[i])
|
||||||
|
{
|
||||||
|
StdMeshTrack& track = *animation.Tracks[i];
|
||||||
|
|
||||||
|
// Get next parent track
|
||||||
|
StdMeshTrack* parent_track = NULL;
|
||||||
|
StdMeshBone* parent_bone = Bones[i]->Parent;
|
||||||
|
while(parent_bone && !(parent_track = animation.Tracks[parent_bone->Index]))
|
||||||
|
parent_bone = parent_bone->Parent;
|
||||||
|
assert(!parent_bone || parent_track);
|
||||||
|
|
||||||
|
for(std::map<float, StdMeshKeyFrame>::iterator iter = track.Frames.begin(); iter != track.Frames.end(); ++iter)
|
||||||
|
{
|
||||||
|
// TODO: If this bone's track is not as smooth as the parent animation
|
||||||
|
// (which means if there is more than one keyframe in the parent
|
||||||
|
// animation for each keyframe pair in the this bone's animation),
|
||||||
|
// then we need to insert additional child keyframes, so that the
|
||||||
|
// transformation for the child does not skip parent keyframes.
|
||||||
|
StdMeshKeyFrame& frame = iter->second;
|
||||||
|
|
||||||
|
// Apply transformation of parent tracks (for which we computed
|
||||||
|
// already the bone transformations, as we walk the bone list
|
||||||
|
// hierarchically) in bone's coordinate system.
|
||||||
|
frame.Trans.Mul(Bones[i]->InverseTrans);
|
||||||
|
frame.Trans.Transform(Bones[i]->Trans);
|
||||||
|
|
||||||
|
if(parent_bone)
|
||||||
|
frame.Trans.Transform(parent_track->GetTransformAt(iter->first));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMesh::AddMasterBone(StdMeshBone* bone)
|
||||||
|
{
|
||||||
|
bone->Index = Bones.size(); // Remember index in master bone table
|
||||||
|
Bones.push_back(bone);
|
||||||
|
for(unsigned int i = 0; i < bone->Children.size(); ++i)
|
||||||
|
AddMasterBone(bone->Children[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const StdMeshAnimation* StdMesh::GetAnimationByName(const StdStrBuf& name) const
|
||||||
|
{
|
||||||
|
std::map<StdStrBuf, StdMeshAnimation>::const_iterator iter = Animations.find(name);
|
||||||
|
if(iter == Animations.end()) return NULL;
|
||||||
|
return &iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
StdMeshInstance::StdMeshInstance(const StdMesh& mesh):
|
||||||
|
Mesh(mesh), CurrentFaceOrdering(FO_Fixed), Animation(NULL), Position(0.0f),
|
||||||
|
BoneTransforms(Mesh.GetNumBones()), Vertices(Mesh.GetNumVertices()),
|
||||||
|
Faces(Mesh.GetNumFaces())
|
||||||
|
{
|
||||||
|
for(unsigned int i = 0; i < Mesh.GetNumVertices(); ++i)
|
||||||
|
Vertices[i] = Mesh.GetVertex(i);
|
||||||
|
|
||||||
|
// This is FO_Fixed actually
|
||||||
|
for(unsigned int i = 0; i < Mesh.GetNumFaces(); ++i)
|
||||||
|
Faces[i] = &Mesh.GetFace(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshInstance::SetFaceOrdering(FaceOrdering ordering)
|
||||||
|
{
|
||||||
|
CurrentFaceOrdering = ordering;
|
||||||
|
ReorderFaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StdMeshInstance::SetAnimationByName(const StdStrBuf& animation_name)
|
||||||
|
{
|
||||||
|
const StdMeshAnimation* animation = Mesh.GetAnimationByName(animation_name);
|
||||||
|
if(!animation) return false;
|
||||||
|
SetAnimation(*animation);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshInstance::SetAnimation(const StdMeshAnimation& animation)
|
||||||
|
{
|
||||||
|
// TODO: Make sure the animation belongs to this mesh
|
||||||
|
Animation = &animation;
|
||||||
|
SetPosition(0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshInstance::UnsetAnimation()
|
||||||
|
{
|
||||||
|
Animation = NULL;
|
||||||
|
|
||||||
|
// Reset instance vertices
|
||||||
|
for(unsigned int i = 0; i < Mesh.GetNumVertices(); ++i)
|
||||||
|
Vertices[i] = Mesh.GetVertex(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshInstance::SetPosition(float position)
|
||||||
|
{
|
||||||
|
assert(Animation);
|
||||||
|
Position = position;
|
||||||
|
|
||||||
|
// Compute transformation matrix for each bone.
|
||||||
|
for(unsigned int i = 0; i < BoneTransforms.size(); ++i)
|
||||||
|
{
|
||||||
|
StdMeshTrack* track = Animation->Tracks[i];
|
||||||
|
if(track)
|
||||||
|
{
|
||||||
|
BoneTransforms[i] = track->GetTransformAt(position);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No track for this bone, so use parent transformation
|
||||||
|
const StdMeshBone* parent = Mesh.GetBone(i).GetParent();
|
||||||
|
if(parent)
|
||||||
|
{
|
||||||
|
// Parent should already have been processed, because the bone indices
|
||||||
|
// are supposed to be hierarchically ordered.
|
||||||
|
assert(parent->Index < i);
|
||||||
|
BoneTransforms[i] = BoneTransforms[parent->Index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BoneTransforms[i].SetIdentity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute transformation for each vertex. We could later think about
|
||||||
|
// doing this on the GPU using a vertex shader. This would then probably
|
||||||
|
// need to go to CStdGL::PerformMesh and CStdD3D::PerformMesh.
|
||||||
|
for(unsigned int i = 0; i < Vertices.size(); ++i)
|
||||||
|
{
|
||||||
|
const StdMesh::Vertex& vertex = Mesh.Vertices[i];
|
||||||
|
if(!vertex.BoneAssignments.empty())
|
||||||
|
{
|
||||||
|
Vertices[i].x = Vertices[i].y = Vertices[i].z = 0.0f;
|
||||||
|
Vertices[i].nx = Vertices[i].ny = Vertices[i].nz = 0.0f;
|
||||||
|
Vertices[i].u = vertex.u; Vertices[i].v = vertex.v;
|
||||||
|
|
||||||
|
for(unsigned int j = 0; j < vertex.BoneAssignments.size(); ++j)
|
||||||
|
{
|
||||||
|
const StdMeshVertexBoneAssignment& assignment = vertex.BoneAssignments[j];
|
||||||
|
StdMeshVertex vtx = vertex;
|
||||||
|
vtx.Transform(BoneTransforms[assignment.BoneIndex]);
|
||||||
|
vtx.Mul(assignment.Weight);
|
||||||
|
Vertices[i].Add(vtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vertices[i] = vertex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CurrentFaceOrdering != FO_Fixed)
|
||||||
|
ReorderFaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshInstance::ReorderFaces()
|
||||||
|
{
|
||||||
|
StdMeshInstanceFaceOrderingCmpPred pred(*this);
|
||||||
|
std::sort(Faces.begin(), Faces.end(), pred);
|
||||||
|
}
|
||||||
|
|
||||||
|
// vim: et ts=2 sw=2
|
|
@ -0,0 +1,448 @@
|
||||||
|
/*
|
||||||
|
* OpenClonk, http://www.openclonk.org
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Armin Burgmeier
|
||||||
|
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
|
||||||
|
*
|
||||||
|
* Portions might be copyrighted by other authors who have contributed
|
||||||
|
* to OpenClonk.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
* See isc_license.txt for full license and disclaimer.
|
||||||
|
*
|
||||||
|
* "Clonk" is a registered trademark of Matthes Bender.
|
||||||
|
* See clonk_trademark_license.txt for full license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <StdMeshMaterial.h>
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
|
StdMeshMaterialError::StdMeshMaterialError(const StdStrBuf& message, const char* file, unsigned int line)
|
||||||
|
{
|
||||||
|
Buf.Format("%s:%u: %s", file, line, message.getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Token
|
||||||
|
{
|
||||||
|
TOKEN_IDTF,
|
||||||
|
TOKEN_BRACE_OPEN,
|
||||||
|
TOKEN_BRACE_CLOSE,
|
||||||
|
TOKEN_COLON,
|
||||||
|
TOKEN_EOF
|
||||||
|
};
|
||||||
|
|
||||||
|
class StdMeshMaterialParserCtx
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StdMeshMaterialParserCtx(const char* mat_script, const char* filename, StdMeshMaterialTextureLoader& tex_loader);
|
||||||
|
|
||||||
|
void SkipWhitespace();
|
||||||
|
Token Peek(StdStrBuf& name);
|
||||||
|
Token Advance(StdStrBuf& name);
|
||||||
|
Token AdvanceNonEOF(StdStrBuf& name);
|
||||||
|
Token AdvanceRequired(StdStrBuf& name, Token expect);
|
||||||
|
Token AdvanceRequired(StdStrBuf& name, Token expect1, Token expect2);
|
||||||
|
float AdvanceFloat();
|
||||||
|
bool AdvanceFloatOptional(float& value);
|
||||||
|
bool AdvanceBoolean();
|
||||||
|
void Error(const StdStrBuf& message);
|
||||||
|
void ErrorUnexpectedIdentifier(const StdStrBuf& identifier);
|
||||||
|
|
||||||
|
// Current parsing data
|
||||||
|
unsigned int Line;
|
||||||
|
const char* Script;
|
||||||
|
|
||||||
|
StdStrBuf FileName;
|
||||||
|
StdMeshMaterialTextureLoader& TextureLoader;
|
||||||
|
};
|
||||||
|
|
||||||
|
StdMeshMaterialParserCtx::StdMeshMaterialParserCtx(const char* mat_script, const char* filename, StdMeshMaterialTextureLoader& tex_loader):
|
||||||
|
Line(0), Script(mat_script), FileName(filename), TextureLoader(tex_loader)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshMaterialParserCtx::SkipWhitespace()
|
||||||
|
{
|
||||||
|
while(isspace(*Script))
|
||||||
|
{
|
||||||
|
if(*Script == '\n') ++Line;
|
||||||
|
++Script;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Token StdMeshMaterialParserCtx::Peek(StdStrBuf& name)
|
||||||
|
{
|
||||||
|
SkipWhitespace();
|
||||||
|
|
||||||
|
const char* before = Script;
|
||||||
|
Token tok = Advance(name);
|
||||||
|
Script = before;
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token StdMeshMaterialParserCtx::Advance(StdStrBuf& name)
|
||||||
|
{
|
||||||
|
SkipWhitespace();
|
||||||
|
|
||||||
|
switch(*Script)
|
||||||
|
{
|
||||||
|
case '\0':
|
||||||
|
name.Clear();
|
||||||
|
return TOKEN_EOF;
|
||||||
|
case '{':
|
||||||
|
++Script;
|
||||||
|
name = "{";
|
||||||
|
return TOKEN_BRACE_OPEN;
|
||||||
|
case '}':
|
||||||
|
++Script;
|
||||||
|
name = "}";
|
||||||
|
return TOKEN_BRACE_CLOSE;
|
||||||
|
case ':':
|
||||||
|
++Script;
|
||||||
|
name = ":";
|
||||||
|
return TOKEN_COLON;
|
||||||
|
default:
|
||||||
|
const char* begin = Script;
|
||||||
|
// Advance to next whitespace
|
||||||
|
do { ++Script; } while(!isspace(*Script) && *Script != '{' && *Script != '}' && *Script != ':');
|
||||||
|
name.Copy(begin, Script - begin);
|
||||||
|
return TOKEN_IDTF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Token StdMeshMaterialParserCtx::AdvanceNonEOF(StdStrBuf& name)
|
||||||
|
{
|
||||||
|
Token token = Advance(name);
|
||||||
|
if(token == TOKEN_EOF) Error(StdStrBuf("Unexpected end of file"));
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token StdMeshMaterialParserCtx::AdvanceRequired(StdStrBuf& name, Token expect)
|
||||||
|
{
|
||||||
|
Token token = AdvanceNonEOF(name);
|
||||||
|
// TODO: Explain what was actually expected
|
||||||
|
if(token != expect) Error(StdStrBuf("'") + name + "' unexpected");
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token StdMeshMaterialParserCtx::AdvanceRequired(StdStrBuf& name, Token expect1, Token expect2)
|
||||||
|
{
|
||||||
|
Token token = AdvanceNonEOF(name);
|
||||||
|
// TODO: Explain what was actually expected
|
||||||
|
if(token != expect1 && token != expect2)
|
||||||
|
Error(StdStrBuf("'") + name + "' unexpected");
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
float StdMeshMaterialParserCtx::AdvanceFloat()
|
||||||
|
{
|
||||||
|
StdStrBuf buf;
|
||||||
|
AdvanceRequired(buf, TOKEN_IDTF);
|
||||||
|
char* end;
|
||||||
|
float f = strtof(buf.getData(), &end);
|
||||||
|
if(*end != '\0') Error(StdStrBuf("Floating point value expected"));
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StdMeshMaterialParserCtx::AdvanceFloatOptional(float& value)
|
||||||
|
{
|
||||||
|
StdStrBuf buf;
|
||||||
|
Token tok = Peek(buf);
|
||||||
|
|
||||||
|
if(tok == TOKEN_IDTF && isdigit(buf[0]))
|
||||||
|
{
|
||||||
|
value = AdvanceFloat();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StdMeshMaterialParserCtx::AdvanceBoolean()
|
||||||
|
{
|
||||||
|
StdStrBuf buf;
|
||||||
|
AdvanceRequired(buf, TOKEN_IDTF);
|
||||||
|
if(buf == "on") return true;
|
||||||
|
if(buf == "off") return false;
|
||||||
|
Error(StdStrBuf("Expected either 'on' or 'off', but not '") + buf + "'");
|
||||||
|
return false; // Never reached
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshMaterialParserCtx::Error(const StdStrBuf& message)
|
||||||
|
{
|
||||||
|
throw StdMeshMaterialError(message, FileName.getData(), Line);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshMaterialParserCtx::ErrorUnexpectedIdentifier(const StdStrBuf& identifier)
|
||||||
|
{
|
||||||
|
Error(StdStrBuf("Unexpected identifier: '") + identifier + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
StdMeshMaterialTextureUnit::TexRef::TexRef(unsigned int size):
|
||||||
|
RefCount(1), Tex(size, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
StdMeshMaterialTextureUnit::TexRef::~TexRef()
|
||||||
|
{
|
||||||
|
assert(RefCount == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
StdMeshMaterialTextureUnit::StdMeshMaterialTextureUnit():
|
||||||
|
Texture(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
StdMeshMaterialTextureUnit::StdMeshMaterialTextureUnit(const StdMeshMaterialTextureUnit& other):
|
||||||
|
Texture(other.Texture)
|
||||||
|
{
|
||||||
|
if(Texture)
|
||||||
|
++Texture->RefCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
StdMeshMaterialTextureUnit::~StdMeshMaterialTextureUnit()
|
||||||
|
{
|
||||||
|
if(Texture && !--Texture->RefCount)
|
||||||
|
delete Texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
StdMeshMaterialTextureUnit& StdMeshMaterialTextureUnit::operator=(const StdMeshMaterialTextureUnit& other)
|
||||||
|
{
|
||||||
|
if(this == &other) return *this;
|
||||||
|
if(Texture) if(!--Texture->RefCount) delete Texture;
|
||||||
|
Texture = other.Texture;
|
||||||
|
if(Texture) ++Texture->RefCount;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshMaterialTextureUnit::Load(StdMeshMaterialParserCtx& ctx)
|
||||||
|
{
|
||||||
|
Token token;
|
||||||
|
StdStrBuf token_name;
|
||||||
|
while((token = ctx.AdvanceNonEOF(token_name)) == TOKEN_IDTF)
|
||||||
|
{
|
||||||
|
if(token_name == "texture")
|
||||||
|
{
|
||||||
|
ctx.AdvanceRequired(token_name, TOKEN_IDTF);
|
||||||
|
|
||||||
|
CPNGFile png;
|
||||||
|
if(!ctx.TextureLoader.LoadTexture(token_name.getData(), png))
|
||||||
|
ctx.Error(StdStrBuf("Could not load texture '") + token_name + "'");
|
||||||
|
|
||||||
|
if(png.iWdt != png.iHgt)
|
||||||
|
ctx.Error(StdStrBuf("Texture '") + token_name + "' is not quadratic");
|
||||||
|
|
||||||
|
Texture = new TexRef(png.iWdt);
|
||||||
|
|
||||||
|
Texture->Tex.Lock();
|
||||||
|
for(unsigned int y = 0; y < png.iHgt; ++y)
|
||||||
|
for(unsigned int x = 0; x < png.iWdt; ++x)
|
||||||
|
Texture->Tex.SetPix4(x, y, png.GetPix(x, y));
|
||||||
|
Texture->Tex.Unlock();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ctx.ErrorUnexpectedIdentifier(token_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(token != TOKEN_BRACE_CLOSE)
|
||||||
|
ctx.Error(StdStrBuf("'") + token_name.getData() + "' unexpected");
|
||||||
|
}
|
||||||
|
|
||||||
|
StdMeshMaterialPass::StdMeshMaterialPass()
|
||||||
|
{
|
||||||
|
Ambient[0] = Ambient[1] = Ambient[2] = 1.0f; Ambient[3] = 0.0f;
|
||||||
|
Diffuse[0] = Diffuse[1] = Diffuse[2] = 1.0f; Diffuse[3] = 0.0f;
|
||||||
|
Specular[0] = Specular[1] = Specular[2] = 0.0f; Specular[3] = 1.0f;
|
||||||
|
Emissive[0] = Emissive[1] = Emissive[2] = 0.0f; Emissive[3] = 1.0f;
|
||||||
|
Shininess = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshMaterialPass::Load(StdMeshMaterialParserCtx& ctx)
|
||||||
|
{
|
||||||
|
Token token;
|
||||||
|
StdStrBuf token_name;
|
||||||
|
while((token = ctx.AdvanceNonEOF(token_name)) == TOKEN_IDTF)
|
||||||
|
{
|
||||||
|
if(token_name == "texture_unit")
|
||||||
|
{
|
||||||
|
// TODO: Can there be an optional name?
|
||||||
|
ctx.AdvanceRequired(token_name, TOKEN_BRACE_OPEN);
|
||||||
|
TextureUnits.push_back(StdMeshMaterialTextureUnit());
|
||||||
|
TextureUnits.back().Load(ctx);
|
||||||
|
}
|
||||||
|
else if(token_name == "ambient")
|
||||||
|
{
|
||||||
|
Ambient[0] = ctx.AdvanceFloat();
|
||||||
|
Ambient[1] = ctx.AdvanceFloat();
|
||||||
|
Ambient[2] = ctx.AdvanceFloat();
|
||||||
|
if(ctx.AdvanceFloatOptional(Ambient[3]))
|
||||||
|
Ambient[3] = 1 - Ambient[3];
|
||||||
|
}
|
||||||
|
else if(token_name == "diffuse")
|
||||||
|
{
|
||||||
|
Diffuse[0] = ctx.AdvanceFloat();
|
||||||
|
Diffuse[1] = ctx.AdvanceFloat();
|
||||||
|
Diffuse[2] = ctx.AdvanceFloat();
|
||||||
|
if(ctx.AdvanceFloatOptional(Diffuse[3]))
|
||||||
|
Diffuse[3] = 1 - Diffuse[3];
|
||||||
|
}
|
||||||
|
else if(token_name == "specular")
|
||||||
|
{
|
||||||
|
Specular[0] = ctx.AdvanceFloat();
|
||||||
|
Specular[1] = ctx.AdvanceFloat();
|
||||||
|
Specular[2] = ctx.AdvanceFloat();
|
||||||
|
|
||||||
|
// The fourth argument is optional, not the fifth:
|
||||||
|
float specular3 = ctx.AdvanceFloat();
|
||||||
|
|
||||||
|
float shininess;
|
||||||
|
if(ctx.AdvanceFloatOptional(shininess))
|
||||||
|
{
|
||||||
|
Specular[3] = 1 - specular3;
|
||||||
|
Shininess = shininess;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Shininess = specular3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(token_name == "emissive")
|
||||||
|
{
|
||||||
|
Emissive[0] = ctx.AdvanceFloat();
|
||||||
|
Emissive[1] = ctx.AdvanceFloat();
|
||||||
|
Emissive[2] = ctx.AdvanceFloat();
|
||||||
|
if(ctx.AdvanceFloatOptional(Emissive[3]))
|
||||||
|
Emissive[3] = 1 - Emissive[3];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ctx.ErrorUnexpectedIdentifier(token_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(token != TOKEN_BRACE_CLOSE)
|
||||||
|
ctx.Error(StdStrBuf("'") + token_name.getData() + "' unexpected");
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshMaterialTechnique::Load(StdMeshMaterialParserCtx& ctx)
|
||||||
|
{
|
||||||
|
Token token;
|
||||||
|
StdStrBuf token_name;
|
||||||
|
while((token = ctx.AdvanceNonEOF(token_name)) == TOKEN_IDTF)
|
||||||
|
{
|
||||||
|
if(token_name == "pass")
|
||||||
|
{
|
||||||
|
// TODO: Can there be an optional name?
|
||||||
|
ctx.AdvanceRequired(token_name, TOKEN_BRACE_OPEN);
|
||||||
|
Passes.push_back(StdMeshMaterialPass());
|
||||||
|
Passes.back().Load(ctx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ctx.ErrorUnexpectedIdentifier(token_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(token != TOKEN_BRACE_CLOSE)
|
||||||
|
ctx.Error(StdStrBuf("'") + token_name.getData() + "' unexpected");
|
||||||
|
}
|
||||||
|
|
||||||
|
StdMeshMaterial::StdMeshMaterial():
|
||||||
|
Line(0), ReceiveShadows(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshMaterial::Load(StdMeshMaterialParserCtx& ctx)
|
||||||
|
{
|
||||||
|
Token token;
|
||||||
|
StdStrBuf token_name;
|
||||||
|
while((token = ctx.AdvanceNonEOF(token_name)) == TOKEN_IDTF)
|
||||||
|
{
|
||||||
|
if(token_name == "technique")
|
||||||
|
{
|
||||||
|
// TODO: Can there be an optional name?
|
||||||
|
ctx.AdvanceRequired(token_name, TOKEN_BRACE_OPEN);
|
||||||
|
Techniques.push_back(StdMeshMaterialTechnique());
|
||||||
|
Techniques.back().Load(ctx);
|
||||||
|
}
|
||||||
|
else if(token_name == "receive_shadows")
|
||||||
|
{
|
||||||
|
ReceiveShadows = ctx.AdvanceBoolean();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ctx.ErrorUnexpectedIdentifier(token_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(token != TOKEN_BRACE_CLOSE)
|
||||||
|
ctx.Error(StdStrBuf("'") + token_name.getData() + "' unexpected");
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshMatManager::Clear()
|
||||||
|
{
|
||||||
|
Materials.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdMeshMatManager::Parse(const char* mat_script, const char* filename, StdMeshMaterialTextureLoader& tex_loader)
|
||||||
|
{
|
||||||
|
StdMeshMaterialParserCtx ctx(mat_script, filename, tex_loader);
|
||||||
|
|
||||||
|
Token token;
|
||||||
|
StdStrBuf token_name;
|
||||||
|
while((token = ctx.Advance(token_name)) == TOKEN_IDTF)
|
||||||
|
{
|
||||||
|
if(token_name == "material")
|
||||||
|
{
|
||||||
|
// Read name
|
||||||
|
StdStrBuf material_name;
|
||||||
|
ctx.AdvanceRequired(material_name, TOKEN_IDTF);
|
||||||
|
|
||||||
|
// Check for uniqueness
|
||||||
|
std::map<StdStrBuf, StdMeshMaterial>::iterator iter = Materials.find(material_name);
|
||||||
|
if(iter != Materials.end())
|
||||||
|
ctx.Error(FormatString("Material with name '%s' is already defined in %s:%u", material_name.getData(), iter->second.FileName.getData(), iter->second.Line));
|
||||||
|
|
||||||
|
// Check if there is a parent given
|
||||||
|
Token next = ctx.AdvanceRequired(token_name, TOKEN_BRACE_OPEN, TOKEN_COLON);
|
||||||
|
// Read parent name, if any
|
||||||
|
StdMeshMaterial* parent = NULL;
|
||||||
|
if(next == TOKEN_COLON)
|
||||||
|
{
|
||||||
|
// Note that if there is a parent, then it needs to be loaded
|
||||||
|
// already. This currently makes only sense when its defined above
|
||||||
|
// in the same material script file or in a parent definition.
|
||||||
|
// We could later support material scripts in the System.c4g.
|
||||||
|
StdStrBuf parent_name;
|
||||||
|
ctx.AdvanceRequired(parent_name, TOKEN_IDTF);
|
||||||
|
ctx.AdvanceRequired(token_name, TOKEN_BRACE_OPEN);
|
||||||
|
|
||||||
|
iter = Materials.find(parent_name);
|
||||||
|
if(iter == Materials.end())
|
||||||
|
ctx.Error(StdStrBuf("Parent material '") + parent_name + "' does not exist (or is not yet loaded)");
|
||||||
|
parent = &iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy properties from parent if one is given, otherwise
|
||||||
|
// default-construct the material.
|
||||||
|
StdMeshMaterial& mat = Materials.insert(std::make_pair(material_name, parent ? StdMeshMaterial(*parent) : StdMeshMaterial())).first->second;
|
||||||
|
// Set/Overwrite source and name
|
||||||
|
mat.Name = material_name;
|
||||||
|
mat.FileName = ctx.FileName;
|
||||||
|
mat.Line = ctx.Line;
|
||||||
|
|
||||||
|
mat.Load(ctx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ctx.ErrorUnexpectedIdentifier(token_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(token != TOKEN_EOF)
|
||||||
|
ctx.Error(StdStrBuf("'") + token_name.getData() + "' unexpected");
|
||||||
|
}
|
||||||
|
|
||||||
|
const StdMeshMaterial* StdMeshMatManager::GetMaterial(const char* material_name) const
|
||||||
|
{
|
||||||
|
std::map<StdStrBuf, StdMeshMaterial>::const_iterator iter = Materials.find(StdStrBuf(material_name));
|
||||||
|
if(iter == Materials.end()) return NULL;
|
||||||
|
return &iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
// vim: et ts=2 sw=2
|
|
@ -210,11 +210,13 @@ bool CStdWindow::FindInfo()
|
||||||
// attributes for a single buffered visual in RGBA format with at least 4 bits per color
|
// attributes for a single buffered visual in RGBA format with at least 4 bits per color
|
||||||
static int attrListSgl[] = { GLX_RGBA,
|
static int attrListSgl[] = { GLX_RGBA,
|
||||||
GLX_RED_SIZE, 4, GLX_GREEN_SIZE, 4, GLX_BLUE_SIZE, 4,
|
GLX_RED_SIZE, 4, GLX_GREEN_SIZE, 4, GLX_BLUE_SIZE, 4,
|
||||||
|
GLX_DEPTH_SIZE, 8,
|
||||||
None };
|
None };
|
||||||
// attributes for a double buffered visual in RGBA format with at least 4 bits per color
|
// attributes for a double buffered visual in RGBA format with at least 4 bits per color
|
||||||
static int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER,
|
static int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER,
|
||||||
GLX_RED_SIZE, 4, GLX_GREEN_SIZE, 4, GLX_BLUE_SIZE, 4,
|
GLX_RED_SIZE, 4, GLX_GREEN_SIZE, 4, GLX_BLUE_SIZE, 4,
|
||||||
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
|
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
|
||||||
|
GLX_DEPTH_SIZE, 8,
|
||||||
None };
|
None };
|
||||||
// doublebuffered is the best
|
// doublebuffered is the best
|
||||||
Info = glXChooseVisual(dpy, DefaultScreen(dpy), attrListDbl);
|
Info = glXChooseVisual(dpy, DefaultScreen(dpy), attrListDbl);
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
www.sourceforge.net/projects/tinyxml
|
||||||
|
Original file by Yves Berquin.
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any
|
||||||
|
damages arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any
|
||||||
|
purpose, including commercial applications, and to alter it and
|
||||||
|
redistribute it freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must
|
||||||
|
not claim that you wrote the original software. If you use this
|
||||||
|
software in a product, an acknowledgment in the product documentation
|
||||||
|
would be appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and
|
||||||
|
must not be misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* THIS FILE WAS ALTERED BY Tyge Løvset, 7. April 2005.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef TIXML_USE_STL
|
||||||
|
|
||||||
|
#include "tinystr.h"
|
||||||
|
|
||||||
|
// Error value for find primitive
|
||||||
|
const TiXmlString::size_type TiXmlString::npos = static_cast< size_type >(-1);
|
||||||
|
|
||||||
|
// Null rep.
|
||||||
|
TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, '\0' };
|
||||||
|
|
||||||
|
|
||||||
|
void TiXmlString::reserve (size_type cap)
|
||||||
|
{
|
||||||
|
if (cap > capacity())
|
||||||
|
{
|
||||||
|
TiXmlString tmp;
|
||||||
|
tmp.init(length(), cap);
|
||||||
|
memcpy(tmp.start(), data(), length());
|
||||||
|
swap(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TiXmlString& TiXmlString::assign(const char* str, size_type len)
|
||||||
|
{
|
||||||
|
size_type cap = capacity();
|
||||||
|
if (len > cap || cap > 3*(len + 8))
|
||||||
|
{
|
||||||
|
TiXmlString tmp;
|
||||||
|
tmp.init(len);
|
||||||
|
memcpy(tmp.start(), str, len);
|
||||||
|
swap(tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memmove(start(), str, len);
|
||||||
|
set_size(len);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TiXmlString& TiXmlString::append(const char* str, size_type len)
|
||||||
|
{
|
||||||
|
size_type newsize = length() + len;
|
||||||
|
if (newsize > capacity())
|
||||||
|
{
|
||||||
|
reserve (newsize + capacity());
|
||||||
|
}
|
||||||
|
memmove(finish(), str, len);
|
||||||
|
set_size(newsize);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TiXmlString operator + (const TiXmlString & a, const TiXmlString & b)
|
||||||
|
{
|
||||||
|
TiXmlString tmp;
|
||||||
|
tmp.reserve(a.length() + b.length());
|
||||||
|
tmp += a;
|
||||||
|
tmp += b;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
TiXmlString operator + (const TiXmlString & a, const char* b)
|
||||||
|
{
|
||||||
|
TiXmlString tmp;
|
||||||
|
TiXmlString::size_type b_len = static_cast<TiXmlString::size_type>( strlen(b) );
|
||||||
|
tmp.reserve(a.length() + b_len);
|
||||||
|
tmp += a;
|
||||||
|
tmp.append(b, b_len);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
TiXmlString operator + (const char* a, const TiXmlString & b)
|
||||||
|
{
|
||||||
|
TiXmlString tmp;
|
||||||
|
TiXmlString::size_type a_len = static_cast<TiXmlString::size_type>( strlen(a) );
|
||||||
|
tmp.reserve(a_len + b.length());
|
||||||
|
tmp.append(a, a_len);
|
||||||
|
tmp += b;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // TIXML_USE_STL
|
|
@ -0,0 +1,304 @@
|
||||||
|
/*
|
||||||
|
www.sourceforge.net/projects/tinyxml
|
||||||
|
Original file by Yves Berquin.
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any
|
||||||
|
damages arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any
|
||||||
|
purpose, including commercial applications, and to alter it and
|
||||||
|
redistribute it freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must
|
||||||
|
not claim that you wrote the original software. If you use this
|
||||||
|
software in a product, an acknowledgment in the product documentation
|
||||||
|
would be appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and
|
||||||
|
must not be misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* THIS FILE WAS ALTERED BY Tyge Lovset, 7. April 2005.
|
||||||
|
*
|
||||||
|
* - completely rewritten. compact, clean, and fast implementation.
|
||||||
|
* - sizeof(TiXmlString) = pointer size (4 bytes on 32-bit systems)
|
||||||
|
* - fixed reserve() to work as per specification.
|
||||||
|
* - fixed buggy compares operator==(), operator<(), and operator>()
|
||||||
|
* - fixed operator+=() to take a const ref argument, following spec.
|
||||||
|
* - added "copy" constructor with length, and most compare operators.
|
||||||
|
* - added swap(), clear(), size(), capacity(), operator+().
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TIXML_USE_STL
|
||||||
|
|
||||||
|
#ifndef TIXML_STRING_INCLUDED
|
||||||
|
#define TIXML_STRING_INCLUDED
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
TiXmlString is an emulation of a subset of the std::string template.
|
||||||
|
Its purpose is to allow compiling TinyXML on compilers with no or poor STL support.
|
||||||
|
Only the member functions relevant to the TinyXML project have been implemented.
|
||||||
|
The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase
|
||||||
|
a string and there's no more room, we allocate a buffer twice as big as we need.
|
||||||
|
*/
|
||||||
|
class TiXmlString
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
// The size type used
|
||||||
|
typedef unsigned int size_type;
|
||||||
|
|
||||||
|
// Error value for find primitive
|
||||||
|
static const size_type npos; // = -1;
|
||||||
|
|
||||||
|
|
||||||
|
// TiXmlString empty constructor
|
||||||
|
TiXmlString () : rep_(&nullrep_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// TiXmlString copy constructor
|
||||||
|
TiXmlString (const TiXmlString & copy)
|
||||||
|
{
|
||||||
|
init(copy.length());
|
||||||
|
memcpy(start(), copy.data(), length());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TiXmlString constructor, based on a string
|
||||||
|
TiXmlString (const char * copy)
|
||||||
|
{
|
||||||
|
init( static_cast<size_type>( strlen(copy) ));
|
||||||
|
memcpy(start(), copy, length());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TiXmlString constructor, based on a string
|
||||||
|
TiXmlString (const char * str, size_type len)
|
||||||
|
{
|
||||||
|
init(len);
|
||||||
|
memcpy(start(), str, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TiXmlString destructor
|
||||||
|
~TiXmlString ()
|
||||||
|
{
|
||||||
|
quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// = operator
|
||||||
|
TiXmlString& operator = (const char * copy)
|
||||||
|
{
|
||||||
|
return assign( copy, (size_type)strlen(copy));
|
||||||
|
}
|
||||||
|
|
||||||
|
// = operator
|
||||||
|
TiXmlString& operator = (const TiXmlString & copy)
|
||||||
|
{
|
||||||
|
return assign(copy.start(), copy.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// += operator. Maps to append
|
||||||
|
TiXmlString& operator += (const char * suffix)
|
||||||
|
{
|
||||||
|
return append(suffix, static_cast<size_type>( strlen(suffix) ));
|
||||||
|
}
|
||||||
|
|
||||||
|
// += operator. Maps to append
|
||||||
|
TiXmlString& operator += (char single)
|
||||||
|
{
|
||||||
|
return append(&single, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// += operator. Maps to append
|
||||||
|
TiXmlString& operator += (const TiXmlString & suffix)
|
||||||
|
{
|
||||||
|
return append(suffix.data(), suffix.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Convert a TiXmlString into a null-terminated char *
|
||||||
|
const char * c_str () const { return rep_->str; }
|
||||||
|
|
||||||
|
// Convert a TiXmlString into a char * (need not be null terminated).
|
||||||
|
const char * data () const { return rep_->str; }
|
||||||
|
|
||||||
|
// Return the length of a TiXmlString
|
||||||
|
size_type length () const { return rep_->size; }
|
||||||
|
|
||||||
|
// Alias for length()
|
||||||
|
size_type size () const { return rep_->size; }
|
||||||
|
|
||||||
|
// Checks if a TiXmlString is empty
|
||||||
|
bool empty () const { return rep_->size == 0; }
|
||||||
|
|
||||||
|
// Return capacity of string
|
||||||
|
size_type capacity () const { return rep_->capacity; }
|
||||||
|
|
||||||
|
|
||||||
|
// single char extraction
|
||||||
|
const char& at (size_type index) const
|
||||||
|
{
|
||||||
|
assert( index < length() );
|
||||||
|
return rep_->str[ index ];
|
||||||
|
}
|
||||||
|
|
||||||
|
// [] operator
|
||||||
|
char& operator [] (size_type index) const
|
||||||
|
{
|
||||||
|
assert( index < length() );
|
||||||
|
return rep_->str[ index ];
|
||||||
|
}
|
||||||
|
|
||||||
|
// find a char in a string. Return TiXmlString::npos if not found
|
||||||
|
size_type find (char lookup) const
|
||||||
|
{
|
||||||
|
return find(lookup, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// find a char in a string from an offset. Return TiXmlString::npos if not found
|
||||||
|
size_type find (char tofind, size_type offset) const
|
||||||
|
{
|
||||||
|
if (offset >= length()) return npos;
|
||||||
|
|
||||||
|
for (const char* p = c_str() + offset; *p != '\0'; ++p)
|
||||||
|
{
|
||||||
|
if (*p == tofind) return static_cast< size_type >( p - c_str() );
|
||||||
|
}
|
||||||
|
return npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear ()
|
||||||
|
{
|
||||||
|
//Lee:
|
||||||
|
//The original was just too strange, though correct:
|
||||||
|
// TiXmlString().swap(*this);
|
||||||
|
//Instead use the quit & re-init:
|
||||||
|
quit();
|
||||||
|
init(0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function to reserve a big amount of data when we know we'll need it. Be aware that this
|
||||||
|
function DOES NOT clear the content of the TiXmlString if any exists.
|
||||||
|
*/
|
||||||
|
void reserve (size_type cap);
|
||||||
|
|
||||||
|
TiXmlString& assign (const char* str, size_type len);
|
||||||
|
|
||||||
|
TiXmlString& append (const char* str, size_type len);
|
||||||
|
|
||||||
|
void swap (TiXmlString& other)
|
||||||
|
{
|
||||||
|
Rep* r = rep_;
|
||||||
|
rep_ = other.rep_;
|
||||||
|
other.rep_ = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void init(size_type sz) { init(sz, sz); }
|
||||||
|
void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; }
|
||||||
|
char* start() const { return rep_->str; }
|
||||||
|
char* finish() const { return rep_->str + rep_->size; }
|
||||||
|
|
||||||
|
struct Rep
|
||||||
|
{
|
||||||
|
size_type size, capacity;
|
||||||
|
char str[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
void init(size_type sz, size_type cap)
|
||||||
|
{
|
||||||
|
if (cap)
|
||||||
|
{
|
||||||
|
// Lee: the original form:
|
||||||
|
// rep_ = static_cast<Rep*>(operator new(sizeof(Rep) + cap));
|
||||||
|
// doesn't work in some cases of new being overloaded. Switching
|
||||||
|
// to the normal allocation, although use an 'int' for systems
|
||||||
|
// that are overly picky about structure alignment.
|
||||||
|
const size_type bytesNeeded = sizeof(Rep) + cap;
|
||||||
|
const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int );
|
||||||
|
rep_ = reinterpret_cast<Rep*>( new int[ intsNeeded ] );
|
||||||
|
|
||||||
|
rep_->str[ rep_->size = sz ] = '\0';
|
||||||
|
rep_->capacity = cap;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rep_ = &nullrep_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void quit()
|
||||||
|
{
|
||||||
|
if (rep_ != &nullrep_)
|
||||||
|
{
|
||||||
|
// The rep_ is really an array of ints. (see the allocator, above).
|
||||||
|
// Cast it back before delete, so the compiler won't incorrectly call destructors.
|
||||||
|
delete [] ( reinterpret_cast<int*>( rep_ ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rep * rep_;
|
||||||
|
static Rep nullrep_;
|
||||||
|
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
inline bool operator == (const TiXmlString & a, const TiXmlString & b)
|
||||||
|
{
|
||||||
|
return ( a.length() == b.length() ) // optimization on some platforms
|
||||||
|
&& ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare
|
||||||
|
}
|
||||||
|
inline bool operator < (const TiXmlString & a, const TiXmlString & b)
|
||||||
|
{
|
||||||
|
return strcmp(a.c_str(), b.c_str()) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); }
|
||||||
|
inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; }
|
||||||
|
inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); }
|
||||||
|
inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); }
|
||||||
|
|
||||||
|
inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; }
|
||||||
|
inline bool operator == (const char* a, const TiXmlString & b) { return b == a; }
|
||||||
|
inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); }
|
||||||
|
inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); }
|
||||||
|
|
||||||
|
TiXmlString operator + (const TiXmlString & a, const TiXmlString & b);
|
||||||
|
TiXmlString operator + (const TiXmlString & a, const char* b);
|
||||||
|
TiXmlString operator + (const char* a, const TiXmlString & b);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString.
|
||||||
|
Only the operators that we need for TinyXML have been developped.
|
||||||
|
*/
|
||||||
|
class TiXmlOutStream : public TiXmlString
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
|
||||||
|
// TiXmlOutStream << operator.
|
||||||
|
TiXmlOutStream & operator << (const TiXmlString & in)
|
||||||
|
{
|
||||||
|
*this += in;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TiXmlOutStream << operator.
|
||||||
|
TiXmlOutStream & operator << (const char * in)
|
||||||
|
{
|
||||||
|
*this += in;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
} ;
|
||||||
|
|
||||||
|
#endif // TIXML_STRING_INCLUDED
|
||||||
|
#endif // TIXML_USE_STL
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
www.sourceforge.net/projects/tinyxml
|
||||||
|
Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com)
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any
|
||||||
|
damages arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any
|
||||||
|
purpose, including commercial applications, and to alter it and
|
||||||
|
redistribute it freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must
|
||||||
|
not claim that you wrote the original software. If you use this
|
||||||
|
software in a product, an acknowledgment in the product documentation
|
||||||
|
would be appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and
|
||||||
|
must not be misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tinyxml.h"
|
||||||
|
|
||||||
|
// The goal of the seperate error file is to make the first
|
||||||
|
// step towards localization. tinyxml (currently) only supports
|
||||||
|
// english error messages, but the could now be translated.
|
||||||
|
//
|
||||||
|
// It also cleans up the code a bit.
|
||||||
|
//
|
||||||
|
|
||||||
|
const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] =
|
||||||
|
{
|
||||||
|
"No error",
|
||||||
|
"Error",
|
||||||
|
"Failed to open file",
|
||||||
|
"Memory allocation failed.",
|
||||||
|
"Error parsing Element.",
|
||||||
|
"Failed to read Element name",
|
||||||
|
"Error reading Element value.",
|
||||||
|
"Error reading Attributes.",
|
||||||
|
"Error: empty tag.",
|
||||||
|
"Error reading end tag.",
|
||||||
|
"Error parsing Unknown.",
|
||||||
|
"Error parsing Comment.",
|
||||||
|
"Error parsing Declaration.",
|
||||||
|
"Error document empty.",
|
||||||
|
"Error null (0) or unexpected EOF found in input stream.",
|
||||||
|
"Error parsing CDATA.",
|
||||||
|
};
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue