1 /*
2  *******************************************************************************************
3  * Dgame (a D game framework) - Copyright (c) Randy Schütt
4  * 
5  * This software is provided 'as-is', without any express or implied warranty.
6  * In no event will the authors be held liable for any damages arising from
7  * the use of this software.
8  * 
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  * 
13  * 1. The origin of this software must not be misrepresented; you must not claim
14  *    that you wrote the original software. If you use this software in a product,
15  *    an acknowledgment in the product documentation would be appreciated but is
16  *    not required.
17  * 
18  * 2. Altered source versions must be plainly marked as such, and must not be
19  *    misrepresented as being the original software.
20  * 
21  * 3. This notice may not be removed or altered from any source distribution.
22  *******************************************************************************************
23  */
24 module Dgame.System.VertexRenderer;
25 
26 private {
27 	import derelict.opengl3.gl;
28 	
29 	import Dgame.Internal.Log;
30 	import Dgame.Graphics.Shape;
31 }
32 
33 /**
34  * Declare which data is stored. Possible are Vertices, Colors or Texture coordinates.
35  */
36 enum Target {
37 	None   = 0,		/** Declare that the data consist of nothing relevant. */
38 	Vertex = 1, 	/** Declare that the data consist of vertices. */
39 	Color  = 2, 	/** Declare that the data consist of colors. */
40 	TexCoords = 4 	/** Declare that the data consist of texture coordinates. */
41 }
42 
43 /**
44  * Buffer is a wrapper for a static Vertex Array.
45  * <b>It has nothing to do with the class VertexArray</b>
46  *
47  * Author: rschuett
48  */
49 final abstract class VertexRenderer {
50 	/**
51 	 * Points to a specific Target.
52 	 * 
53 	 * See: glVertexPointer
54 	 * See: glColorPointer
55 	 * See: glTexCoordPointer
56 	 * See: Target enum.
57 	 * 
58 	 * Note: This method expects a <b>single</b> Target.
59 	 */
60 	static void pointTo(Target trg, void* ptr = null, ubyte stride = 0, ubyte offset = 0) {
61 		VertexRenderer.enableState(trg);
62 		
63 		if (ptr !is null)
64 			ptr += offset;
65 		else if (offset != 0)
66 			ptr = cast(void*)(offset);
67 		
68 		final switch (trg) {
69 			case Target.None:
70 				Log.error("Invalid Target");
71 				break;
72 			case Target.Vertex:
73 				glVertexPointer(3, GL_FLOAT, stride, ptr);
74 				break;
75 			case Target.Color:
76 				glColorPointer(4, GL_FLOAT, stride, ptr);
77 				break;
78 			case Target.TexCoords:
79 				glTexCoordPointer(2, GL_FLOAT, stride, ptr);
80 				break;
81 		}
82 	}
83 
84 	/**
85 	 * Points to a specific Target.
86 	 * 
87 	 * See: glVertexPointer
88 	 * See: glColorPointer
89 	 * See: glTexCoordPointer
90 	 * See: Target enum.
91 	 */
92 	static void pointTo(Target trg, const ubyte[Target] stride, const ubyte[Target] offset, void* ptr) {
93 		if (trg & Target.None)
94 			Log.error("Invalid Target");
95 
96 		@safe
97 		ubyte deref(const ubyte* ptr) pure nothrow {
98 			return ptr !is null ? *ptr : 0;
99 		}
100 
101 		if (trg & Target.Vertex)
102 			VertexRenderer.pointTo(Target.Vertex, ptr,
103 			                       deref(Target.Vertex in stride),
104 			                       deref(Target.Vertex in offset));
105 		if (trg & Target.Color)
106 			VertexRenderer.pointTo(Target.Color, ptr,
107 			                       deref(Target.Color in stride),
108 			                       deref(Target.Color in offset));
109 		if (trg & Target.TexCoords)
110 			VertexRenderer.pointTo(Target.TexCoords, ptr,
111 			                       deref(Target.TexCoords in stride),
112 			                       deref(Target.TexCoords in offset));
113 	}
114 	
115 	/**
116 	 * Enable a specific client state (with glEnableClientState)
117 	 * like GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
118 	 * with the corresponding Target.
119 	 */
120 	static void enableState(Target trg) {
121 		if (trg & Target.None)
122 			Log.error("Invalid Target");
123 
124 		if (trg & Target.Vertex)
125 			glEnableClientState(GL_VERTEX_ARRAY);
126 		if (trg & Target.Color)
127 			glEnableClientState(GL_COLOR_ARRAY);
128 		if (trg & Target.TexCoords)
129 			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
130 	}
131 	
132 	/**
133 	 * Enable all client states
134 	 */
135 	static void enableAllStates() {
136 		VertexRenderer.enableState(Target.Vertex | Target.Color | Target.TexCoords);
137 	}
138 	
139 	/**
140 	 * Disable all client states
141 	 */
142 	static void disableAllStates() {
143 		VertexRenderer.disableState(Target.Vertex | Target.Color | Target.TexCoords);
144 	}
145 	
146 	/**
147 	 * Disable a specific client state (with glDisableClientState)
148 	 */
149 	static void disableState(Target trg) {
150 		if (trg & Target.None)
151 			Log.error("Invalid Target");
152 
153 		if (trg & Target.Vertex)
154 			glDisableClientState(GL_VERTEX_ARRAY);
155 		if (trg & Target.Color)
156 			glDisableClientState(GL_COLOR_ARRAY);
157 		if (trg & Target.TexCoords)
158 			glDisableClientState(GL_TEXTURE_COORD_ARRAY);
159 	}
160 	
161 	/**
162 	 * Draw Shapes of a specific type from the data which is addressed through 'pointTo'.
163 	 * It will use count vertices.
164 	 *
165 	 * See: pointTo
166 	 */
167 	static void drawArrays(Shape.Type ptype, size_t count, size_t start = 0) {
168 		glDrawArrays(ptype, cast(uint) start, cast(uint) count);
169 	}
170 	
171 	/**
172 	 * Draw Shapes of a specific type from the data which is addressed through 'pointTo'.
173 	 * It will use count vertices and indices for the correct index per vertex.
174 	 * 
175 	 * See: pointTo
176 	 */
177 	static void drawElements(Shape.Type ptype, size_t count, uint[] indices) {
178 		if (indices.length == 0)
179 			return;
180 
181 		glDrawElements(ptype, cast(uint) count, GL_UNSIGNED_INT, &indices[0]); 
182 	}
183 	
184 	/**
185 	 * Draw Shapes of a specific type from the data which is addressed through 'pointTo'.
186 	 * It will use count vertices and indices for the correct index per vertex.
187 	 * 
188 	 * Note: If start or end are -1 or below, 0 and indices.length are used.
189 	 * 
190 	 * See: pointTo
191 	 */
192 	static void drawRangeElements(Shape.Type ptype, size_t count, uint[] indices, uint start = 0, uint end = 0) {
193 		if (indices.length == 0)
194 			return;
195 
196 		glDrawRangeElements(ptype, start, end != 0 ? end : cast(uint) indices.length, cast(uint) count, GL_UNSIGNED_INT, &indices[0]);
197 	}
198 }