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.model;
33 
34 import mango_engine.game;
35 import mango_engine.util;
36 import mango_engine.graphics.renderer;
37 import mango_engine.graphics.texture;
38 import mango_engine.graphics.shader;
39 
40 import mango_stl.misc;
41 
42 import gl3n.linalg;
43 
44 /// Struct that represents a Vertex with a vec3 (position)
45 class Vertex {
46     shared float x;
47     shared float y;
48     shared float z;
49 
50     /// Vector containing the Vertex's coordinates (3D).
51     vec3 positionToVec3() @safe nothrow {
52         return vec3(x, y, z);
53     }
54 
55     /// Creates a copy of the vertex.
56     Vertex duplicate() @safe nothrow {
57         return new Vertex(vec3(this.x, this.y, this.z));
58     }
59 
60     this(vec3 position) @safe nothrow {
61         this.x = position.x;
62         this.y = position.y;
63         this.z = position.z;
64     }
65 }
66 
67 /++
68     Struct that represents a Vertex with
69     a position vector(vec3), and a texture
70     vector (vec2).
71 +/
72 class TexturedVertex : Vertex {
73     shared float tX;
74     shared float tY;
75 
76     /// Vector containing the texture coordinates.
77     vec2 textureToVec2() @safe nothrow {
78         return vec2(tX, tY);
79     }
80 
81     override Vertex duplicate() @safe nothrow {
82         return new TexturedVertex(vec3(this.x, this.y, this.z), vec2(this.tX, this.tY));
83     }
84 
85     this(vec3 position, vec2 texture) @safe nothrow {
86         super(position);
87         this.tX = texture.x;
88         this.tY = texture.y;
89     }
90 }
91 
92 /// Represents a Model which can be rendered. A Model has a Shader and a Texture
93 class Model {
94     immutable string name;
95 
96     private shared GameManager _game;
97     private shared Lock lock;
98 
99     protected shared Vertex[] vertices;
100     protected shared uint[] _indices;
101 
102     protected shared Texture _texture;
103     protected shared ShaderProgram _shader;
104 
105     @property uint[] indices() @trusted nothrow { return cast(uint[]) _indices; }
106     
107     @property Texture texture() @trusted nothrow { return cast(Texture) _texture; }
108     @property shared void texture(shared Texture texture) @safe {
109         synchronized(lock) {
110             this._texture = texture;
111         }
112     }
113     
114     @property ShaderProgram shader() @trusted nothrow { return cast(ShaderProgram) _shader; }
115 
116     @property GameManager game() @trusted nothrow { return cast(GameManager) _game; }
117 
118     protected this(in string name, GameManager game, Vertex[] vertices, uint[] indices, Texture texture, ShaderProgram shader) @trusted nothrow {
119         this.name = name;
120         this._game = cast(shared) game;
121         this.lock = new Lock();
122 
123         this.vertices = cast(shared) vertices;
124         this._indices = cast(shared) indices;
125 
126         this._texture = cast(shared) texture;
127         this._shader = cast(shared) shader;
128     }
129 
130     static Model build(in string name, GameManager game, Vertex[] vertices, uint[] indices, Texture texture, ShaderProgram shader) @safe {
131         mixin(InterfaceClassFactory!("model", "Model", "name, game, vertices, indices, texture, shader"));
132     }
133 
134     final void render(Renderer renderer) @system {
135         //game.eventManager.fireEvent(new ModelRenderBeginEvent(cast(shared) this));
136         synchronized(this.lock) {
137             render_(renderer);
138         }
139     }
140 
141     final void replaceVertices(Vertex[] vertices) @trusted {
142         synchronized(this.lock) {
143             this.vertices = cast(shared) vertices;
144             replaceVertices_();
145         }
146     }
147 
148     final void replaceVertex(size_t arrayPosition, Vertex vertex) @trusted 
149     in {
150         assert(arrayPosition < this.vertices.length, "Invalid arrayPosition (greater than array size!)");
151     } body {
152         synchronized(this.lock) {
153             this.vertices[arrayPosition] = cast(shared) vertex;
154             replaceVertex_(arrayPosition, vertex);
155         }
156     }
157     
158     final Vertex getVertex(size_t arrayPosition) @trusted 
159     in {
160         assert(arrayPosition < this.vertices.length, "Invalid arrayPosition (greater than array size!)");
161     } body {
162         synchronized(this.lock) {
163             return (cast(Vertex) this.vertices[arrayPosition]).duplicate();
164         }
165     }
166 
167     Vertex[] getVertices() @trusted nothrow {
168         return cast(Vertex[]) this.vertices;
169     }
170 
171     /// Allows returning the lock used for preventing changes while renderering.
172     shared(Lock) getRenderingLock() @safe nothrow {
173         return this.lock;
174     }
175     
176     abstract void cleanup() @system;
177     
178     abstract protected void replaceVertices_() @system;
179     abstract protected void replaceVertex_(size_t pos, Vertex v) @system;
180     abstract protected void render_(Renderer renderer) @system;
181 }