diff --git a/examples/d3d/views/res/shaders/colored.frag b/examples/d3d/views/res/shaders/colored.frag new file mode 100644 index 00000000..05fd8f04 --- /dev/null +++ b/examples/d3d/views/res/shaders/colored.frag @@ -0,0 +1,7 @@ +uniform sampler2D tex; +in vec4 col; +out vec4 outColor; +void main(void) +{ + outColor = col; +} diff --git a/examples/d3d/views/res/shaders/colored.vert b/examples/d3d/views/res/shaders/colored.vert new file mode 100644 index 00000000..4ee0d2ab --- /dev/null +++ b/examples/d3d/views/res/shaders/colored.vert @@ -0,0 +1,9 @@ +in vec4 vertex; +in vec4 colAttr; +out vec4 col; +uniform mat4 matrix; +void main(void) +{ + gl_Position = matrix * vertex; + col = colAttr; +} diff --git a/examples/d3d/views/resources.list b/examples/d3d/views/resources.list index 61d7ce47..ea3fbba9 100644 --- a/examples/d3d/views/resources.list +++ b/examples/d3d/views/resources.list @@ -4,6 +4,8 @@ res/mdpi/cr3_logo.png res/mdpi/tx_fabric.jpg res/mdpi/crate.png res/mdpi/blocks.png +res/models/suzanne.obj +res/shaders/colored.vert +res/shaders/colored.frag res/shaders/textured.vert res/shaders/textured.frag -res/models/suzanne.obj diff --git a/src/dlangui/core/math3d.d b/src/dlangui/core/math3d.d index 1af3cc16..027fbb4f 100644 --- a/src/dlangui/core/math3d.d +++ b/src/dlangui/core/math3d.d @@ -22,6 +22,12 @@ struct vec2 { this(float[2] v) { vec = v; } + this(float[] v) { + vec = v[0..2]; + } + this(float * v) { + vec = v[0..2]; + } this(const vec2 v) { vec = v.vec; } @@ -258,6 +264,12 @@ struct vec3 { this(float[3] v) { vec = v; } + this(float[] v) { + vec = v[0..3]; + } + this(float * v) { + vec = v[0..3]; + } this(const vec3 v) { vec = v.vec; } @@ -1581,3 +1593,13 @@ unittest { m.rotateY(10); m.rotateZ(10); } + +/// calculate normal for triangle +vec3 triangleNormal(vec3 p1, vec3 p2, vec3 p3) { + return vec3.crossProduct(p2 - p1, p3 - p2).normalized(); +} + +/// calculate normal for triangle +vec3 triangleNormal(float[3] p1, float[3] p2, float[3] p3) { + return vec3.crossProduct(vec3(p2) - vec3(p1), vec3(p3) - vec3(p2)).normalized(); +} diff --git a/src/dlangui/graphics/scene/mesh.d b/src/dlangui/graphics/scene/mesh.d index 7f2adf41..79b1d820 100644 --- a/src/dlangui/graphics/scene/mesh.d +++ b/src/dlangui/graphics/scene/mesh.d @@ -27,7 +27,7 @@ abstract class GraphicsEffect : RefCountedObject { /// vertex element type enum VertexElementType : ubyte { - POSITION = 1, + POSITION = 0, NORMAL, COLOR, TEXCOORD0, @@ -40,6 +40,8 @@ enum VertexElementType : ubyte { TEXCOORD7, } +static assert(VertexElementType.max == VertexElementType.TEXCOORD7); + /// Graphics primitive type enum PrimitiveType : int { triangles, @@ -98,21 +100,61 @@ struct VertexElement { /// Vertex format elements list struct VertexFormat { private VertexElement[] _elements; + private byte[VertexElementType.max + 1] _elementOffset = [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]; private int _vertexSize; /// make using element list this(inout VertexElement[] elems...) { _elements = elems.dup; - foreach(elem; elems) + foreach(elem; elems) { + _elementOffset[elem.type] = cast(byte)(_vertexSize / float.sizeof); _vertexSize += elem.size * float.sizeof; + } } /// init from vertex element types, using default sizes for types this(inout VertexElementType[] types...) { foreach(t; types) { + _elementOffset[t] = cast(byte)(_vertexSize / float.sizeof); VertexElement elem = VertexElement(t); _elements ~= elem; _vertexSize += elem.size; } } + int elementOffset(VertexElementType type) const { + return _elementOffset[type]; + } + bool hasElement(VertexElementType type) const { + return _elementOffset[type] >= 0; + } + /// set vec2 component value of vertex + void set(float * vertex, VertexElementType type, vec2 value) const { + int start = _elementOffset[type]; + if (start >= 0) { + vertex += start; + vertex[0] = value.vec[0]; + vertex[1] = value.vec[1]; + } + } + /// set vec3 component value of vertex + void set(float * vertex, VertexElementType type, vec3 value) const { + int start = _elementOffset[type]; + if (start >= 0) { + vertex += start; + vertex[0] = value.vec[0]; + vertex[1] = value.vec[1]; + vertex[2] = value.vec[2]; + } + } + /// set vec4 component value of vertex + void set(float * vertex, VertexElementType type, vec4 value) const { + int start = _elementOffset[type]; + if (start >= 0) { + vertex += start; + vertex[0] = value.vec[0]; + vertex[1] = value.vec[1]; + vertex[2] = value.vec[2]; + vertex[3] = value.vec[3]; + } + } /// get number of elements @property int length() const { return cast(int)_elements.length; @@ -170,9 +212,10 @@ class Mesh : RefCountedObject { protected VertexBuffer _vertexBuffer; protected bool _dirtyVertexBuffer = true; - @property ref const(VertexFormat) vertexFormat() const { return _vertexFormat; } + @property ref VertexFormat vertexFormat() { return _vertexFormat; } + @property const(VertexFormat) * vertexFormatPtr() { return &_vertexFormat; } - @property VertexFormat vertexFormat() { return _vertexFormat; } + //@property ref VertexFormat vertexFormat() { return _vertexFormat; } @property void vertexFormat(VertexFormat format) { assert(_vertexCount == 0); diff --git a/src/dlangui/graphics/scene/objimport.d b/src/dlangui/graphics/scene/objimport.d index b2ccf256..94df8eca 100644 --- a/src/dlangui/graphics/scene/objimport.d +++ b/src/dlangui/graphics/scene/objimport.d @@ -1,7 +1,9 @@ module dlangui.graphics.scene.objimport; import dlangui.core.logger; +import dlangui.core.math3d; import dlangui.dml.tokenizer; +import dlangui.graphics.scene.mesh; struct ObjModelImport { alias FaceIndex = int[3]; @@ -14,6 +16,9 @@ struct ObjModelImport { private int _triangleCount; private int _txCount; private float[8] _buf; + + MeshRef mesh; + protected float[] parseFloatList(Token[] tokens, int maxItems = 3, float padding = 0) { int i = 0; foreach(t; tokens) { @@ -126,7 +131,85 @@ struct ObjModelImport { return true; } + vec3 vertexForIndex(int index) { + if (index < 0) + index = _vertexCount + 1 + index; + if (index >= 1 && index <= _vertexCount) { + index = (index - 1) * 3; + return vec3(&_vertexData[index]); + } + return vec3.init; + } + + vec3 normalForIndex(int index) { + if (index < 0) + index = _normalCount + 1 + index; + if (index >= 1 && index <= _normalCount) { + index = (index - 1) * 3; + return vec3(&_normalData[index]); + } + return vec3(0, 0, 1); + } + + vec2 txForIndex(int index) { + if (index < 0) + index = _txCount + 1 + index; + if (index >= 1 && index <= _txCount) { + index = (index - 1) * 2; + return vec2(&_txData[index]); + } + return vec2.init; + } + + bool _meshHasTexture; + void createMeshIfNotExist() { + if (!mesh.isNull) + return; + if (_txCount) { + mesh = new Mesh(VertexFormat(VertexElementType.POSITION, VertexElementType.NORMAL, VertexElementType.COLOR, VertexElementType.TEXCOORD0)); + _meshHasTexture = true; + } else { + mesh = new Mesh(VertexFormat(VertexElementType.POSITION, VertexElementType.NORMAL, VertexElementType.COLOR)); + _meshHasTexture = false; + } + } protected bool addTriangle(FaceIndex v1, FaceIndex v2, FaceIndex v3) { + createMeshIfNotExist(); + float[16 * 3] data; + const (VertexFormat) * fmt = mesh.vertexFormatPtr; + int vfloats = fmt.vertexFloats; + vec3 p1 = vertexForIndex(v1[0]); + vec3 p2 = vertexForIndex(v2[0]); + vec3 p3 = vertexForIndex(v3[0]); + fmt.set(data.ptr, VertexElementType.POSITION, p1); + fmt.set(data.ptr + vfloats, VertexElementType.POSITION, p2); + fmt.set(data.ptr + vfloats * 2, VertexElementType.POSITION, p3); + if (fmt.hasElement(VertexElementType.TEXCOORD0)) { + fmt.set(data.ptr, VertexElementType.TEXCOORD0, txForIndex(v1[1])); + fmt.set(data.ptr + vfloats, VertexElementType.TEXCOORD0, txForIndex(v2[1])); + fmt.set(data.ptr + vfloats * 2, VertexElementType.TEXCOORD0, txForIndex(v3[1])); + } + if (fmt.hasElement(VertexElementType.COLOR)) { + const vec4 white = vec4(1, 1, 1, 1); + fmt.set(data.ptr, VertexElementType.COLOR, white); + fmt.set(data.ptr + vfloats, VertexElementType.COLOR, white); + fmt.set(data.ptr + vfloats * 2, VertexElementType.COLOR, white); + } + if (fmt.hasElement(VertexElementType.NORMAL)) { + vec3 normal; + if (!v1[2] || !v2[2] || !v3[2]) { + // no normal specified, calculate it + normal = triangleNormal(p1, p2, p3); + } + fmt.set(data.ptr, VertexElementType.NORMAL, v1[2] ? normalForIndex(v1[2]) : normal); + fmt.set(data.ptr + vfloats, VertexElementType.NORMAL, v2[2] ? normalForIndex(v2[2]) : normal); + fmt.set(data.ptr + vfloats * 2, VertexElementType.NORMAL, v3[2] ? normalForIndex(v3[2]) : normal); + } + int startVertex = mesh.addVertexes(data.ptr[0 .. vfloats * 3]); + mesh.addPart(PrimitiveType.triangles, [ + cast(ushort)(startVertex + 0), + cast(ushort)(startVertex + 1), + cast(ushort)(startVertex + 2)]); _triangleCount++; return true; }