OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
StdMeshMaterial.h
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 
17 #ifndef INC_StdMeshMaterial
18 #define INC_StdMeshMaterial
19 
20 #include "lib/StdBuf.h"
21 #include "graphics/C4Surface.h"
22 #include "graphics/C4Shader.h"
23 
24 #include <vector>
25 #include <map>
26 #include <tuple>
27 
28 // TODO: Support more features of OGRE material scripts
29 // Refer to http://www.ogre3d.org/docs/manual/manual_14.html
30 
32 
33 class StdMeshMaterialError: public std::exception
34 {
35 public:
36  StdMeshMaterialError(const StdStrBuf& message, const char* file, unsigned int line);
37  virtual ~StdMeshMaterialError() throw() {}
38 
39  virtual const char* what() const throw() { return Buf.getData(); }
40 
41 protected:
43 };
44 
46 {
47 public:
48  enum Type {
50  AUTO_TEXTURE_MATRIX, // Texture matrix for the i-th texture
51  INT,
57  };
58 
59  enum Auto {
60  // TODO: OGRE auto values
62  };
63 
64  StdMeshMaterialShaderParameter(); // type=FLOAT, value uninitialized
65  StdMeshMaterialShaderParameter(Type type); // value uninitialized
69 
72 
73  Type GetType() const { return type; }
74  void SetType(Type type); // changes type, new value is uninitialized
75 
76  // Getters
77  Auto GetAuto() const { assert(type == AUTO); return a; }
78  int GetInt() const { assert(type == INT || type == AUTO_TEXTURE_MATRIX); return i; }
79  float GetFloat() const { assert(type == FLOAT); return f[0]; }
80  const float* GetFloatv() const { assert(type == FLOAT2 || type == FLOAT3 || type == FLOAT4); return f; }
81  const float* GetMatrix() const { assert(type == MATRIX_4X4); return matrix; }
82 
83  // Setters
84  Auto& GetAuto() { assert(type == AUTO); return a; }
85  int& GetInt() { assert(type == INT || type == AUTO_TEXTURE_MATRIX); return i; }
86  float& GetFloat() { assert(type == FLOAT); return f[0]; }
87  float* GetFloatv() { assert(type == FLOAT2 || type == FLOAT3 || type == FLOAT4); return f; }
88  float* GetMatrix() { assert(type == MATRIX_4X4); return matrix; }
89 private:
90  void CopyShallow(const StdMeshMaterialShaderParameter& other);
91  void CopyDeep(const StdMeshMaterialShaderParameter& other);
92  void Move(StdMeshMaterialShaderParameter &&other);
93 
94  Type type;
95 
96  union {
97  Auto a;
98  int i;
99  float f[4];
100  float* matrix; // 16 floats, row-major order
101  };
102 };
103 
105 {
106 public:
108 
109  void Load(StdMeshMaterialParserCtx& ctx);
110 
112 
113  std::vector<std::pair<StdCopyStrBuf, StdMeshMaterialShaderParameter> > NamedParameters;
114 private:
117 };
118 
123 };
124 
125 // Interface to load additional resources.
126 // Given a texture filename occuring in the
127 // material script, this should load the texture from wherever the material
128 // script is actually loaded, for example from a C4Group.
129 // Given a shader filename, this should load the shader text.
131 {
132 public:
133  virtual C4Surface* LoadTexture(const char* filename) = 0;
134  virtual StdStrBuf LoadShaderCode(const char* filename) = 0;
135  virtual void AddShaderSlices(C4Shader& shader, int ssc) = 0; // add default shader slices
137 };
138 
139 // This is just a container class to hold the shader code; the C4Shader
140 // objects are later created from that code by mixing them with the default
141 // slices.
143 {
144 public:
145  StdMeshMaterialShader(const char* filename, const char* name, const char* language, StdMeshMaterialShaderType /* type */, const char* code):
146  Filename(filename), Name(name), Language(language), Code(code)
147  {}
148 
149  const char* GetFilename() const { return Filename.getData(); }
150  const char* GetCode() const { return Code.getData(); }
151 
152 private:
153  StdCopyStrBuf Filename;
154  StdCopyStrBuf Name;
155  StdCopyStrBuf Language;
156  StdCopyStrBuf Code;
157 };
158 
160 {
161 public:
162  StdMeshMaterialProgram(const char* name, const StdMeshMaterialShader* fragment_shader, const StdMeshMaterialShader* vertex_shader, const StdMeshMaterialShader* geometry_shader);
163  bool AddParameterNames(const StdMeshMaterialShaderParameters& parameters); // returns true if some parameter names were not yet registered.
164 
165  bool IsCompiled() const { return Shader.Initialised(); }
166  bool Compile(StdMeshMaterialLoader& loader);
167 
168  const C4Shader* GetShader(int ssc) const;
169  int GetParameterIndex(const char* name) const;
170 
171  const StdMeshMaterialShader* GetFragmentShader() const { return FragmentShader; }
172  const StdMeshMaterialShader* GetVertexShader() const { return VertexShader; }
173  const StdMeshMaterialShader* GetGeometryShader() const { return GeometryShader; }
174 private:
175  bool CompileShader(StdMeshMaterialLoader& loader, C4Shader& shader, int ssc);
176 
177  // Human-readable program name
178  const StdCopyStrBuf Name;
179 
180  // Program components
181  const StdMeshMaterialShader* FragmentShader;
182  const StdMeshMaterialShader* VertexShader;
183  const StdMeshMaterialShader* GeometryShader;
184 
185  // Compiled shaders
186  C4Shader Shader;
187  C4Shader ShaderMod2;
188  C4Shader ShaderLight;
189  C4Shader ShaderLightMod2;
190 
191  // Filled as program references are encountered;
192  std::vector<StdCopyStrBuf> ParameterNames;
193 };
194 
196 {
197 public:
199  {
204  };
205 
207  {
212  };
213 
215  {
220  };
221 
223  {
239  };
240 
242  {
247  BOS_PlayerColor, // not specified in ogre, added in OpenClonk
249  };
250 
252  {
253  enum Type
254  {
262  };
263 
265  {
271  };
272 
273  enum WaveType
274  {
280  };
281 
283 
284  union
285  {
286  struct { float X; float Y; } Scroll;
287  struct { float XSpeed; float YSpeed; } ScrollAnim;
288  struct { float Angle; } Rotate;
289  struct { float RevsPerSec; } RotateAnim;
290  struct { float X; float Y; } Scale;
291  struct { float M[16]; } Transform;
292  struct { XFormType XForm; WaveType Wave; float Base; float Frequency; float Phase; float Amplitude; } WaveXForm;
293  };
294 
295  double GetScrollX(double t) const { assert(TransformType == T_SCROLL_ANIM); return ScrollAnim.XSpeed * t; }
296  double GetScrollY(double t) const { assert(TransformType == T_SCROLL_ANIM); return ScrollAnim.YSpeed * t; }
297  double GetRotate(double t) const { assert(TransformType == T_ROTATE_ANIM); return fmod(RotateAnim.RevsPerSec * t, 1.0) * 360.0; }
298  double GetWaveXForm(double t) const;
299  };
300 
301  // Ref-counted texture. When a meterial inherits from one which contains
302  // a TextureUnit, then they will share the same C4TexRef.
303  class Tex
304  {
305  public:
306  Tex(C4Surface* Surface); // Takes ownership
307  ~Tex();
308 
309  unsigned int RefCount;
310 
311  // TODO: Note this cannot be C4Surface here, because C4Surface
312  // does not have a virtual destructor, so we couldn't delete it
313  // properly in that case. I am a bit annoyed that this
314  // currently requires a cross-ref to lib/texture. I think
315  // C4Surface should go away and the file loading/saving
316  // should be free functions instead. I also think the file
317  // loading/saving should be decoupled from the surfaces, so we
318  // can skip the surface here and simply use a C4TexRef. armin.
321  };
322 
323  // Simple wrapper which handles refcounting of Tex
324  class TexPtr
325  {
326  public:
327  TexPtr(C4Surface* Surface);
328  TexPtr(const TexPtr& other);
329  ~TexPtr();
330 
331  TexPtr& operator=(const TexPtr& other);
332 
334  };
335 
337 
338  void LoadTexture(StdMeshMaterialParserCtx& ctx, const char* texname);
339  void Load(StdMeshMaterialParserCtx& ctx);
340 
341  bool HasTexture() const { return !Textures.empty(); }
342  size_t GetNumTextures() const { return Textures.size(); }
343  const C4TexRef& GetTexture(unsigned int i) const { return Textures[i].pTex->Texture; }
344  bool HasFrameAnimation() const { return Duration > 0; }
345  bool HasTexCoordAnimation() const { return !Transformations.empty(); }
346 
348  float Duration; // Duration of texture animation, if any.
349 
351  float TexBorderColor[4];
352  FilteringType Filtering[3]; // min, max, mipmap
353 
359 
365 
366  // Transformations to be applied to texture coordinates in order
367  std::vector<Transformation> Transformations;
368 
369 private:
370  std::vector<TexPtr> Textures;
371 };
372 
374 {
375 public:
377  {
381  };
382 
384  {
395  };
396 
398  {
407  };
408 
410  void Load(StdMeshMaterialParserCtx& ctx);
411 
412  bool IsOpaque() const { return SceneBlendFactors[1] == SB_Zero; }
413 
415  std::vector<StdMeshMaterialTextureUnit> TextureUnits;
416 
417  float Ambient[4];
418  float Diffuse[4];
419  float Specular[4];
420  float Emissive[4];
421  float Shininess;
422 
425 
431 
433  {
434  // This points into the StdMeshMatManager maps
436  // Parameters for this instance
438  };
439 
441  {
442  public:
443  ProgramInstance(const StdMeshMaterialProgram* program, const ShaderInstance* fragment_instance, const ShaderInstance* vertex_instance, const ShaderInstance* geometry_instance);
444 
445  // This points into the StdMeshMatManager map
447 
448  // Parameters for this instance
449  struct ParameterRef {
451  int UniformIndex; // Index into parameter table for this program
452  };
453 
454  std::vector<ParameterRef> Parameters;
455 
456  private:
457  void LoadParameterRefs(const ShaderInstance* instance);
458  };
459 
463 
464  // This is a shared_ptr and not a unique_ptr so that this class is
465  // copyable, so it can be inherited. However, when the inherited
466  // material is prepared, the ProgramInstance will be overwritten
467  // anyway, so in that sense a unique_ptr would be enough. We could
468  // change it and make this class only movable (not copyable), and
469  // provide inheritance by copying all other fields, and letting
470  // PrepareMaterial fill the program instance.
471  std::shared_ptr<ProgramInstance> Program;
472 
473 private:
474  void LoadShaderRef(StdMeshMaterialParserCtx& ctx, StdMeshMaterialShaderType type);
475 };
476 
478 {
479 public:
481 
482  void Load(StdMeshMaterialParserCtx& ctx);
483 
484  bool IsOpaque() const;
485 
487  std::vector<StdMeshMaterialPass> Passes;
488 
489  // Filled in by gfx implementation: Whether this technique is available on
490  // the hardware and gfx engine (DX/GL) we are running on
491  bool Available;
492 };
493 
495 {
496 public:
497  StdMeshMaterial();
498  void Load(StdMeshMaterialParserCtx& ctx);
499 
500  bool IsOpaque() const { assert(BestTechniqueIndex >= 0); return Techniques[BestTechniqueIndex].IsOpaque(); }
501 
502  // Location the Material was loaded from
504  unsigned int Line;
505 
506  // Material name
508 
509  // Not currently used in Clonk, but don't fail when we see this in a
510  // Material script:
512 
513  // Available techniques
514  std::vector<StdMeshMaterialTechnique> Techniques;
515 
516  // Filled in by gfx implementation: Best technique to use
517  int BestTechniqueIndex; // Don't use a pointer into the Technique vector to save us from implementing a copyctor
518 };
519 
521 {
522  friend class StdMeshMaterialUpdate;
523 private:
524  typedef std::map<StdCopyStrBuf, StdMeshMaterial> MaterialMap;
525 
526 public:
530  };
531 
532  class Iterator
533  {
534  friend class StdMeshMatManager;
535  public:
536  Iterator(const MaterialMap::iterator& iter): iter_(iter) {}
537  Iterator(const Iterator& iter): iter_(iter.iter_) {}
538 
539  Iterator operator=(const Iterator& iter) { iter_ = iter.iter_; return *this; }
540  Iterator& operator++() { ++iter_; return *this; }
541  bool operator==(const Iterator& other) const { return iter_ == other.iter_; }
542  bool operator!=(const Iterator& other) const { return iter_ != other.iter_; }
543 
544  const StdMeshMaterial& operator*() const { return iter_->second; }
545  const StdMeshMaterial* operator->() const { return &iter_->second; }
546  private:
547  MaterialMap::iterator iter_;
548  };
549 
550  // Remove all materials from manager. Make sure there is no StdMesh
551  // referencing any out there before calling this.
552  void Clear();
553 
554  // Parse a material script file, and add the materials to the manager.
555  // filename may be nullptr if the source is not a file. It will only be used
556  // for error messages.
557  // Throws StdMeshMaterialError.
558  // Returns a set of all loaded materials.
559  std::set<StdCopyStrBuf> Parse(const char* mat_script, const char* filename, StdMeshMaterialLoader& loader);
560 
561  // Get material by name. nullptr if there is no such material with this name.
562  const StdMeshMaterial* GetMaterial(const char* material_name) const;
563 
564  Iterator Begin() { return Iterator(Materials.begin()); }
565  Iterator End() { return Iterator(Materials.end()); }
566  void Remove(const StdStrBuf& name, class StdMeshMaterialUpdate* update);
567  Iterator Remove(const Iterator& iter, class StdMeshMaterialUpdate* update);
568 
569  const StdMeshMaterialShader* AddShader(const char* filename, const char* name, const char* language, StdMeshMaterialShaderType type, const char* text, uint32_t load_flags); // if load_flags & SMM_AcceptExisting, the function returns the existing shader, otherwise returns nullptr.
570  const StdMeshMaterialProgram* AddProgram(const char* name, StdMeshMaterialLoader& loader, const StdMeshMaterialPass::ShaderInstance& fragment_shader, const StdMeshMaterialPass::ShaderInstance& vertex_shader, const StdMeshMaterialPass::ShaderInstance& geometry_shader); // returns nullptr if shader code cannot be compiled
571 
572  const StdMeshMaterialShader* GetFragmentShader(const char* name) const;
573  const StdMeshMaterialShader* GetVertexShader(const char* name) const;
574  const StdMeshMaterialShader* GetGeometryShader(const char* name) const;
575 private:
576  MaterialMap Materials;
577 
578  // Shader code for custom shaders.
579  typedef std::map<StdCopyStrBuf, std::unique_ptr<StdMeshMaterialShader>> ShaderMap;
580  ShaderMap FragmentShaders;
581  ShaderMap VertexShaders;
582  ShaderMap GeometryShaders;
583 
584  // Linked programs
585  typedef std::map<std::tuple<const StdMeshMaterialShader*, const StdMeshMaterialShader*, const StdMeshMaterialShader*>, std::unique_ptr<StdMeshMaterialProgram> > ProgramMap;
586  ProgramMap Programs;
587 };
588 
590 
591 #endif
TexAddressModeType TexAddressMode
const char * getData() const
Definition: StdBuf.h:450
void LoadTexture(StdMeshMaterialParserCtx &ctx, const char *texname)
void Load(StdMeshMaterialParserCtx &ctx)
const StdMeshMaterialShader * GetGeometryShader(const char *name) const
void Load(StdMeshMaterialParserCtx &ctx)
StdCopyStrBuf FileName
StdMeshMaterialShaderParameters Parameters
ShaderInstance FragmentShader
StdMeshMatManager MeshMaterialManager
ShaderInstance GeometryShader
StdMeshMaterialShader(const char *filename, const char *name, const char *language, StdMeshMaterialShaderType, const char *code)
BlendOpSourceType ColorOpSources[2]
const StdMeshMaterial * operator->() const
SceneBlendType SceneBlendFactors[2]
bool IsOpaque() const
bool operator==(const Iterator &other) const
const StdMeshMaterialShader * Shader
std::vector< ParameterRef > Parameters
#define a
Iterator operator=(const Iterator &iter)
const StdMeshMaterialShader * GetGeometryShader() const
virtual const char * what() const
ShaderInstance VertexShader
Iterator(const Iterator &iter)
bool operator!=(const Iterator &other) const
virtual void AddShaderSlices(C4Shader &shader, int ssc)=0
const StdMeshMaterialShader * GetVertexShader() const
virtual C4Surface * LoadTexture(const char *filename)=0
std::vector< Transformation > Transformations
virtual StdStrBuf LoadShaderCode(const char *filename)=0
size_t GetNumTextures() const
TexPtr & operator=(const TexPtr &other)
StdMeshMaterialShaderParameter & operator=(const StdMeshMaterialShaderParameter &other)
const StdMeshMaterialShader * GetFragmentShader() const
void Load(StdMeshMaterialParserCtx &ctx)
StdMeshMaterialShaderType
const float * GetMatrix() const
const StdMeshMaterial & operator*() const
virtual ~StdMeshMaterialError()
std::set< StdCopyStrBuf > Parse(const char *mat_script, const char *filename, StdMeshMaterialLoader &loader)
StdMeshMaterialShaderParameter & AddParameter(const char *name, StdMeshMaterialShaderParameter::Type type)
bool HasTexCoordAnimation() const
StdMeshMaterialProgram(const char *name, const StdMeshMaterialShader *fragment_shader, const StdMeshMaterialShader *vertex_shader, const StdMeshMaterialShader *geometry_shader)
int Angle(int iX1, int iY1, int iX2, int iY2)
Definition: Standard.cpp:35
const float * GetFloatv() const
BlendOpSourceType AlphaOpSources[2]
const StdMeshMaterialShader * GetFragmentShader(const char *name) const
StdMeshMaterialError(const StdStrBuf &message, const char *file, unsigned int line)
int GetParameterIndex(const char *name) const
Iterator(const MaterialMap::iterator &iter)
CullHardwareType CullHardware
bool Compile(StdMeshMaterialLoader &loader)
const C4TexRef & GetTexture(unsigned int i) const
std::shared_ptr< ProgramInstance > Program
bool Initialised() const
Definition: C4Shader.h:107
std::vector< StdMeshMaterialPass > Passes
std::vector< StdMeshMaterialTextureUnit > TextureUnits
bool AddParameterNames(const StdMeshMaterialShaderParameters &parameters)
unsigned int Line
void Load(StdMeshMaterialParserCtx &ctx)
void Load(StdMeshMaterialParserCtx &ctx)
C4MaterialMap MaterialMap
Definition: C4Material.cpp:970
DepthFunctionType AlphaRejectionFunction
StdCopyStrBuf Name
const StdMeshMaterialProgram * AddProgram(const char *name, StdMeshMaterialLoader &loader, const StdMeshMaterialPass::ShaderInstance &fragment_shader, const StdMeshMaterialPass::ShaderInstance &vertex_shader, const StdMeshMaterialPass::ShaderInstance &geometry_shader)
std::vector< std::pair< StdCopyStrBuf, StdMeshMaterialShaderParameter > > NamedParameters
std::vector< StdMeshMaterialTechnique > Techniques
#define X(sdl, oc)
const char * GetFilename() const
const StdMeshMaterial * GetMaterial(const char *material_name) const
ProgramInstance(const StdMeshMaterialProgram *program, const ShaderInstance *fragment_instance, const ShaderInstance *vertex_instance, const ShaderInstance *geometry_instance)
const StdMeshMaterialShader * GetVertexShader(const char *name) const
const char * GetCode() const
const StdMeshMaterialShader * AddShader(const char *filename, const char *name, const char *language, StdMeshMaterialShaderType type, const char *text, uint32_t load_flags)
virtual ~StdMeshMaterialLoader()
bool IsOpaque() const
void Remove(const StdStrBuf &name, class StdMeshMaterialUpdate *update)
const StdMeshMaterialShaderParameter * Parameter
const C4Shader * GetShader(int ssc) const
const StdMeshMaterialProgram *const Program