1 module dlangui.graphics.scene.mesh;
2 
3 public import dlangui.core.config;
4 static if (ENABLE_OPENGL):
5 static if (BACKEND_GUI):
6 
7 import dlangui.core.math3d;
8 import dlangui.core.types;
9 //import dlangui.graphics.scene.material;
10 import dlangui.graphics.scene.effect;
11 
12 /// Reference counted Mesh object
13 alias MeshRef = Ref!Mesh;
14 
15 /// Base class for graphics effect / program - e.g. for OpenGL shader program
16 abstract class GraphicsEffect : RefCountedObject {
17     /// get location for vertex attribute
18     int getVertexElementLocation(VertexElementType type);
19 
20     void setUniform(string uniformName, ref const(mat4) matrix);
21 
22     void setUniform(string uniformName, const(mat4)[] matrix);
23 
24     void setUniform(string uniformName, float v);
25 
26     void setUniform(string uniformName, const float[] v);
27 
28     void setUniform(string uniformName, vec2 vec);
29 
30     void setUniform(string uniformName, const vec2[] vec);
31 
32     void setUniform(string uniformName, vec3 vec);
33 
34     void setUniform(string uniformName, const vec3[] vec);
35 
36     void setUniform(string uniformName, vec4 vec);
37 
38     void setUniform(string uniformName, const vec4[] vec);
39 
40     void setUniform(DefaultUniform id, ref const(mat4) matrix);
41 
42     void setUniform(DefaultUniform id, const(mat4)[] matrix);
43 
44     void setUniform(DefaultUniform id, float v);
45 
46     void setUniform(DefaultUniform id, const float[] v);
47 
48     void setUniform(DefaultUniform id, vec2 vec);
49 
50     void setUniform(DefaultUniform id, const vec2[] vec);
51 
52     void setUniform(DefaultUniform id, vec3 vec);
53 
54     void setUniform(DefaultUniform id, const vec3[] vec);
55 
56     void setUniform(DefaultUniform id, vec4 vec);
57 
58     void setUniform(DefaultUniform id, const vec4[] vec);
59 
60     /// returns true if effect has uniform
61     bool hasUniform(DefaultUniform id);
62 
63     /// returns true if effect has uniform
64     bool hasUniform(string uniformName);
65 
66     void draw(Mesh mesh, bool wireframe);
67 }
68 
69 enum DefaultUniform : int {
70     // colors
71     u_ambientColor, // vec3
72     u_diffuseColor, // vec4
73 
74     // textures
75     u_diffuseTexture, //uniform sampler2D u_diffuseTexture;
76     u_lightmapTexture, //uniform sampler2D u_lightmapTexture;
77     u_normalmapTexture, //uniform sampler2D u_normalmapTexture;
78 
79     // lights
80     u_directionalLightColor, //uniform vec3 u_directionalLightColor[DIRECTIONAL_LIGHT_COUNT];
81     u_directionalLightDirection, //uniform vec3 u_directionalLightDirection[DIRECTIONAL_LIGHT_COUNT];
82     u_pointLightColor, //uniform vec3 u_pointLightColor[POINT_LIGHT_COUNT];
83     u_pointLightPosition, //uniform vec3 u_pointLightPosition[POINT_LIGHT_COUNT];
84     u_pointLightRangeInverse, //uniform float u_pointLightRangeInverse[POINT_LIGHT_COUNT];
85     u_spotLightColor, //uniform vec3 u_spotLightColor[SPOT_LIGHT_COUNT];
86     u_spotLightRangeInverse, //uniform float u_spotLightRangeInverse[SPOT_LIGHT_COUNT];
87     u_spotLightInnerAngleCos, //uniform float u_spotLightInnerAngleCos[SPOT_LIGHT_COUNT];
88     u_spotLightOuterAngleCos, //uniform float u_spotLightOuterAngleCos[SPOT_LIGHT_COUNT];
89     u_spotLightPosition, //uniform vec3 u_spotLightPosition[SPOT_LIGHT_COUNT];
90     u_spotLightDirection, //uniform vec3 u_spotLightDirection[SPOT_LIGHT_COUNT];
91 
92     u_specularExponent, //uniform float u_specularExponent;
93     u_modulateColor, //uniform vec4 u_modulateColor;
94     u_modulateAlpha, //uniform float u_modulateAlpha;
95 
96     // fog
97     u_fogColor, // uniform vec4 u_fogColor
98     u_fogMinDistance, // uniform float u_fogMinDistance
99     u_fogMaxDistance, // uniform float u_fogMaxDistance
100 
101     // matrix
102     u_worldViewProjectionMatrix, //uniform mat4 u_worldViewProjectionMatrix;
103     u_inverseTransposeWorldViewMatrix, //uniform mat4 u_inverseTransposeWorldViewMatrix;
104     u_worldMatrix, //uniform mat4 u_worldMatrix;
105     u_worldViewMatrix, //uniform mat4 u_worldViewMatrix;
106     u_cameraPosition, //uniform vec3 u_cameraPosition;
107 
108     u_matrixPalette, //uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];
109     u_clipPlane, //uniform vec4 u_clipPlane;
110 }
111 
112 enum DefaultAttribute : int {
113     a_position, //attribute vec4 a_position;
114 
115     a_blendWeights, //attribute vec4 a_blendWeights;
116     a_blendIndices, //attribute vec4 a_blendIndices;
117 
118     a_texCoord, //attribute vec2 a_texCoord;
119     a_texCoord1, //attribute vec2 a_texCoord1;
120     a_normal, //attribute vec3 a_normal;
121     a_color, //attribute vec3 a_color;
122     a_tangent, //attribute vec3 a_tangent;
123     a_binormal, //attribute vec3 a_binormal;
124 }
125 
126 /// vertex element type
127 enum VertexElementType : ubyte {
128     POSITION = 0,
129     NORMAL,
130     COLOR,
131     TANGENT,
132     BINORMAL,
133     BLENDWEIGHTS,
134     BLENDINDICES,
135     TEXCOORD0,
136     TEXCOORD1,
137     TEXCOORD2,
138     TEXCOORD3,
139     TEXCOORD4,
140     TEXCOORD5,
141     TEXCOORD6,
142     TEXCOORD7,
143 }
144 
145 static assert(VertexElementType.max == VertexElementType.TEXCOORD7);
146 
147 /// Graphics primitive type
148 enum PrimitiveType : int {
149     triangles,
150     triangleStripes,
151     lines,
152     lineStripes,
153     points,
154 }
155 
156 /// Vertex buffer object base class
157 class VertexBuffer {
158     /// bind into current context
159     //void bind() {}
160     /// unbind from current context
161     //void unbind() {}
162     /// set or change data
163     void setData(Mesh mesh) { }
164     /// draw mesh using specified effect
165     void draw(GraphicsEffect effect, bool wireframe) { }
166 }
167 
168 /// location for element is not found
169 enum VERTEX_ELEMENT_NOT_FOUND = -1;
170 
171 /// vertex attribute properties
172 struct VertexElement {
173     private VertexElementType _type;
174     private ubyte _size;
175     /// returns element type
176     @property VertexElementType type() const { return _type; }
177     /// return element size in floats
178     @property ubyte size() const { return _size; }
179     /// return element size in bytes
180     @property ubyte byteSize() const { return cast(ubyte)(_size * float.sizeof); }
181 
182     this(VertexElementType type, ubyte size = 0) {
183         if (size == 0) {
184             // autoassign default size
185             switch(type) with (VertexElementType) {
186                 case POSITION:
187                 case NORMAL:
188                 case TANGENT:
189                 case BINORMAL:
190                     size = 3;
191                     break;
192                 case BLENDWEIGHTS:
193                 case BLENDINDICES:
194                 case COLOR:
195                     size = 4;
196                     break;
197                 default: // tx coords
198                     size = 2;
199                     break;
200             }
201         }
202         _type = type;
203         _size = size;
204     }
205 }
206 
207 /// Vertex format elements list
208 struct VertexFormat {
209     private VertexElement[] _elements;
210     private byte[16] _elementOffset = [-1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1];
211     private int _vertexSize; // vertex size in floats
212     /// make using element list
213     this(inout VertexElement[] elems...) {
214         _elements = elems.dup;
215         foreach(elem; elems) {
216             _elementOffset[elem.type] = cast(byte)_vertexSize;
217             _vertexSize += elem.size;
218         }
219     }
220     /// init from vertex element types, using default sizes for types
221     this(inout VertexElementType[] types...) {
222         foreach(t; types) {
223             _elementOffset[t] = cast(byte)_vertexSize;
224             VertexElement elem = VertexElement(t);
225             _elements ~= elem;
226             _vertexSize += elem.size;
227         }
228     }
229     int elementOffset(VertexElementType type) const {
230         return _elementOffset[type];
231     }
232     bool hasElement(VertexElementType type) const {
233         return _elementOffset[type] >= 0;
234     }
235     /// set vec2 component value of vertex
236     void set(float * vertex, VertexElementType type, vec2 value) const {
237         int start = _elementOffset[type];
238         if (start >= 0) {
239             vertex += start;
240             vertex[0] = value.vec[0];
241             vertex[1] = value.vec[1];
242         }
243     }
244     /// set vec3 component value of vertex
245     void set(float * vertex, VertexElementType type, vec3 value) const {
246         int start = _elementOffset[type];
247         if (start >= 0) {
248             vertex += start;
249             vertex[0] = value.vec[0];
250             vertex[1] = value.vec[1];
251             vertex[2] = value.vec[2];
252         }
253     }
254     /// set vec4 component value of vertex
255     void set(float * vertex, VertexElementType type, vec4 value) const {
256         int start = _elementOffset[type];
257         if (start >= 0) {
258             vertex += start;
259             vertex[0] = value.vec[0];
260             vertex[1] = value.vec[1];
261             vertex[2] = value.vec[2];
262             vertex[3] = value.vec[3];
263         }
264     }
265     /// get number of elements
266     @property int length() const {
267         return cast(int)_elements.length;
268     }
269     /// get element by index
270     VertexElement opIndex(int index) const {
271         return _elements[index];
272     }
273     /// returns vertex size in bytes
274     @property int vertexSize() const {
275         return _vertexSize * cast(int)float.sizeof;
276     }
277     /// returns vertex size in floats
278     @property int vertexFloats() const {
279         return _vertexSize;
280     }
281     /// returns true if it's valid vertex format
282     @property bool isValid() const {
283         if (!_vertexSize)
284             return false;
285         foreach(elem; _elements) {
286             if (elem.type == VertexElementType.POSITION)
287                 return true;
288         }
289         return false;
290     }
291     /// compare
292     bool opEquals(immutable ref VertexFormat fmt) const {
293         if (_vertexSize != fmt._vertexSize)
294             return false;
295         for(int i = 0; i < _elements.length; i++)
296             if (_elements[i] != fmt._elements[i])
297                 return false;
298         return true;
299     }
300     string dump(float * data) {
301         import std.conv : to;
302         char[] buf;
303         int pos = 0;
304         foreach(VertexElement e; _elements) {
305             buf ~= data[pos .. pos + e.size].to!string;
306             pos += e.size;
307         }
308         return buf.dup;
309     }
310 }
311 
312 struct IndexFragment {
313     PrimitiveType type;
314     ushort start;
315     ushort end;
316     this(PrimitiveType type, int start, int end) {
317         this.type = type;
318         this.start = cast(ushort)start;
319         this.end = cast(ushort)end;
320     }
321 }
322 
323 /// Mesh
324 class Mesh : RefCountedObject {
325     protected VertexFormat _vertexFormat;
326     protected int _vertexCount;
327     protected float[] _vertexData;
328     protected MeshPart[] _parts;
329     protected VertexBuffer _vertexBuffer;
330     protected bool _dirtyVertexBuffer = true;
331 
332     @property ref VertexFormat vertexFormat() { return _vertexFormat; }
333     @property const(VertexFormat) * vertexFormatPtr() { return &_vertexFormat; }
334 
335     /// returns true if vertex format contains specified element
336     bool hasElement(VertexElementType type) const {
337         return _vertexFormat.hasElement(type);
338     }
339 
340     //@property ref VertexFormat vertexFormat() { return _vertexFormat; }
341 
342     @property void vertexFormat(VertexFormat format) {
343         assert(_vertexCount == 0);
344         _vertexFormat = format;
345         _dirtyVertexBuffer = true;
346     }
347 
348     const(float[]) vertex(int index) {
349         int i = _vertexFormat.vertexFloats * index;
350         return _vertexData[i .. i + _vertexFormat.vertexFloats];
351     }
352 
353     void reset() {
354         _vertexCount = 0;
355         _vertexData.length = 0;
356         _dirtyVertexBuffer = true;
357         if (_vertexBuffer) {
358             destroy(_vertexBuffer);
359             _vertexBuffer = null;
360         }
361         if (_parts.length) {
362             foreach(p; _parts)
363                 destroy(p);
364             _parts.length = 0;
365         }
366     }
367 
368     string dumpVertexes(int maxCount = 30) {
369         char[] buf;
370         int count = 0;
371         for(int i = 0; i < _vertexData.length; i+= _vertexFormat.vertexFloats) {
372             buf ~= "\n";
373             buf ~= _vertexFormat.dump(_vertexData.ptr + i);
374             if (++count >= maxCount)
375                 break;
376         }
377         return buf.dup;
378     }
379 
380     /// returns vertex count
381     @property int vertexCount() const { return _vertexCount; }
382 
383     /// returns vertex data array
384     @property const(float[]) vertexData() const { return _vertexData; }
385 
386     /// return index data for all parts
387     @property const(ushort[]) indexData() const {
388         if (!_parts)
389             return null;
390         if (_parts.length == 1)
391             return _parts[0].data;
392         int sz = 0;
393         foreach(p; _parts)
394             sz += p.length;
395         ushort[] res;
396         res.length = 0;
397         int pos = 0;
398         foreach(p; _parts) {
399             res[pos .. pos + p.length] = p.data[0 .. $];
400             pos += p.length;
401         }
402         return res;
403     }
404 
405     /// list of mesh fragments
406     @property IndexFragment[] indexFragments() const {
407         IndexFragment[] res;
408         int pos = 0;
409         foreach(p; _parts) {
410             res ~= IndexFragment(p.type, pos, pos + p.length);
411             pos += p.length;
412         }
413         return res;
414     }
415 
416     /// get vertex buffer object
417     @property VertexBuffer vertexBuffer() {
418         if (_dirtyVertexBuffer && _vertexBuffer) {
419             _vertexBuffer.setData(this);
420             _dirtyVertexBuffer = false;
421         }
422         return _vertexBuffer;
423     }
424 
425     /// set vertex buffer object
426     @property void vertexBuffer(VertexBuffer buffer) {
427         if (_vertexBuffer) {
428             _vertexBuffer.destroy;
429             _vertexBuffer = null;
430         }
431         _vertexBuffer = buffer;
432         if (_vertexBuffer) {
433             _vertexBuffer.setData(this);
434             _dirtyVertexBuffer = false;
435         }
436     }
437 
438     /// mesh part count
439     @property int partCount() const { return cast(int)_parts.length; }
440     /// returns mesh part by index
441     MeshPart part(int index) { return _parts[index]; }
442 
443     MeshPart addPart(MeshPart meshPart) {
444         _parts ~= meshPart;
445         _dirtyVertexBuffer = true;
446         return meshPart;
447     }
448 
449     /// add new mesh part or append indexes to existing part (if type matches)
450     MeshPart addPart(PrimitiveType type, ushort[] indexes) {
451         MeshPart lastPart = _parts.length > 0 ? _parts[$ - 1] : null;
452         if (!lastPart || lastPart.type != type)
453             return addPart(new MeshPart(type, indexes));
454         lastPart.add(indexes);
455         return lastPart;
456     }
457 
458     /// adds single vertex
459     int addVertex(float[] data) {
460         assert(_vertexFormat.isValid && data.length == _vertexFormat.vertexFloats);
461         int res = _vertexCount;
462         _vertexData.assumeSafeAppend();
463         _vertexData ~= data;
464         _vertexCount++;
465         _dirtyVertexBuffer = true;
466         return res;
467     }
468 
469     /// adds one or more vertexes
470     int addVertexes(float[] data) {
471         assert(_vertexFormat.isValid && (data.length > 0) && (data.length % _vertexFormat.vertexFloats == 0));
472         int res = _vertexCount;
473         _vertexData.assumeSafeAppend();
474         _vertexData ~= data;
475         _vertexCount += cast(int)(data.length / _vertexFormat.vertexFloats);
476         _dirtyVertexBuffer = true;
477         return res;
478     }
479 
480     this() {
481     }
482 
483     this(VertexFormat vertexFormat) {
484         _vertexFormat = vertexFormat;
485     }
486 
487     ~this() {
488         if (_vertexBuffer) {
489             _vertexBuffer.destroy;
490             _vertexBuffer = null;
491         }
492     }
493 
494 
495     void addQuad(ref vec3 v0, ref vec3 v1, ref vec3 v2, ref vec3 v3, ref vec4 color) {
496         ushort startVertex = cast(ushort)vertexCount;
497         if (hasElement(VertexElementType.NORMAL)) {
498             vec3 normal = vec3.crossProduct((v1 - v0), (v3 - v0)).normalized;
499             if (hasElement(VertexElementType.TANGENT)) {
500                 vec3 tangent = (v1 - v0).normalized;
501                 vec3 binormal = (v3 - v0).normalized;
502                 addVertex([v0.x, v0.y, v0.z, color.r, color.g, color.b, color.a, 0, 0, normal.x, normal.y, normal.z, tangent.x, tangent.y, tangent.z, binormal.x, binormal.y, binormal.z]);
503                 addVertex([v1.x, v1.y, v1.z, color.r, color.g, color.b, color.a, 1, 0, normal.x, normal.y, normal.z, tangent.x, tangent.y, tangent.z, binormal.x, binormal.y, binormal.z]);
504                 addVertex([v2.x, v2.y, v2.z, color.r, color.g, color.b, color.a, 1, 1, normal.x, normal.y, normal.z, tangent.x, tangent.y, tangent.z, binormal.x, binormal.y, binormal.z]);
505                 addVertex([v3.x, v3.y, v3.z, color.r, color.g, color.b, color.a, 0, 1, normal.x, normal.y, normal.z, tangent.x, tangent.y, tangent.z, binormal.x, binormal.y, binormal.z]);
506             } else {
507                 addVertex([v0.x, v0.y, v0.z, color.r, color.g, color.b, color.a, 0, 0, normal.x, normal.y, normal.z]);
508                 addVertex([v1.x, v1.y, v1.z, color.r, color.g, color.b, color.a, 1, 0, normal.x, normal.y, normal.z]);
509                 addVertex([v2.x, v2.y, v2.z, color.r, color.g, color.b, color.a, 1, 1, normal.x, normal.y, normal.z]);
510                 addVertex([v3.x, v3.y, v3.z, color.r, color.g, color.b, color.a, 0, 1, normal.x, normal.y, normal.z]);
511             }
512         } else {
513             addVertex([v0.x, v0.y, v0.z, color.r, color.g, color.b, color.a, 0, 0]);
514             addVertex([v1.x, v1.y, v1.z, color.r, color.g, color.b, color.a, 1, 0]);
515             addVertex([v2.x, v2.y, v2.z, color.r, color.g, color.b, color.a, 1, 1]);
516             addVertex([v3.x, v3.y, v3.z, color.r, color.g, color.b, color.a, 0, 1]);
517         }
518         addPart(PrimitiveType.triangles, [
519             cast(ushort)(startVertex + 0),
520             cast(ushort)(startVertex + 1),
521             cast(ushort)(startVertex + 2),
522             cast(ushort)(startVertex + 2),
523             cast(ushort)(startVertex + 3),
524             cast(ushort)(startVertex + 0)]);
525     }
526 
527     void addCubeMesh(vec3 pos, float d=1, vec4 color = vec4(1,1,1,1)) {
528         auto p000 = vec3(pos.x-d, pos.y-d, pos.z-d);
529         auto p100 = vec3(pos.x+d, pos.y-d, pos.z-d);
530         auto p010 = vec3(pos.x-d, pos.y+d, pos.z-d);
531         auto p110 = vec3(pos.x+d, pos.y+d, pos.z-d);
532         auto p001 = vec3(pos.x-d, pos.y-d, pos.z+d);
533         auto p101 = vec3(pos.x+d, pos.y-d, pos.z+d);
534         auto p011 = vec3(pos.x-d, pos.y+d, pos.z+d);
535         auto p111 = vec3(pos.x+d, pos.y+d, pos.z+d);
536         addQuad(p000, p010, p110, p100, color); // front face
537         addQuad(p101, p111, p011, p001, color); // back face
538         addQuad(p100, p110, p111, p101, color); // right face
539         addQuad(p001, p011, p010, p000, color); // left face
540         addQuad(p010, p011, p111, p110, color); // top face
541         addQuad(p001, p000, p100, p101, color); // bottom face
542     }
543 
544     static Mesh createCubeMesh(vec3 pos, float d=1, vec4 color = vec4(1,1,1,1)) {
545         Mesh mesh = new Mesh(VertexFormat(VertexElementType.POSITION, VertexElementType.COLOR, VertexElementType.TEXCOORD0
546                                           , VertexElementType.NORMAL, VertexElementType.TANGENT, VertexElementType.BINORMAL
547                                           ));
548         mesh.addCubeMesh(pos, d, color);
549         return mesh;
550     }
551 }
552 
553 /// Mesh part - set of vertex indexes with graphics primitive type
554 class MeshPart {
555     protected PrimitiveType _type;
556     protected ushort[] _indexData;
557     this(PrimitiveType type, ushort[] indexes = null) {
558         _type = type;
559         _indexData.assumeSafeAppend;
560         add(indexes);
561     }
562 
563     void add(ushort[] indexes) {
564         if (indexes.length)
565             _indexData ~= indexes;
566     }
567 
568     /// returns primitive type
569     @property PrimitiveType type() const { return _type; }
570 
571     /// change primitive type
572     @property void type(PrimitiveType t) { _type = t; }
573 
574     /// index length
575     @property int length() const { return cast(int)_indexData.length; }
576 
577     /// index data
578     @property const(ushort[]) data() const { return _indexData; }
579 }