1 | #include "semicircle.h" |
2 | #include "shaders.h" |
3 | |
4 | #include "../util/shader.h" |
5 | |
6 | #include "config.h" |
7 | |
8 | #ifdef USE_GLES |
9 | #include <GLES2/gl2.h> |
10 | #include <GLES2/gl2ext.h> |
11 | #else |
12 | #include <GL/glew.h> |
13 | #endif |
14 | |
15 | #include <math.h> |
16 | #include <stdlib.h> |
17 | |
18 | #define PI 3.1415926 |
19 | #define MIN_VERTICES 3 |
20 | #define MAX_VERTICES 100 |
21 | |
22 | #ifndef USE_GLES |
23 | static GLuint sliSemiCircleOutlineVAO = 0; |
24 | #endif |
25 | static GLuint sliSemiCircleOutlineVBOs[1] = {0}; |
26 | |
27 | #ifndef USE_GLES |
28 | static GLuint sliSemiCircleFillVAO = 0; |
29 | #endif |
30 | static GLuint sliSemiCircleFillVBOs[1] = {0}; |
31 | |
32 | static double sliOutlineRadius = 0; |
33 | static double sliFillRadius = 0; |
34 | |
35 | static int sliNumOutlineVertices = 0; |
36 | static int sliNumFillVertices = 0; |
37 | |
38 | void sliSemiCircleInit() |
39 | { |
40 | // initialize our outline state object |
41 | #ifndef USE_GLES |
42 | glGenVertexArrays(1, &sliSemiCircleOutlineVAO); |
43 | glBindVertexArray(sliSemiCircleOutlineVAO); |
44 | #endif |
45 | glGenBuffers(1, sliSemiCircleOutlineVBOs); |
46 | |
47 | // configure outline vertex data |
48 | glBindBuffer(GL_ARRAY_BUFFER, sliSemiCircleOutlineVBOs[0]); |
49 | glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * (MAX_VERTICES + 1) * 2, NULL, GL_DYNAMIC_DRAW); // + 1 for middle of line loop |
50 | glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL); |
51 | glEnableVertexAttribArray(0); |
52 | |
53 | // initialize our fill state object |
54 | #ifndef USE_GLES |
55 | glGenVertexArrays(1, &sliSemiCircleFillVAO); |
56 | glBindVertexArray(sliSemiCircleFillVAO); |
57 | #endif |
58 | glGenBuffers(1, sliSemiCircleFillVBOs); |
59 | |
60 | // configure fill vertex data |
61 | glBindBuffer(GL_ARRAY_BUFFER, sliSemiCircleFillVBOs[0]); |
62 | glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * (MAX_VERTICES + 1) * 2, NULL, GL_DYNAMIC_DRAW); // + 1 for middle of triangle fan |
63 | glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL); |
64 | glEnableVertexAttribArray(0); |
65 | } |
66 | |
67 | void sliSemiCircleDestroy() |
68 | { |
69 | glDeleteBuffers(1, sliSemiCircleOutlineVBOs); |
70 | #ifndef USE_GLES |
71 | glDeleteVertexArrays(1, &sliSemiCircleOutlineVAO); |
72 | #endif |
73 | |
74 | glDeleteBuffers(1, sliSemiCircleFillVBOs); |
75 | #ifndef USE_GLES |
76 | glDeleteVertexArrays(1, &sliSemiCircleFillVAO); |
77 | #endif |
78 | } |
79 | |
80 | void sliSemiCircleOutline(Mat4 *modelview, Vec4 *color, double radius, int numVertices, double degrees) |
81 | { |
82 | const double EPS = 0.00001; |
83 | |
84 | GLfloat vertices[(MAX_VERTICES + 1) * 2]; // + 1 for middle of line loop |
85 | GLfloat *vertexPtr; |
86 | double theta; |
87 | double transform; |
88 | double c, s; |
89 | double x, y; |
90 | int i; |
91 | |
92 | // make sure the number of vertices is something reasonable |
93 | if(numVertices < MIN_VERTICES) numVertices = MIN_VERTICES; |
94 | if(numVertices > MAX_VERTICES) numVertices = MAX_VERTICES; |
95 | |
96 | // if the number of vertices specified is different from what we've allocated, prepare to re-compute them |
97 | if(numVertices != sliNumOutlineVertices || fabs(radius - sliOutlineRadius) > EPS) |
98 | { |
99 | // clamp the degree range to something sane |
100 | if(degrees < -360.0) degrees = 360.0; |
101 | if(degrees > 360.0) degrees = 360.0; |
102 | |
103 | // assign new vertex count and radius |
104 | sliNumOutlineVertices = numVertices; |
105 | sliOutlineRadius = radius; |
106 | vertexPtr = vertices; |
107 | |
108 | // compute angle increment, and pre-compute sin and cos of that increment |
109 | theta = ((degrees / 180.0) * PI) / (double)(sliNumOutlineVertices - 1); |
110 | c = cos(theta); |
111 | s = sin(theta); |
112 | |
113 | // first vertex position of line loop |
114 | x = radius; |
115 | y = 0; |
116 | |
117 | // add center vertex for the middle point (the center of the loop) |
118 | *vertexPtr++ = 0.0f; |
119 | *vertexPtr++ = 0.0f; |
120 | |
121 | // compute new vertex positions |
122 | for(i = 0; i < sliNumOutlineVertices; i ++) |
123 | { |
124 | *vertexPtr++ = (float)x; |
125 | *vertexPtr++ = (float)y; |
126 | |
127 | // apply rotation matrix to current vertex position |
128 | transform = x; |
129 | x = c * x - s * y; |
130 | y = s * transform + c * y; |
131 | } |
132 | |
133 | // now pass the vertex data to OpenGL |
134 | #ifndef USE_GLES |
135 | glBindVertexArray(sliSemiCircleOutlineVAO); |
136 | #endif |
137 | glBindBuffer(GL_ARRAY_BUFFER, sliSemiCircleOutlineVBOs[0]); |
138 | glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * (sliNumOutlineVertices + 1) * 2, vertices); // + 1 for middle of line loop |
139 | } |
140 | |
141 | // prepare our shader object |
142 | shaderBind(sliBasicShader); |
143 | shaderUniformMatrix4fv(sliBasicShader, "u_Modelview" , 1, (float*)modelview); |
144 | shaderUniform4f(sliBasicShader, "u_Color" , (float)color -> x, (float)color -> y, (float)color -> z, (float)color -> w); |
145 | |
146 | // bind appropriate object state and render the object |
147 | #ifndef USE_GLES |
148 | glBindVertexArray(sliSemiCircleOutlineVAO); |
149 | #else |
150 | glBindBuffer(GL_ARRAY_BUFFER, sliSemiCircleOutlineVBOs[0]); |
151 | glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL); |
152 | #endif |
153 | glDrawArrays(GL_LINE_LOOP, 0, sliNumOutlineVertices + 1); // + 1 for middle of line loop |
154 | } |
155 | |
156 | void sliSemiCircleFill(Mat4 *modelview, Vec4 *color, double radius, int numVertices, double degrees) |
157 | { |
158 | const double EPS = 0.00001; |
159 | |
160 | GLfloat vertices[(MAX_VERTICES + 1) * 2]; // + 1 for middle of triangle fan |
161 | GLfloat *vertexPtr; |
162 | double theta; |
163 | double transform; |
164 | double c, s; |
165 | double x, y; |
166 | int i; |
167 | |
168 | // make sure the number of vertices is something reasonable |
169 | if(numVertices < MIN_VERTICES) numVertices = MIN_VERTICES; |
170 | if(numVertices > MAX_VERTICES) numVertices = MAX_VERTICES; |
171 | |
172 | // if the number of vertices specified is different from what we've allocated, prepare to re-compute them |
173 | if(numVertices != sliNumFillVertices || fabs(radius - sliFillRadius) > EPS) |
174 | { |
175 | // clamp the degree range to something sane |
176 | if(degrees < -360.0) degrees = 360.0; |
177 | if(degrees > 360.0) degrees = 360.0; |
178 | |
179 | // assign new vertex count |
180 | sliNumFillVertices = numVertices; |
181 | sliFillRadius = radius; |
182 | vertexPtr = vertices; |
183 | |
184 | // compute angle increment, and pre-compute sin and cos of that increment |
185 | theta = ((degrees / 180.0) * PI) / (double)(sliNumFillVertices - 1); |
186 | c = cos(theta); |
187 | s = sin(theta); |
188 | |
189 | // first vertex position of semi circle |
190 | x = radius; |
191 | y = 0; |
192 | |
193 | // insert triangle fan center vertex, which is the extra (+1) vertex |
194 | *vertexPtr++ = 0.0f; |
195 | *vertexPtr++ = 0.0f; |
196 | |
197 | // compute new vertex positions |
198 | for(i = 0; i < sliNumFillVertices; i ++) |
199 | { |
200 | *vertexPtr++ = (float)x; |
201 | *vertexPtr++ = (float)y; |
202 | |
203 | // apply rotation matrix to current vertex position |
204 | transform = x; |
205 | x = c * x - s * y; |
206 | y = s * transform + c * y; |
207 | } |
208 | |
209 | // now pass the vertex data to OpenGL |
210 | #ifndef USE_GLES |
211 | glBindVertexArray(sliSemiCircleFillVAO); |
212 | #endif |
213 | glBindBuffer(GL_ARRAY_BUFFER, sliSemiCircleFillVBOs[0]); |
214 | glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * (sliNumFillVertices + 1) * 3, vertices); // + 1 for middle of triangle fan |
215 | } |
216 | |
217 | // prepare our shader object |
218 | shaderBind(sliBasicShader); |
219 | shaderUniformMatrix4fv(sliBasicShader, "u_Modelview" , 1, (float*)modelview); |
220 | shaderUniform4f(sliBasicShader, "u_Color" , (float)color -> x, (float)color -> y, (float)color -> z, (float)color -> w); |
221 | |
222 | // bind appropriate object state and render the object |
223 | #ifndef USE_GLES |
224 | glBindVertexArray(sliSemiCircleFillVAO); |
225 | #else |
226 | glBindBuffer(GL_ARRAY_BUFFER, sliSemiCircleFillVBOs[0]); |
227 | glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL); |
228 | #endif |
229 | glDrawArrays(GL_TRIANGLE_FAN, 0, sliNumFillVertices + 1); // + 1 for middle of triangle fan |
230 | } |
231 | |