forked from Mirrors/openclonk
Merged default into mesh
commit
6da0846c87
|
@ -398,6 +398,8 @@ add_library(standard STATIC
|
|||
standard/src/StdGL.cpp
|
||||
standard/src/StdGLCtx.cpp
|
||||
standard/src/StdMarkup.cpp
|
||||
standard/src/StdMesh.cpp
|
||||
standard/src/StdMeshMaterial.cpp
|
||||
standard/src/StdNoGfx.cpp
|
||||
standard/src/StdPNG.cpp
|
||||
standard/src/StdRegistry.cpp
|
||||
|
@ -428,6 +430,8 @@ add_library(standard STATIC
|
|||
standard/inc/StdFont.h
|
||||
standard/inc/StdGL.h
|
||||
standard/inc/StdMarkup.h
|
||||
standard/inc/StdMesh.h
|
||||
standard/inc/StdMeshMaterial.h
|
||||
standard/inc/StdNoGfx.h
|
||||
standard/inc/StdPNG.h
|
||||
standard/inc/StdRandom.h
|
||||
|
@ -442,6 +446,12 @@ add_library(standard STATIC
|
|||
standard/inc/StdWindow.h
|
||||
standard/zlib/gzio.c
|
||||
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(
|
||||
|
|
12
Makefile.am
12
Makefile.am
|
@ -434,6 +434,8 @@ libstandard_a_SOURCES = \
|
|||
standard/src/StdGL.cpp \
|
||||
standard/src/StdGLCtx.cpp \
|
||||
standard/src/StdMarkup.cpp \
|
||||
standard/src/StdMesh.cpp \
|
||||
standard/src/StdMeshMaterial.cpp \
|
||||
standard/src/StdNoGfx.cpp \
|
||||
standard/src/StdPNG.cpp \
|
||||
standard/src/StdRegistry.cpp \
|
||||
|
@ -464,6 +466,8 @@ libstandard_a_SOURCES = \
|
|||
standard/inc/StdFont.h \
|
||||
standard/inc/StdGL.h \
|
||||
standard/inc/StdMarkup.h \
|
||||
standard/inc/StdMesh.h \
|
||||
standard/inc/StdMeshMaterial.h \
|
||||
standard/inc/StdNoGfx.h \
|
||||
standard/inc/StdPNG.h \
|
||||
standard/inc/StdRandom.h \
|
||||
|
@ -477,7 +481,13 @@ libstandard_a_SOURCES = \
|
|||
standard/inc/StdVideo.h \
|
||||
standard/inc/StdWindow.h \
|
||||
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
|
||||
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_ScenarioObjects "Objects.txt"
|
||||
#define C4CFN_ScenarioDesc "Desc%s.rtf"
|
||||
#define C4CFN_DefMaterials "*.material"
|
||||
#define C4CFN_DefMesh "Graphics.mesh.xml"
|
||||
#define C4CFN_DefGraphics "Graphics.bmp"
|
||||
#define C4CFN_DefGraphicsPNG "Graphics.png"
|
||||
#define C4CFN_ClrByOwnerPNG "Overlay.png"
|
||||
|
|
|
@ -44,16 +44,31 @@ class C4DefGraphics
|
|||
|
||||
C4DefGraphics *GetLast(); // get last graphics in list
|
||||
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
|
||||
|
||||
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
|
||||
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 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
|
||||
void Clear(); // clear fields; delete additional graphics
|
||||
bool IsColorByOwner() // returns whether ColorByOwner-surfaces have been created
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#ifndef INC_C4Game
|
||||
#define INC_C4Game
|
||||
|
||||
|
||||
#include <StdMeshMaterial.h>
|
||||
#include <C4GameParameters.h>
|
||||
#include <C4PlayerInfo.h>
|
||||
#include <C4RoundResults.h>
|
||||
|
@ -82,7 +82,7 @@ class C4Game
|
|||
|
||||
C4PathFinder PathFinder;
|
||||
C4TransferZones TransferZones;
|
||||
C4Group ScenarioFile;
|
||||
C4Group ScenarioFile;
|
||||
C4GroupSet GroupSet;
|
||||
C4Group *pParentGroup;
|
||||
C4Extra Extra;
|
||||
|
@ -94,6 +94,7 @@ class C4Game
|
|||
#endif
|
||||
C4Scoreboard Scoreboard;
|
||||
C4VideoPlayer VideoPlayer;
|
||||
StdMeshMatManager MaterialManager;
|
||||
class C4Network2Stats *pNetworkStatistics; // may be NULL if no statistics are recorded
|
||||
class C4KeyboardInput &KeyboardInput;
|
||||
class C4FileMonitor *pFileMonitor;
|
||||
|
|
|
@ -173,6 +173,7 @@ class C4Object: public C4PropList
|
|||
C4NotifyingObjectList Contents;
|
||||
C4MaterialList *MaterialContents; // SyncClearance-NoSave //
|
||||
C4DefGraphics *pGraphics; // currently set object graphics
|
||||
StdMeshInstance* pMeshInstance; // Instance for mesh-type objects
|
||||
C4Effect *pEffects; // linked list of effects
|
||||
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 DrawActionFace(C4TargetFacet &cgo, float offX, float offY);
|
||||
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 ClearPointers(C4Object *ptr);
|
||||
BOOL ExecMovement();
|
||||
|
|
|
@ -201,6 +201,7 @@ P_InLiquidAction,
|
|||
P_TurnAction,
|
||||
P_Reverse,
|
||||
P_Step,
|
||||
P_Animation,
|
||||
P_LAST };
|
||||
|
||||
// There is only one Stringtable in Game.ScriptEngine
|
||||
|
|
|
@ -525,7 +525,7 @@ BOOL C4Def::Load(C4Group &hGroup,
|
|||
|
||||
// Read surface 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));
|
||||
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 (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)
|
||||
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?
|
||||
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();
|
||||
|
||||
// draw overlays
|
||||
|
|
|
@ -42,6 +42,35 @@
|
|||
#include <C4GameObjects.h>
|
||||
#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(C4Def *pOwnDef)
|
||||
|
@ -49,6 +78,7 @@ C4DefGraphics::C4DefGraphics(C4Def *pOwnDef)
|
|||
// store def
|
||||
pDef = pOwnDef;
|
||||
// zero fields
|
||||
Type = TYPE_Bitmap;
|
||||
Bitmap = BitmapClr = NULL;
|
||||
pNext = NULL;
|
||||
fColorBitmapAutoCreated = false;
|
||||
|
@ -64,8 +94,17 @@ C4DefGraphics *C4DefGraphics::GetLast()
|
|||
void C4DefGraphics::Clear()
|
||||
{
|
||||
// zero own fields
|
||||
if (BitmapClr) { delete BitmapClr; BitmapClr=NULL; }
|
||||
if (Bitmap) { delete Bitmap; Bitmap=NULL; }
|
||||
switch (Type)
|
||||
{
|
||||
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
|
||||
C4AdditionalDefGraphics *pGrp2N = pNext, *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;
|
||||
fColorBitmapAutoCreated = true;
|
||||
}
|
||||
Type = TYPE_Bitmap;
|
||||
// success
|
||||
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
|
||||
if (!LoadBitmap(hGroup, C4CFN_DefGraphics, C4CFN_DefGraphicsPNG, C4CFN_ClrByOwnerPNG, fColorByOwner)) return false;
|
||||
|
||||
// load additional graphics
|
||||
// first, search all png-graphics in NewGfx
|
||||
char Filename[_MAX_PATH+1]; *Filename=0;
|
||||
C4DefGraphics *pLastGraphics = this;
|
||||
int32_t iWildcardPos;
|
||||
iWildcardPos = SCharPos('*', C4CFN_DefGraphicsExPNG);
|
||||
|
@ -251,6 +347,7 @@ C4PortraitGraphics *C4PortraitGraphics::Get(const char *szGrpName)
|
|||
|
||||
bool C4DefGraphics::CopyGraphicsFrom(C4DefGraphics &rSource)
|
||||
{
|
||||
if (Type != TYPE_Bitmap) return false; // TODO!
|
||||
// clear previous
|
||||
if (BitmapClr) { delete BitmapClr; BitmapClr=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)
|
||||
{
|
||||
if(Type != TYPE_Bitmap) return; // TODO
|
||||
// create facet and draw it
|
||||
C4Surface *pSfc = BitmapClr ? BitmapClr : Bitmap; if (!pSfc) return;
|
||||
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)
|
||||
{
|
||||
// safety
|
||||
if (!pGfxPortrait || !szFilename || !pGfxPortrait->Bitmap) return false;
|
||||
if (!pGfxPortrait || !szFilename || pGfxPortrait->Type != C4DefGraphics::TYPE_Bitmap || !pGfxPortrait->Bitmap) return false;
|
||||
// save files
|
||||
if (pGfxPortrait->fColorBitmapAutoCreated)
|
||||
{
|
||||
|
@ -602,6 +700,7 @@ void C4GraphicsOverlay::UpdateFacet()
|
|||
if (eMode == MODE_Object) return;
|
||||
// otherwise, source graphics must be specified
|
||||
if (!pSourceGfx) return;
|
||||
if (pSourceGfx->Type != C4DefGraphics::TYPE_Bitmap) return;
|
||||
C4Def *pDef = pSourceGfx->pDef;
|
||||
assert(pDef);
|
||||
fZoomToShape = false;
|
||||
|
|
|
@ -594,6 +594,7 @@ void C4Game::Clear()
|
|||
KeyboardInput.Clear();
|
||||
SetMusicLevel(100);
|
||||
PlayList.Clear();
|
||||
MaterialManager.Clear();
|
||||
|
||||
// global fullscreen class is not cleared, because it holds the carrier window
|
||||
// but the menu must be cleared (maybe move Fullscreen.Menu somewhere else?)
|
||||
|
|
|
@ -153,6 +153,7 @@ void C4Object::Default()
|
|||
pLayer=NULL;
|
||||
pSolidMaskData=NULL;
|
||||
pGraphics=NULL;
|
||||
pMeshInstance=NULL;
|
||||
pDrawTransform=NULL;
|
||||
pEffects=NULL;
|
||||
pGfxOverlay=NULL;
|
||||
|
@ -182,6 +183,15 @@ BOOL C4Object::Init(C4PropList *pDef, C4Object *pCreator,
|
|||
|
||||
// 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;
|
||||
|
||||
// Position
|
||||
|
@ -411,6 +421,18 @@ void C4Object::UpdateGraphics(bool fGraphicsChanged, bool fTemp)
|
|||
// ensure SolidMask-rect lies within new graphics-rect
|
||||
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
|
||||
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)
|
||||
{
|
||||
const float swdt = float(Def->Shape.Wdt);
|
||||
|
@ -481,10 +522,11 @@ void C4Object::DrawFace(C4TargetFacet &cgo, float offX, float offY, int32_t iPha
|
|||
// Straight
|
||||
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,
|
||||
cgo.Surface, tx, ty, twdt, thgt,
|
||||
TRUE, NULL);
|
||||
TRUE, NULL);*/
|
||||
}
|
||||
// Rotated or transformed
|
||||
else
|
||||
|
@ -499,10 +541,11 @@ void C4Object::DrawFace(C4TargetFacet &cgo, float offX, float offY, int32_t iPha
|
|||
{
|
||||
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,
|
||||
cgo.Surface, tx, ty, twdt, thgt,
|
||||
TRUE, &rot);
|
||||
TRUE, &rot);*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -547,10 +590,11 @@ void C4Object::DrawActionFace(C4TargetFacet &cgo, float offX, float offY)
|
|||
// Straight
|
||||
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,
|
||||
cgo.Surface, tx, ty, twdt, thgt,
|
||||
TRUE, NULL);
|
||||
TRUE, NULL);*/
|
||||
}
|
||||
// Rotated or transformed
|
||||
else
|
||||
|
@ -567,10 +611,11 @@ void C4Object::DrawActionFace(C4TargetFacet &cgo, float offX, float 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,
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2253,7 +2312,8 @@ void C4Object::Draw(C4TargetFacet &cgo, int32_t iByPlayer, DrawMode eDrawMode)
|
|||
{ if (FrontParticles && !Contained) FrontParticles.Draw(cgo,this); return; }
|
||||
|
||||
// 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 //////////////////////////////////////////////////////////////////////
|
||||
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),
|
||||
TRUE);
|
||||
}
|
||||
else if (Action.Facet.Surface)
|
||||
else if (Action.Facet.Surface || GetGraphics()->Type != C4DefGraphics::TYPE_Bitmap)
|
||||
DrawActionFace(cgo, offX, offY);
|
||||
}
|
||||
|
||||
|
@ -3161,7 +3221,7 @@ void C4Object::Clear()
|
|||
if (pEffects) { delete pEffects; pEffects=NULL; }
|
||||
if (FrontParticles) FrontParticles.Clear();
|
||||
if (BackParticles) BackParticles.Clear();
|
||||
if (pSolidMaskData) { delete pSolidMaskData; pSolidMaskData=NULL; }
|
||||
if (pSolidMaskData) { delete pSolidMaskData; pSolidMaskData=NULL; }
|
||||
if (Menu) delete Menu; Menu=NULL;
|
||||
if (MaterialContents) delete MaterialContents; MaterialContents=NULL;
|
||||
// clear commands!
|
||||
|
@ -3172,6 +3232,7 @@ void C4Object::Clear()
|
|||
}
|
||||
if (pDrawTransform) { delete pDrawTransform; pDrawTransform=NULL; }
|
||||
if (pGfxOverlay) { delete pGfxOverlay; pGfxOverlay=NULL; }
|
||||
if (pMeshInstance) { delete pMeshInstance; pMeshInstance = NULL; }
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
// 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
|
||||
// the bounds-check is done in CStdDDraw::GetPixel()
|
||||
CSurface *sfcGraphics = GetGraphics()->GetBitmap();
|
||||
|
@ -4028,6 +4092,16 @@ BOOL C4Object::SetAction(C4PropList * Act, C4Object *pTarget, C4Object *pTarget2
|
|||
if (LastAction->GetPropertyInt(P_NoOtherAction) && !fForce)
|
||||
if (Act != LastAction)
|
||||
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
|
||||
if (LastAction)
|
||||
if (Act != LastAction)
|
||||
|
@ -5301,6 +5375,7 @@ void C4Object::ExecAction()
|
|||
if (pAction->GetPropertyInt(P_Delay))
|
||||
{
|
||||
Action.PhaseDelay+=iPhaseAdvance;
|
||||
bool set_new_action = false;
|
||||
if (Action.PhaseDelay >= pAction->GetPropertyInt(P_Delay))
|
||||
{
|
||||
// Advance Phase
|
||||
|
@ -5316,15 +5391,25 @@ void C4Object::ExecAction()
|
|||
{
|
||||
// set new action if it's not Hold
|
||||
if (pAction->GetPropertyStr(P_NextAction) == Strings.P[P_Hold])
|
||||
{
|
||||
Action.Phase = pAction->GetPropertyInt(P_Length)-1;
|
||||
Action.PhaseDelay = pAction->GetPropertyInt(P_Delay)-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set new action
|
||||
set_new_action = true;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 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_Reverse] = RegString("Reverse");
|
||||
P[P_Step] = RegString("Step");
|
||||
P[P_Animation] = RegString("Animation");
|
||||
P[P_Visibility] = RegString("Visibility");
|
||||
P[P_Parallaxity] = RegString("Parallaxity");
|
||||
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(); }
|
||||
|
||||
// less-than operation for map
|
||||
inline bool operator <(const StdStrBuf &v2)
|
||||
inline bool operator <(const StdStrBuf &v2) const
|
||||
{
|
||||
int iLen = getLength(), iLen2 = v2.getLength();
|
||||
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
|
||||
extern StdStrBuf FormatString(const char *szFmt, ...) GNUC_FORMAT_ATTRIBUTE;
|
||||
extern StdStrBuf FormatStringV(const char *szFmt, va_list args);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <StdSurface8.h>
|
||||
#include <StdFont.h>
|
||||
#include <StdBuf.h>
|
||||
#include <StdMesh.h>
|
||||
|
||||
// texref-predef
|
||||
class CStdDDraw;
|
||||
|
@ -287,7 +288,9 @@ class CStdDDraw
|
|||
BOOL Blit(SURFACE sfcSource, float fx, float fy, float fwdt, float fhgt,
|
||||
SURFACE sfcTarget, float tx, float ty, float twdt, float thgt,
|
||||
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 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)
|
||||
SURFACE sfcTarget, int tx, int ty, int twdt, int thgt,
|
||||
BOOL fSrcColKey=FALSE, CBltTransform *pTransform=NULL);
|
||||
|
|
|
@ -113,7 +113,8 @@ class CStdGL : public CStdDDraw
|
|||
#endif
|
||||
// Blit
|
||||
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,
|
||||
SURFACE sfcTarget, float tx, float ty, float wdt, float hgt, const SURFACE textures[]);
|
||||
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 void FillBG(DWORD dwClr=0) { }
|
||||
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 DrawQuadDw(SURFACE, float *, DWORD, DWORD, DWORD, 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;
|
||||
}
|
||||
|
||||
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,
|
||||
SURFACE sfcTarget, int tx, int ty, int twdt, int thgt,
|
||||
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,
|
||||
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;
|
||||
// set some default states
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LESS);
|
||||
glShadeModel(GL_FLAT);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
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
|
||||
static int attrListSgl[] = { GLX_RGBA,
|
||||
GLX_RED_SIZE, 4, GLX_GREEN_SIZE, 4, GLX_BLUE_SIZE, 4,
|
||||
GLX_DEPTH_SIZE, 8,
|
||||
None };
|
||||
// attributes for a double buffered visual in RGBA format with at least 4 bits per color
|
||||
static int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER,
|
||||
GLX_RED_SIZE, 4, GLX_GREEN_SIZE, 4, GLX_BLUE_SIZE, 4,
|
||||
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
|
||||
GLX_DEPTH_SIZE, 8,
|
||||
None };
|
||||
// doublebuffered is the best
|
||||
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