Visualization Library 2.0.0-b3

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
ioAC3D.cpp
Go to the documentation of this file.
1 /**************************************************************************************/
2 /* */
3 /* Visualization Library */
4 /* http://visualizationlibrary.org */
5 /* */
6 /* Copyright (c) 2005-2017, Michele Bosi */
7 /* All rights reserved. */
8 /* */
9 /* Redistribution and use in source and binary forms, with or without modification, */
10 /* are permitted provided that the following conditions are met: */
11 /* */
12 /* - Redistributions of source code must retain the above copyright notice, this */
13 /* list of conditions and the following disclaimer. */
14 /* */
15 /* - Redistributions in binary form must reproduce the above copyright notice, this */
16 /* list of conditions and the following disclaimer in the documentation and/or */
17 /* other materials provided with the distribution. */
18 /* */
19 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
20 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
21 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
22 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
23 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
24 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
25 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
26 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
27 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
28 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29 /* */
30 /**************************************************************************************/
31 
32 #include "ioAC3D.hpp"
33 #include <vlCore/checks.hpp>
34 #include <vlGraphics/Effect.hpp>
35 #include <vlGraphics/Geometry.hpp>
36 #include <vlCore/Image.hpp>
37 #include <vlGraphics/Texture.hpp>
38 #include <vlCore/Log.hpp>
39 #include <vlCore/Say.hpp>
41 #include <vlCore/FileSystem.hpp>
42 #include <vlCore/TextStream.hpp>
43 #include <vlCore/VirtualFile.hpp>
45 #include <map>
47 
48 using namespace vl;
49 
50 namespace
51 {
52  class LoaderAC3D
53  {
54  public:
55 
56  class vert_info
57  {
58  public:
59  int Vert;
60  float U;
61  float V;
62  };
63 
64  class material_info
65  {
66  public:
67  String Name;
68  fvec3 Diffuse;
69  fvec3 Ambient;
70  fvec3 Emission;
71  fvec3 Specular;
72  float Shininess;
73  float Trans;
74  };
75 
76  class surface_info
77  {
78  public:
79  int Flags;
80  int materials;
81  int VertCount;
82  std::vector<vert_info> Vertex;
83  };
84 
85  class mesh_info
86  {
87  public:
88  mesh_info();
89 
90  String Name;
91  String Data;
93  float TexRep[2];
94  dmat4 Matrix;
95  String Url;
96  int NumVert;
97  std::vector<fvec3> Vert;
98  int NumSurf;
99  std::vector<surface_info> Surface;
100  int NumKids;
101  };
102 
103  LoaderAC3D();
104  bool parseAC3D(VirtualFile* file);
105 
106  fvec3 readColor();
107  fvec3 readVector();
108  float readFloat();
109  int readInt();
110  int readHex();
111  String readLine();
112  String readWord();
113  String readName();
114  void readMaterial();
115  void readObject();
116 
117  std::vector<material_info> materials;
118  std::vector<mesh_info> meshes;
119  bool verbose;
120 
121  protected:
122  ref<TextStream> mTokenizer;
123  String mTmpStr;
124  bool mEOF;
125  };
126 }
127 //-----------------------------------------------------------------------------
128 // mesh_info
129 //-----------------------------------------------------------------------------
130 LoaderAC3D::mesh_info::mesh_info()
131 {
132  TexRep[0] = 1;
133  TexRep[1] = 1;
134  NumVert = 0;
135  NumSurf = 0;
136  NumKids = 0;
137 }
138 //-----------------------------------------------------------------------------
139 // LoaderAC3D
140 //-----------------------------------------------------------------------------
141 LoaderAC3D::LoaderAC3D()
142 {
143  verbose = true;
144 }
145 //-----------------------------------------------------------------------------
146 bool LoaderAC3D::parseAC3D(VirtualFile* file)
147 {
148  mEOF = false;
149 
150  mTokenizer = new TextStream;
151  mTokenizer->setInputFile( file );
152  String token;
153 
154  mTokenizer->readString(token);
155 
156  if (token != "AC3Db")
157  {
158  Log::error("Not an AC3Db file!\n");
159  file->close();
160  return false;
161  }
162 
163  while( mTokenizer->readString(token) )
164  {
165  if (token == "MATERIAL")
166  readMaterial();
167  else
168  if (token == "OBJECT")
169  readObject();
170  else
171  {
172  Log::error("AC3D parse error.\n");
173  file->close();
174  return false;
175  }
176  }
177 
178  file->close();
179  return true;
180 }
181 //-----------------------------------------------------------------------------
182 fvec3 LoaderAC3D::readColor()
183 {
184  bool ok = true;
185  ok &= mTokenizer->readString(mTmpStr); float r = mTmpStr.toFloat();
186  ok &= mTokenizer->readString(mTmpStr); float g = mTmpStr.toFloat();
187  ok &= mTokenizer->readString(mTmpStr); float b = mTmpStr.toFloat();
188  mEOF = !ok;
189  if ( !ok )
190  Log::error("LoaderAC3D::readColor() IO error.\n");
191  return fvec3(r,g,b);
192 }
193 //-----------------------------------------------------------------------------
194 fvec3 LoaderAC3D::readVector()
195 {
196  bool ok = true;
197  ok &= mTokenizer->readString(mTmpStr); float x = mTmpStr.toFloat();
198  ok &= mTokenizer->readString(mTmpStr); float y = mTmpStr.toFloat();
199  ok &= mTokenizer->readString(mTmpStr); float z = mTmpStr.toFloat();
200  mEOF = !ok;
201  if ( !ok )
202  Log::error("LoaderAC3D::readVector() IO error.\n");
203  return fvec3(x,y,z);
204 }
205 //-----------------------------------------------------------------------------
206 float LoaderAC3D::readFloat()
207 {
208  bool ok = true;
209  ok &= mTokenizer->readString(mTmpStr); float f = mTmpStr.toFloat();
210  mEOF = !ok;
211  if ( !ok )
212  Log::error("LoaderAC3D::readFloat() IO error.\n");
213  return f;
214 }
215 //-----------------------------------------------------------------------------
216 int LoaderAC3D::readInt()
217 {
218  bool ok = true;
219  ok &= mTokenizer->readString(mTmpStr); int i = mTmpStr.toInt();
220  mEOF = !ok;
221  if ( !ok )
222  Log::error("LoaderAC3D::readInt() IO error.\n");
223  return i;
224 }
225 //-----------------------------------------------------------------------------
226 int LoaderAC3D::readHex()
227 {
228  bool ok = true;
229  ok &= mTokenizer->readString(mTmpStr);
230  mEOF = !ok;
231  if ( !ok )
232  {
233  Log::error("I/O error reading hex.\n");
234  return 0;
235  }
236  else
237  {
238  mTmpStr[0] = ' ';
239  mTmpStr[1] = ' ';
240  return mTmpStr.toInt(true);
241  }
242 }
243 //-----------------------------------------------------------------------------
244 String LoaderAC3D::readWord()
245 {
246  bool ok = true;
247  ok &= mTokenizer->readString( mTmpStr );
248  mEOF = !ok;
249  if ( !ok )
250  {
251  Log::error("I/O error reading word.\n");
252  return "";
253  }
254  else
255  {
256  if ( mTmpStr.count('"') == 1 )
257  {
258  Log::error( Say("The string '%s' contains a single '\"'.\n") << mTmpStr );
259  }
260 
261  mTmpStr.remove('"');
262  return mTmpStr;
263  }
264 }
265 //-----------------------------------------------------------------------------
266 String LoaderAC3D::readName()
267 {
268  bool ok = true;
269  ok &= mTokenizer->readQuotedString( mTmpStr );
270  mEOF = !ok;
271  if ( !ok )
272  {
273  Log::error("I/O error reading word.\n");
274  return "";
275  }
276  else
277  {
278  if ( mTmpStr.count('"') == 1 )
279  {
280  Log::error( Say("The string '%s' contains a single '\"'.\n") << mTmpStr );
281  }
282 
283  mTmpStr.remove('"');
284  return mTmpStr;
285  }
286 }
287 //-----------------------------------------------------------------------------
288 String LoaderAC3D::readLine()
289 {
290  bool ok = true;
291  ok &= mTokenizer->readLine( mTmpStr );
292  if ( !ok )
293  {
294  Log::error("I/O error reading line.\n");
295  return "";
296  }
297  else
298  {
299  return mTmpStr;
300  }
301 }
302 //-----------------------------------------------------------------------------
303 void LoaderAC3D::readMaterial()
304 {
305  // MATERIAL %s rgb %f %f %f amb %f %f %f emis %f %f %f spec %f %f %f shi %d trans %f
306  material_info material;
307 
308  material.Name = readName();
309  readWord(); // rgb
310  material.Diffuse = readColor();
311  readWord(); // amb
312  material.Ambient = readColor();
313  readWord(); // emis
314  material.Emission = readColor();
315  readWord(); // spec
316  material.Specular = readColor();
317  readWord(); // shi
318  material.Shininess = readFloat();
319  readWord(); // trans
320  material.Trans = 1 - readFloat();
321 
322  materials.push_back(material);
323 }
324 //-----------------------------------------------------------------------------
325 void LoaderAC3D::readObject()
326 {
327  mesh_info mesh;
328  String block;
329 
330  block = readWord();
331 
332  do
333  {
334  block = readWord();
335 
336  if (mEOF)
337  break;
338 
339  if (block == "name")
340  {
341  mesh.Name = readName();
342  } else
343  if (block == "data")
344  {
345  // needed to safely skip to the next line
346  int data_size=0;
347  mTokenizer->readLine(mTmpStr);
348  data_size = mTmpStr.toInt();
349 
350  // skip data_size bytes
351  unsigned char ch = 0;
352  for (int i=0; i<data_size; i++ )
353  mTokenizer->readToken(&ch);
354  }
355  else
356  if (block == "texture")
357  {
358  mesh.Texture = readName();
359  } else
360  if (block == "texrep")
361  {
362  mesh.TexRep[0] = readFloat();
363  mesh.TexRep[1] = readFloat();
364  } else
365  if (block == "rot")
366  {
367  mesh.Matrix.setX( (dvec3)readVector() );
368  mesh.Matrix.setY( (dvec3)readVector() );
369  mesh.Matrix.setZ( (dvec3)readVector() );
370  } else
371  if (block == "loc")
372  {
373  mesh.Matrix.setT( (dvec3)readVector() );
374  } else
375  if (block == "url")
376  {
377  mesh.Url = readName();
378  } else
379  if (block == "numvert")
380  {
381  mesh.NumVert = readInt();
382  for(int i=0; i<mesh.NumVert; ++i)
383  {
384  mesh.Vert.push_back( readVector() );
385  }
386  } else
387  if (block == "numsurf")
388  {
389  mesh.NumSurf = readInt();
390  for(int i=0; i<mesh.NumSurf; ++i)
391  {
392  surface_info surf;
393  String tmp;
394  do
395  {
396  tmp = readWord();
397 
398  if (tmp == "SURF")
399  {
400  surf.Flags = readHex();
401  }
402  if (tmp == "mat")
403  {
404  surf.materials = readInt();
405  }
406  if (tmp == "refs")
407  {
408  surf.VertCount = readInt();
409  for(int j=0; j<surf.VertCount; ++j)
410  {
411  vert_info vert;
412  vert.Vert = readInt();
413  vert.U = readFloat();
414  vert.V = readFloat();
415  surf.Vertex.push_back( vert );
416  }
417  }
418  }
419  while (tmp != "refs");
420  mesh.Surface.push_back(surf);
421  }
422  }
423  else
424  if (block == "kids")
425  {
426  mesh.NumKids = readInt();
427  meshes.push_back(mesh);
428  }
429  else
430  {
431  if (verbose)
432  Log::warning( Say("unknown block '%s'\n") << block );
433  // skip line
434  mTokenizer->readLine(mTmpStr);
435  }
436  }
437  while(block != "kids");
438 }
439 //-----------------------------------------------------------------------------
441 {
442  ref<VirtualFile> file = defFileSystem()->locateFile(path);
443  if ( !file )
444  {
445  Log::error( Say("Could not locate '%s'.\n") << path );
446  return NULL;
447  }
448  else
449  {
450  return loadAC3D(file.get() );
451  }
452 }
453 //-----------------------------------------------------------------------------
455 {
457 
458  LoaderAC3D loader;
459  if ( !loader.parseAC3D(file) )
460  return NULL;
461 
462  // compile the material map
463  std::vector< ref<Effect> > mat_map;
464  for(unsigned imat=0; imat<loader.materials.size(); imat++)
465  {
466  ref<Effect> effect = new Effect;
467  mat_map.push_back(effect.get());
468 
469  // apply material
470  effect->shader()->enable(EN_DEPTH_TEST);
471 
472  effect->shader()->gocMaterial()->setAmbient( fvec4(loader.materials[ imat ].Ambient, 1.0f) );
473  effect->shader()->gocMaterial()->setDiffuse( fvec4(loader.materials[ imat ].Diffuse, 1.0f) );
474  effect->shader()->gocMaterial()->setEmission( fvec4(loader.materials[ imat ].Emission, 1.0f) );
475  effect->shader()->gocMaterial()->setSpecular( fvec4(loader.materials[ imat ].Specular, 1.0f) );
476  effect->shader()->gocMaterial()->setShininess( loader.materials[ imat ].Shininess );
477  effect->shader()->gocMaterial()->setTransparency( loader.materials[ imat ].Trans );
478 
479  if ( loader.materials[ imat ].Trans < 1.0f )
480  {
481  effect->shader()->enable(EN_CULL_FACE);
482  effect->shader()->enable(EN_BLEND);
484  }
485  }
486 
487  // dumps the objects
488  for(unsigned imesh=0; imesh<loader.meshes.size(); imesh++)
489  {
490  if ( loader.meshes[imesh].Surface.empty() )
491  continue;
492 
493  ref<Actor> act = new Actor;
494  act->setObjectName( loader.meshes[imesh].Name.toStdString().c_str() );
495 
496  ref<Geometry> geom = new Geometry;
497  geom->setObjectName( loader.meshes[imesh].Name.toStdString().c_str() );
498 
499  ref<ArrayFloat3> verts = new ArrayFloat3;
500  ref<ArrayFloat2> uv = new ArrayFloat2;
502  geom->drawCalls().push_back( polys.get() );
503  geom->setVertexArray( verts.get() );
504  geom->setTexCoordArray(0, uv.get());
505  act->setLod(0, geom.get());
506 
507  // we handle only one material per surface
508  int mat_index = loader.meshes[imesh].Surface[0].materials;
509 
510  act->setEffect( mat_map[ mat_index ].get() );
511 
512  // polygons + vertices
513  int vert_count = 0;
514  for(unsigned isurf=0; isurf<loader.meshes[imesh].Surface.size(); isurf++)
515  {
516  if ( (loader.meshes[imesh].Surface[isurf].Flags & 0xF) != 0 )
517  continue;
518  for( int ivert=1; ivert<loader.meshes[imesh].Surface[isurf].VertCount-1; ivert++)
519  for(int i=0; i<3; ++i)
520  ++vert_count;
521  }
522 
523  verts->resize( vert_count );
524  uv->resize( vert_count );
525 
526  if (!vert_count)
527  continue;
528 
529  // add when we are sure we have some content
530 
531  res_db->resources().push_back( act.get() );
532  res_db->resources().push_back( geom.get() );
533 
534  // warning: this is a quite experimental importer.
535 
536  // !!! FIX !!! i vertici dovrebbero essere < degli indici in generale, vedi sotto
537  polys->indexBuffer()->resize( vert_count );
538 
539  int idx = 0;
540  for(unsigned isurf=0; isurf<loader.meshes[imesh].Surface.size(); isurf++)
541  {
542  if ( (loader.meshes[imesh].Surface[isurf].Flags & 0xF) != 0 ) // not a poly
543  continue;
544  VL_CHECK( loader.meshes[imesh].Surface[isurf].VertCount >= 3 )
545  for( int ivert=1; ivert<loader.meshes[imesh].Surface[isurf].VertCount-1; ivert++)
546  {
547  int vert_idx[] = { 0, ivert, ivert+1 };
548  for(int i=0; i<3; ++i, idx++)
549  {
550  // FIXME: a quanto pare i vertici non sono condivisi, ma lo dovrebbero essere
551  polys->indexBuffer()->at( idx ) = idx;
552  int iv = loader.meshes[imesh].Surface[isurf].Vertex[ vert_idx[i] ].Vert;
553  verts->at( idx ) = loader.meshes[imesh].Vert[ iv ];
554  uv->at( idx ) = fvec2(loader.meshes[imesh].Surface[isurf].Vertex[ vert_idx[i] ].U, loader.meshes[imesh].Surface[isurf].Vertex[ vert_idx[i] ].V);
555  }
556  }
557  }
558 
559  // FIXME
560  /*DoubleVertexRemover dvr;
561  dvr.removeDoubles(geom.get());*/
562  geom->transform( (mat4)loader.meshes[imesh].Matrix );
563  // geom->computeNormals();
564 
565  // !!! FIX !!! texture e double-side sono specificati per mesh e non per materiale, VL dovrebbe creare
566  // combinazioni uniche di materiali/texture/double-side
567 
568  // !!! FIX !!! texture - ci dovrebbe essere un unico materiale per ogni combinazione di double-side/texture
569  if ( loader.meshes[imesh].Texture.length() )
570  {
571  ref<Texture> texture = new Texture;
572  // locate texture
573  String tex_path = loader.meshes[imesh].Texture;
574  ref<VirtualFile> tex_file = defFileSystem()->locateFile(tex_path,file->path().extractPath());
575  if (tex_file)
576  tex_path = tex_file->path();
577  texture->prepareTexture2D(tex_path, TF_RGBA);
578  act->effect()->shader()->gocTextureSampler(0)->setTexture( texture.get() );
579  }
580 
581  // !!! FIX !!! double-side - ci dovrebbe essere un unico materiale per ogni combinazione di double-side/texture
582  if ( (loader.meshes[imesh].Surface[0].Flags & 0x20) )
583  {
584  act->effect()->shader()->gocLightModel()->setTwoSide(true);
585  /* effect->shader()->disable(EN_CULL_FACE); */
586  }
587 
588  }
589 
590  return res_db;
591 }
592 //-----------------------------------------------------------------------------
Associates a Renderable object to an Effect and Transform.
Definition: Actor.hpp:130
Simple class to manage flags in a type safe manner.
Definition: Flags.hpp:39
Material * gocMaterial()
Definition: Shader.cpp:119
void setEffect(Effect *effect)
Binds an Effect to an Actor.
Definition: Actor.hpp:196
VLCORE_EXPORT FileSystem * defFileSystem()
Returns the default FileSystem used by VisualizationLibrary.
Definition: init_core.cpp:153
void setTexture(Texture *texture)
The texture sampler by a texture unit.
Definition: Shader.hpp:1765
void prepareTexture2D(int width, int height, ETextureFormat format, bool border=false)
Prepares for creation an empty 2D texture.
Definition: Texture.hpp:329
Vector3< float > fvec3
A 3 components vector with float precision.
Definition: Vector3.hpp:252
const T * get() const
Definition: Object.hpp:128
An abstract class representing a file.
Definition: VirtualFile.hpp:60
If enabled, do depth comparisons and update the depth buffer; Note that even if the depth buffer exis...
Vector4< float > fvec4
A 4 components vector with float precision.
Definition: Vector4.hpp:279
A simple String formatting class.
Definition: Say.hpp:124
void setObjectName(const char *name)
The name of the object, by default set to the object&#39;s class name in debug builds.
Definition: Object.hpp:220
static void warning(const String &message)
Use this function to provide information about situations that might lead to errors or loss of data...
Definition: Log.cpp:154
TextureSampler * gocTextureSampler(int unit_index)
Definition: Shader.cpp:171
The String class implements an advanced UTF16 (Unicode BMP) string manipulation engine.
Definition: String.hpp:62
If enabled, blend the incoming RGBA color values with the values in the color buffers, see also BlendFunc for more information.
void setTransparency(float alpha)
Definition: Shader.cpp:377
void setShininess(float shininess)
Definition: Shader.hpp:797
static void error(const String &message)
Use this function to provide information about run-time errors: file not found, out of memory...
Definition: Log.cpp:164
void setVertexArray(ArrayAbstract *data)
Conventional vertex array.
Definition: Geometry.cpp:155
String extractPath() const
If the String contains a file path the function returns the path with trailing slash, without the file name.
Definition: String.cpp:830
void setSpecular(const fvec4 &color)
Definition: Shader.hpp:795
virtual ref< VirtualFile > locateFile(const String &full_path, const String &alternate_path=String()) const
Looks for a VirtualFile on the disk and in the currently active FileSystem.
Definition: FileSystem.cpp:61
Wraps an OpenGL texture object representing and managing all the supported texture types...
Definition: Texture.hpp:143
void resize(size_t dim)
Definition: Array.hpp:233
void setInputFile(VirtualFile *file)
virtual void close()=0
Closes the file.
const String & path() const
Returns the path of the file.
Definition: VirtualFile.hpp:98
The Geometry class is a Renderable that implements a polygonal mesh made of polygons, lines and points.
Definition: Geometry.hpp:66
Visualization Library main namespace.
Vector2< float > fvec2
A 2 components vector with float precision.
Definition: Vector2.hpp:282
The TextStream class can be used to conveniently read or parse utf8-encoded text files.
Definition: TextStream.hpp:46
void setDiffuse(const fvec4 &color)
Definition: Shader.hpp:794
void setEmission(const fvec4 &color)
Definition: Shader.hpp:796
const std::vector< ref< Object > > & resources() const
See DrawElements.
LightModel * gocLightModel()
Definition: Shader.cpp:121
void setTexCoordArray(int tex_unit, ArrayAbstract *data)
Conventional texture coords arrays.
Definition: Geometry.cpp:222
void transform(const mat4 &matr, bool normalize=true)
Transforms vertices and normals belonging to this geometry.
Definition: Geometry.cpp:399
void setAmbient(const fvec4 &color)
Definition: Shader.hpp:793
#define NULL
Definition: OpenGLDefs.hpp:81
arr_type * indexBuffer()
The BufferObject containing the indices used to render.
Shader * shader(int lodi=0, int pass=0)
Utility function, same as &#39;lod(lodi)->at(pass);&#39;.
Definition: Effect.hpp:178
Defines the sequence of Shader objects used to render an Actor.
Definition: Effect.hpp:91
T_VectorType & at(size_t i)
Definition: Array.hpp:255
Effect * effect()
Returns the Effect bound to an Actor.
Definition: Actor.hpp:199
void setLod(int lod_index, Renderable *renderable)
Sets the Renderable object representing the LOD level specifed by lod_index.
Definition: Actor.hpp:159
BlendFunc * gocBlendFunc()
Definition: Shader.cpp:149
The ref<> class is used to reference-count an Object.
Definition: Object.hpp:55
An array of vl::fvec3.
Definition: Array.hpp:414
An array of vl::fvec2.
Definition: Array.hpp:412
void setTwoSide(bool twoside)
Definition: Shader.hpp:875
#define VL_CHECK(expr)
Definition: checks.hpp:73
void enable(EEnable capability)
Definition: Shader.hpp:2169
VLGRAPHICS_EXPORT ref< ResourceDatabase > loadAC3D(VirtualFile *file)
Loads and AC3D file (.ac)
Definition: ioAC3D.cpp:454
void set(EBlendFactor src_rgb, EBlendFactor dst_rgb, EBlendFactor src_alpha, EBlendFactor dst_alpha)
Definition: Shader.hpp:617
The ResourceDatabase class contains and manipulates a set of resources.
Collection< DrawCall > & drawCalls()
Returns the list of DrawCall objects bound to a Geometry.
Definition: Geometry.hpp:102
If enabled, cull polygons based on their winding in window coordinates, see also CullFace.