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
25static GLuint sliSemiCircleOutlineVBOs[1] = {0};
26
27#ifndef USE_GLES
28 static GLuint sliSemiCircleFillVAO = 0;
29#endif
30static GLuint sliSemiCircleFillVBOs[1] = {0};
31
32static double sliOutlineRadius = 0;
33static double sliFillRadius = 0;
34
35static int sliNumOutlineVertices = 0;
36static int sliNumFillVertices = 0;
37
38void 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
67void 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
80void 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
156void 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