Merged default into mesh

stable-5.2
Armin Burgmeier 2009-07-27 21:49:33 -04:00
commit 6da0846c87
42 changed files with 19200 additions and 30 deletions

View File

@ -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(

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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;

View File

@ -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();

View File

@ -201,6 +201,7 @@ P_InLiquidAction,
P_TurnAction,
P_Reverse,
P_Step,
P_Animation,
P_LAST };
// There is only one Stringtable in Game.ScriptEngine

View File

@ -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

View File

@ -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;

View File

@ -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?)

View File

@ -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;
}

View File

@ -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()); }
};

View File

@ -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");

View File

@ -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

View File

@ -0,0 +1 @@
Friedliebende grüne Zeitgenossen.

View File

@ -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

View File

@ -0,0 +1,2 @@
DE:Monster
US:Monster

View File

@ -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
}
}
}

View File

@ -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);
}

View File

@ -0,0 +1,3 @@
TxtMovement=Bewegen
TxtLeave=Zurückverwandeln
Name=Monster

View File

@ -0,0 +1,3 @@
TxtMovement=Move
TxtLeave=Retransform
Name=Monster

View File

@ -0,0 +1,5 @@
#strict 2
func Initialize()
{
CreateObject(MONS, LandscapeWidth()/2, LandscapeHeight()/2);
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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) { }

View File

@ -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)

View File

@ -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[])
{

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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