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 }