openclonk/src/lib/StdMeshMaterial.h

343 lines
8.0 KiB
C++

/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2009-2010 Armin Burgmeier
* Copyright (c) 2010 Benjamin Herr
* 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 <StdBuf.h>
#include <StdSurface2.h>
#include <C4Surface.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:
StdCopyStrBuf 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 C4Surface* LoadTexture(const char* filename) = 0;
};
class StdMeshMaterialTextureUnit
{
public:
enum TexAddressModeType
{
AM_Wrap,
AM_Clamp,
AM_Mirror,
AM_Border
};
enum FilteringType
{
F_None,
F_Point,
F_Linear,
F_Anisotropic
};
enum BlendOpType
{
BO_Replace,
BO_Add,
BO_Modulate,
BO_AlphaBlend
};
enum BlendOpExType
{
BOX_Source1,
BOX_Source2,
BOX_Modulate,
BOX_ModulateX2,
BOX_ModulateX4,
BOX_Add,
BOX_AddSigned,
BOX_AddSmooth,
BOX_Subtract,
BOX_BlendDiffuseAlpha,
BOX_BlendTextureAlpha,
BOX_BlendCurrentAlpha,
BOX_BlendManual,
BOX_Dotproduct,
BOX_BlendDiffuseColor
};
enum BlendOpSourceType
{
BOS_Current,
BOS_Texture,
BOS_Diffuse,
BOS_Specular,
BOS_PlayerColor, // not specified in ogre, added in OpenClonk
BOS_Manual
};
struct Transformation
{
enum Type
{
T_SCROLL,
T_SCROLL_ANIM,
T_ROTATE,
T_ROTATE_ANIM,
T_SCALE,
T_TRANSFORM,
T_WAVE_XFORM
};
enum XFormType
{
XF_SCROLL_X,
XF_SCROLL_Y,
XF_ROTATE,
XF_SCALE_X,
XF_SCALE_Y
};
enum WaveType
{
W_SINE,
W_TRIANGLE,
W_SQUARE,
W_SAWTOOTH,
W_INVERSE_SAWTOOTH
};
Type TransformType;
union
{
struct { float X; float Y; } Scroll;
struct { float XSpeed; float YSpeed; } ScrollAnim;
struct { float Angle; } Rotate;
struct { float RevsPerSec; } RotateAnim;
struct { float X; float Y; } Scale;
struct { float M[16]; } Transform;
struct { XFormType XForm; WaveType Wave; float Base; float Frequency; float Phase; float Amplitude; } WaveXForm;
};
double GetScrollX(double t) const { assert(TransformType == T_SCROLL_ANIM); return ScrollAnim.XSpeed * t; }
double GetScrollY(double t) const { assert(TransformType == T_SCROLL_ANIM); return ScrollAnim.YSpeed * t; }
double GetRotate(double t) const { assert(TransformType == T_ROTATE_ANIM); return fmod(RotateAnim.RevsPerSec * t, 1.0) * 360.0; }
double GetWaveXForm(double t) const;
};
// Ref-counted texture. When a meterial inherits from one which contains
// a TextureUnit, then they will share the same CTexRef.
class Tex
{
public:
Tex(C4Surface* Surface); // Takes ownership
~Tex();
unsigned int RefCount;
// TODO: Note this cannot be CSurface here, because CSurface
// does not have a virtual destructor, so we couldn't delete it
// properly in that case. I am a bit annoyed that this
// currently requires a cross-ref to lib/texture. I think
// C4Surface should go away and the file loading/saving
// should be free functions instead. I also think the file
// loading/saving should be decoupled from the surfaces, so we
// can skip the surface here and simply use a CTexRef. armin.
C4Surface* Surf;
CTexRef& Texture;
};
// Simple wrapper which handles refcounting of Tex
class TexPtr
{
public:
TexPtr(C4Surface* Surface);
TexPtr(const TexPtr& other);
~TexPtr();
TexPtr& operator=(const TexPtr& other);
Tex* pTex;
};
StdMeshMaterialTextureUnit();
void LoadTexture(StdMeshMaterialParserCtx& ctx, const char* texname);
void Load(StdMeshMaterialParserCtx& ctx);
bool HasTexture() const { return !Textures.empty(); }
size_t GetNumTextures() const { return Textures.size(); }
const CTexRef& GetTexture(unsigned int i) const { return Textures[i].pTex->Texture; }
bool HasFrameAnimation() const { return Duration > 0; }
bool HasTexCoordAnimation() const { return !Transformations.empty(); }
StdCopyStrBuf Name;
float Duration; // Duration of texture animation, if any.
TexAddressModeType TexAddressMode;
float TexBorderColor[4];
FilteringType Filtering[3]; // min, max, mipmap
BlendOpExType ColorOpEx;
BlendOpSourceType ColorOpSources[2];
float ColorOpManualFactor;
float ColorOpManualColor1[3];
float ColorOpManualColor2[3];
BlendOpExType AlphaOpEx;
BlendOpSourceType AlphaOpSources[2];
float AlphaOpManualFactor;
float AlphaOpManualAlpha1;
float AlphaOpManualAlpha2;
// Transformations to be applied to texture coordinates in order
std::vector<Transformation> Transformations;
private:
std::vector<TexPtr> Textures;
};
class StdMeshMaterialPass
{
public:
enum CullHardwareType
{
CH_Clockwise,
CH_CounterClockwise,
CH_None
};
enum SceneBlendType
{
SB_One,
SB_Zero,
SB_DestColor,
SB_SrcColor,
SB_OneMinusDestColor,
SB_OneMinusSrcColor,
SB_DestAlpha,
SB_SrcAlpha,
SB_OneMinusDestAlpha,
SB_OneMinusSrcAlpha
};
StdMeshMaterialPass();
void Load(StdMeshMaterialParserCtx& ctx);
bool IsOpaque() const { return SceneBlendFactors[1] == SB_Zero; }
StdCopyStrBuf Name;
std::vector<StdMeshMaterialTextureUnit> TextureUnits;
float Ambient[4];
float Diffuse[4];
float Specular[4];
float Emissive[4];
float Shininess;
bool DepthWrite;
CullHardwareType CullHardware;
SceneBlendType SceneBlendFactors[2];
};
class StdMeshMaterialTechnique
{
public:
StdMeshMaterialTechnique();
void Load(StdMeshMaterialParserCtx& ctx);
bool IsOpaque() const;
StdCopyStrBuf Name;
std::vector<StdMeshMaterialPass> Passes;
// Filled in by gfx implementation: Whether this technique is available on
// the hardware and gfx engine (DX/GL) we are running on
bool Available;
};
class StdMeshMaterial
{
public:
StdMeshMaterial();
void Load(StdMeshMaterialParserCtx& ctx);
bool IsOpaque() const { assert(BestTechniqueIndex >= 0); return Techniques[BestTechniqueIndex].IsOpaque(); }
// Location the Material was loaded from
StdCopyStrBuf FileName;
unsigned int Line;
// Material name
StdCopyStrBuf 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;
// Filled in by gfx implementation: Best technique to use
int BestTechniqueIndex; // Don't use a pointer into the Technique vector to save us from implementing a copyctor
};
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<StdCopyStrBuf, StdMeshMaterial> Materials;
};
extern StdMeshMatManager MeshMaterialManager;
#endif