1 /*
2  *  BSD 3-Clause License
3  *  
4  *  Copyright (c) 2016, Mango-Engine Team
5  *  All rights reserved.
6  *  
7  *  Redistribution and use in source and binary forms, with or without
8  *  modification, are permitted provided that the following conditions are met:
9  *  
10  *  * Redistributions of source code must retain the above copyright notice, this
11  *    list of conditions and the following disclaimer.
12  *  
13  *  * Redistributions in binary form must reproduce the above copyright notice,
14  *    this list of conditions and the following disclaimer in the documentation
15  *    and/or other materials provided with the distribution.
16  *  
17  *  * Neither the name of the copyright holder nor the names of its
18  *    contributors may be used to endorse or promote products derived from
19  *    this software without specific prior written permission.
20  *  
21  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 module mango_engine.graphics.opengl.gl_model;
33 
34 import mango_engine.game;
35 import mango_engine.graphics.renderer;
36 import mango_engine.graphics.model;
37 import mango_engine.graphics.texture;
38 import mango_engine.graphics.shader;
39 import mango_engine.graphics.opengl.gl_backend;
40 import mango_engine.graphics.opengl.gl_types;
41 import mango_engine.graphics.opengl.gl_texture;
42 import mango_engine.graphics.opengl.gl_shader;
43 
44 import derelict.opengl3.gl3;
45 
46 import gl3n.linalg;
47 
48 class GLModel : Model {
49     /// Enum containing array positions for Mesh VBOs.
50     static enum VBOIndexes {
51         VBO_VERTICES,
52         VBO_INDICES,
53         VBO_TEXTURES
54     }
55 
56     protected shared size_t _drawCount;
57 
58     protected shared VBO[uint] vboList;
59     private shared VAO _vao;
60 
61     /// The VAO belonging to the Mesh.
62     @property VAO vao() @trusted nothrow { return cast(VAO) _vao; }
63 
64     /++
65         The amount of points (vertices) that will be
66         rendered. This is equal to the amount of
67         indices.
68     +/
69     @property size_t drawCount() @trusted nothrow { return cast(size_t) _drawCount; }
70 
71     /++
72         The amount of points (vertices) that will be
73         rendered. This is equal to the amount of
74         indices.
75     +/
76     @property protected void drawCount(shared size_t drawCount) @safe nothrow { _drawCount = drawCount; }
77 
78     this(GameManager game, Vertex[] vertices, uint[] indices, Texture texture, ShaderProgram shader) @trusted {
79         super(game, vertices, indices, texture, shader);
80         
81         gl_check();
82         
83         this._drawCount = indices.length;
84 
85         setup();
86     }
87 
88     private void setup() @system {
89         _vao = cast(shared) VAO.generateNew();
90         vao.bind();
91 
92         auto indicesVBO = new VBO(GL_ELEMENT_ARRAY_BUFFER);
93         indicesVBO.bind();
94         indicesVBO.setData(indices);
95         //indicesVBO.setDataRaw(indices.ptr, cast(GLsizei) (indices.length * uint.sizeof));
96 
97         //------------------- Vertices
98         auto verticesVBO = new VBO(GL_ARRAY_BUFFER);
99         verticesVBO.bind();
100         verticesVBO.setDataRaw(
101             cast(void*) positionVerticesToFloats(cast(Vertex[]) vertices),
102             cast(GLsizei) (vertices.length * vec3.sizeof) // Single vertex is a vec3
103         );
104 
105         glEnableVertexAttribArray(0);
106         glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, cast(void*) 0);
107         //------------------- End Vertices
108 
109         vboList[VBOIndexes.VBO_VERTICES] = cast(shared) verticesVBO;
110         vboList[VBOIndexes.VBO_INDICES] = cast(shared) indicesVBO;
111 
112         // Check if using Textured vertices.
113         if(cast(TexturedVertex[]) vertices) {
114             auto textureVBO = new VBO(GL_ARRAY_BUFFER);
115             textureVBO.bind();
116             textureVBO.setDataRaw(
117                 cast(void*) textureVerticesToFloats(cast(Vertex[]) vertices),
118                 cast(GLsizei) (vertices.length * vec2.sizeof)
119             );
120 
121             glEnableVertexAttribArray(1);
122             glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, cast(void*) 0);
123 
124             vboList[VBOIndexes.VBO_TEXTURES] = cast(shared) textureVBO;
125         }
126 
127         vao.unbind();
128     }
129 
130     /// Cleanup resources used by the Model.
131     override void cleanup() @trusted {
132         vao.bind();
133         foreach(vbo; vboList.values) {
134             (cast(VBO) vbo).cleanup();
135         }
136         vao.unbind();
137         vao.cleanup();
138     }
139     
140     override protected void render_(Renderer renderer) @system {
141         (cast(GLTexture) texture).bind();
142         (cast(GLShaderProgram) shader).use();
143 
144         vao.bind();
145         
146         glDrawElements(GL_TRIANGLES, cast(GLsizei) drawCount,
147             GL_UNSIGNED_INT,
148             cast(void*) 0
149         );
150 
151         vao.unbind();
152     }
153 }