1 /**
2  * Retrograde Engine
3  *
4  * Authors:
5  *  Mike Bierlee, m.bierlee@lostmoment.com
6  * Copyright: 2014-2021 Mike Bierlee
7  * License:
8  *  This software is licensed under the terms of the MIT license.
9  *  The full terms of the license can be found in the LICENSE.txt file.
10  */
11 
12 module retrograde.graphics.threedee.opengl.model;
13 
14 version(Have_derelict_gl3) {
15 
16 import retrograde.model;
17 import retrograde.graphics.threedee.opengl.rendering;
18 import retrograde.geometry;
19 
20 import derelict.opengl3.gl3;
21 
22 class OpenGlMesh {
23     public immutable Mesh mesh;
24     public GLuint vertexArrayObject;
25     public GLuint vertexBufferObject;
26 
27     this(immutable Mesh mesh) {
28         this.mesh = mesh;
29     }
30 }
31 
32 class OpenGlModel : Model {
33 
34     private OpenGlMesh[] meshes;
35     private bool loaded;
36 
37     this(immutable Mesh[] meshes) {
38         foreach (mesh ; meshes) {
39             this.meshes ~= new OpenGlMesh(mesh);
40         }
41     }
42 
43     public override void loadIntoVram() {
44         if (isLoadedIntoVram()) {
45             throw new ModelLoadException("Cannot load OpenGL model into VRAM: Model has been previously loaded already. Unload model with unloadFromVram first.");
46         }
47 
48         foreach (openGlMesh ; meshes) {
49             // TODO: Optimize: load as actual vertex-face data if possible
50             uint totalVertices = openGlMesh.mesh.faces.length * 3;
51             Vertex[] vertexData = [];
52             foreach(face; openGlMesh.mesh.faces) {
53                 vertexData ~= openGlMesh.mesh.vertices[face.vertexIndex1];
54                 vertexData ~= openGlMesh.mesh.vertices[face.vertexIndex2];
55                 vertexData ~= openGlMesh.mesh.vertices[face.vertexIndex3];
56             }
57 
58             GLuint vertexArrayObject;
59             GLuint vertexBufferObject;
60 
61             glCreateVertexArrays(1, &vertexArrayObject);
62             glCreateBuffers(1, &vertexBufferObject);
63 
64             uint verticesByteSize = Vertex.sizeof * vertexData.length;
65             glNamedBufferStorage(vertexBufferObject, verticesByteSize, vertexData.ptr, 0);
66 
67             glVertexArrayAttribBinding(vertexArrayObject, 0, 0);
68             glVertexArrayAttribFormat(vertexArrayObject, 0, 4, GL_FLOAT, GL_FALSE, Vertex.x.offsetof);
69             glEnableVertexArrayAttrib(vertexArrayObject, 0);
70 
71             glVertexArrayAttribBinding(vertexArrayObject, 1, 0);
72             glVertexArrayAttribFormat(vertexArrayObject, 1, 4, GL_FLOAT, GL_FALSE, Vertex.r.offsetof);
73             glEnableVertexArrayAttrib(vertexArrayObject, 1);
74 
75             glVertexArrayAttribBinding(vertexArrayObject, 2, 0);
76             glVertexArrayAttribFormat(vertexArrayObject, 2, 2, GL_FLOAT, GL_FALSE, Vertex.u.offsetof);
77             glEnableVertexArrayAttrib(vertexArrayObject, 2);
78 
79             glVertexArrayVertexBuffer(vertexArrayObject, 0, vertexBufferObject, 0, Vertex.sizeof);
80 
81             openGlMesh.vertexArrayObject = vertexArrayObject;
82             openGlMesh.vertexBufferObject = vertexBufferObject;
83         }
84 
85         loaded = true;
86     }
87 
88     public override void unloadFromVram() {
89         foreach (openGlMesh ; meshes) {
90             glDeleteVertexArrays(1, &openGlMesh.vertexArrayObject);
91             glDeleteBuffers(1, &openGlMesh.vertexBufferObject);
92             openGlMesh.vertexArrayObject = 0;
93             openGlMesh.vertexBufferObject = 0;
94         }
95 
96         loaded = false;
97     }
98 
99     public override bool isLoadedIntoVram() {
100         return loaded;
101     }
102 
103     public override void draw() {
104         foreach (openGlMesh ; meshes) {
105             glBindVertexArray(openGlMesh.vertexArrayObject);
106             glDrawArrays(GL_TRIANGLES, 0, openGlMesh.mesh.faces.length * 3);
107             glBindVertexArray(0);
108         }
109     }
110 
111 }
112 
113 }