SDL_gpu  0.11.0
A hardware-accelerated, cross-platform 2D graphics API
renderer_shapes_GL_common.inl
Go to the documentation of this file.
1 /* This is an implementation file to be included after certain #defines have been set.
2 See a particular renderer's *.c file for specifics. */
3 
4 #ifndef DEGPERRAD
5 #define DEGPERRAD 57.2957795f
6 #endif
7 
8 #ifndef RADPERDEG
9 #define RADPERDEG 0.0174532925f
10 #endif
11 
12 
13 
14 
15 
16 
17 
18 // All shapes start this way for setup and so they can access the blit buffer properly
19 #define BEGIN_UNTEXTURED(function_name, shape, num_additional_vertices, num_additional_indices) \
20  GPU_CONTEXT_DATA* cdata; \
21  float* blit_buffer; \
22  unsigned short* index_buffer; \
23  int vert_index; \
24  int color_index; \
25  float r, g, b, a; \
26  unsigned short blit_buffer_starting_index; \
27  if(target == NULL) \
28  { \
29  GPU_PushErrorCode(function_name, GPU_ERROR_NULL_ARGUMENT, "target"); \
30  return; \
31  } \
32  if(renderer != target->renderer) \
33  { \
34  GPU_PushErrorCode(function_name, GPU_ERROR_USER_ERROR, "Mismatched renderer"); \
35  return; \
36  } \
37  \
38  makeContextCurrent(renderer, target); \
39  if(renderer->current_context_target == NULL) \
40  { \
41  GPU_PushErrorCode(function_name, GPU_ERROR_USER_ERROR, "NULL context"); \
42  return; \
43  } \
44  \
45  if(!bindFramebuffer(renderer, target)) \
46  { \
47  GPU_PushErrorCode(function_name, GPU_ERROR_BACKEND_ERROR, "Failed to bind framebuffer."); \
48  return; \
49  } \
50  \
51  prepareToRenderToTarget(renderer, target); \
52  prepareToRenderShapes(renderer, shape); \
53  \
54  cdata = (GPU_CONTEXT_DATA*)renderer->current_context_target->context->data; \
55  \
56  if(cdata->blit_buffer_num_vertices + (num_additional_vertices) >= cdata->blit_buffer_max_num_vertices) \
57  { \
58  if(!growBlitBuffer(cdata, cdata->blit_buffer_num_vertices + (num_additional_vertices))) \
59  renderer->impl->FlushBlitBuffer(renderer); \
60  } \
61  if(cdata->index_buffer_num_vertices + (num_additional_indices) >= cdata->index_buffer_max_num_vertices) \
62  { \
63  if(!growIndexBuffer(cdata, cdata->index_buffer_num_vertices + (num_additional_indices))) \
64  renderer->impl->FlushBlitBuffer(renderer); \
65  } \
66  \
67  blit_buffer = cdata->blit_buffer; \
68  index_buffer = cdata->index_buffer; \
69  \
70  vert_index = GPU_BLIT_BUFFER_VERTEX_OFFSET + cdata->blit_buffer_num_vertices*GPU_BLIT_BUFFER_FLOATS_PER_VERTEX; \
71  color_index = GPU_BLIT_BUFFER_COLOR_OFFSET + cdata->blit_buffer_num_vertices*GPU_BLIT_BUFFER_FLOATS_PER_VERTEX; \
72  \
73  if(target->use_color) \
74  { \
75  r = MIX_COLOR_COMPONENT_NORMALIZED_RESULT(target->color.r, color.r); \
76  g = MIX_COLOR_COMPONENT_NORMALIZED_RESULT(target->color.g, color.g); \
77  b = MIX_COLOR_COMPONENT_NORMALIZED_RESULT(target->color.b, color.b); \
78  a = MIX_COLOR_COMPONENT_NORMALIZED_RESULT(GET_ALPHA(target->color), GET_ALPHA(color)); \
79  } \
80  else \
81  { \
82  r = color.r/255.0f; \
83  g = color.g/255.0f; \
84  b = color.b/255.0f; \
85  a = GET_ALPHA(color)/255.0f; \
86  } \
87  blit_buffer_starting_index = cdata->blit_buffer_num_vertices; \
88  (void)blit_buffer_starting_index;
89 
90 
91 
92 
93 
94 static float SetLineThickness(GPU_Renderer* renderer, float thickness)
95 {
96  float old;
97 
98  if(renderer->current_context_target == NULL)
99  return 1.0f;
100 
102  if(old != thickness)
103  renderer->impl->FlushBlitBuffer(renderer);
104 
105  renderer->current_context_target->context->line_thickness = thickness;
106  #ifndef SDL_GPU_SKIP_LINE_WIDTH
107  glLineWidth(thickness);
108  #endif
109  return old;
110 }
111 
112 static float GetLineThickness(GPU_Renderer* renderer)
113 {
114  return renderer->current_context_target->context->line_thickness;
115 }
116 
117 static void Pixel(GPU_Renderer* renderer, GPU_Target* target, float x, float y, SDL_Color color)
118 {
119  BEGIN_UNTEXTURED("GPU_Pixel", GL_POINTS, 1, 1);
120 
121  SET_UNTEXTURED_VERTEX(x, y, r, g, b, a);
122 }
123 
124 static void Line(GPU_Renderer* renderer, GPU_Target* target, float x1, float y1, float x2, float y2, SDL_Color color)
125 {
126  float thickness = GetLineThickness(renderer);
127 
128  float t = thickness/2;
129  float line_angle = atan2f(y2 - y1, x2 - x1);
130  float tc = t*cosf(line_angle);
131  float ts = t*sinf(line_angle);
132 
133  BEGIN_UNTEXTURED("GPU_Line", GL_TRIANGLES, 4, 6);
134 
135  SET_UNTEXTURED_VERTEX(x1 + ts, y1 - tc, r, g, b, a);
136  SET_UNTEXTURED_VERTEX(x1 - ts, y1 + tc, r, g, b, a);
137  SET_UNTEXTURED_VERTEX(x2 + ts, y2 - tc, r, g, b, a);
138 
141  SET_UNTEXTURED_VERTEX(x2 - ts, y2 + tc, r, g, b, a);
142 }
143 
144 // Arc() might call Circle()
145 static void Circle(GPU_Renderer* renderer, GPU_Target* target, float x, float y, float radius, SDL_Color color);
146 
147 static void Arc(GPU_Renderer* renderer, GPU_Target* target, float x, float y, float radius, float start_angle, float end_angle, SDL_Color color)
148 {
149  float dx, dy;
150  int i;
151 
152  float t = GetLineThickness(renderer)/2;
153  float inner_radius = radius - t;
154  float outer_radius = radius + t;
155 
156  float dt;
157  int numSegments;
158 
159  float tempx;
160  float c, s;
161 
162  if(inner_radius < 0.0f)
163  inner_radius = 0.0f;
164 
165  if(start_angle > end_angle)
166  {
167  float swapa = end_angle;
168  end_angle = start_angle;
169  start_angle = swapa;
170  }
171  if(start_angle == end_angle)
172  return;
173 
174  // Big angle
175  if(end_angle - start_angle >= 360)
176  {
177  Circle(renderer, target, x, y, radius, color);
178  return;
179  }
180 
181  // Shift together
182  while(start_angle < 0 && end_angle < 0)
183  {
184  start_angle += 360;
185  end_angle += 360;
186  }
187  while(start_angle > 360 && end_angle > 360)
188  {
189  start_angle -= 360;
190  end_angle -= 360;
191  }
192 
193 
194  dt = ((end_angle - start_angle)/360)*(1.25f/sqrtf(outer_radius)); // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.
195 
196  numSegments = (fabs(end_angle - start_angle)*M_PI/180)/dt;
197  if(numSegments == 0)
198  return;
199 
200  {
201  BEGIN_UNTEXTURED("GPU_Arc", GL_TRIANGLES, 2*(numSegments), 6*(numSegments));
202 
203  c = cos(dt);
204  s = sin(dt);
205 
206  // Rotate to start
207  start_angle *= M_PI/180;
208  dx = cos(start_angle);
209  dy = sin(start_angle);
210 
211  BEGIN_UNTEXTURED_SEGMENTS(x+inner_radius*dx, y+inner_radius*dy, x+outer_radius*dx, y+outer_radius*dy, r, g, b, a);
212 
213  for (i = 1; i < numSegments; i++)
214  {
215  tempx = c * dx - s * dy;
216  dy = s * dx + c * dy;
217  dx = tempx;
218  SET_UNTEXTURED_SEGMENTS(x+inner_radius*dx, y+inner_radius*dy, x+outer_radius*dx, y+outer_radius*dy, r, g, b, a);
219  }
220 
221  // Last point
222  end_angle *= M_PI/180;
223  dx = cos(end_angle);
224  dy = sin(end_angle);
225  END_UNTEXTURED_SEGMENTS(x+inner_radius*dx, y+inner_radius*dy, x+outer_radius*dx, y+outer_radius*dy, r, g, b, a);
226  }
227 }
228 
229 // ArcFilled() might call CircleFilled()
230 static void CircleFilled(GPU_Renderer* renderer, GPU_Target* target, float x, float y, float radius, SDL_Color color);
231 
232 static void ArcFilled(GPU_Renderer* renderer, GPU_Target* target, float x, float y, float radius, float start_angle, float end_angle, SDL_Color color)
233 {
234  float dx, dy;
235  int i;
236 
237  float dt;
238  int numSegments;
239 
240  float tempx;
241  float c, s;
242 
243  if(start_angle > end_angle)
244  {
245  float swapa = end_angle;
246  end_angle = start_angle;
247  start_angle = swapa;
248  }
249  if(start_angle == end_angle)
250  return;
251 
252  // Big angle
253  if(end_angle - start_angle >= 360)
254  {
255  CircleFilled(renderer, target, x, y, radius, color);
256  return;
257  }
258 
259  // Shift together
260  while(start_angle < 0 && end_angle < 0)
261  {
262  start_angle += 360;
263  end_angle += 360;
264  }
265  while(start_angle > 360 && end_angle > 360)
266  {
267  start_angle -= 360;
268  end_angle -= 360;
269  }
270 
271  dt = ((end_angle - start_angle)/360)*(1.25f/sqrtf(radius)); // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.
272 
273  numSegments = (fabs(end_angle - start_angle)*M_PI/180)/dt;
274  if(numSegments == 0)
275  return;
276 
277  {
278  BEGIN_UNTEXTURED("GPU_ArcFilled", GL_TRIANGLES, 3 + (numSegments - 1) + 1, 3 + (numSegments - 1) * 3 + 3);
279 
280  c = cos(dt);
281  s = sin(dt);
282 
283  // Rotate to start
284  start_angle *= M_PI/180;
285  dx = cos(start_angle);
286  dy = sin(start_angle);
287 
288  // First triangle
289  SET_UNTEXTURED_VERTEX(x, y, r, g, b, a);
290  SET_UNTEXTURED_VERTEX(x + radius*dx, y + radius*dy, r, g, b, a); // first point
291 
292  tempx = c * dx - s * dy;
293  dy = s * dx + c * dy;
294  dx = tempx;
295  SET_UNTEXTURED_VERTEX(x + radius*dx, y + radius*dy, r, g, b, a); // new point
296 
297  for (i = 2; i < numSegments + 1; i++)
298  {
299  tempx = c * dx - s * dy;
300  dy = s * dx + c * dy;
301  dx = tempx;
302  SET_INDEXED_VERTEX(0); // center
303  SET_INDEXED_VERTEX(i); // last point
304  SET_UNTEXTURED_VERTEX(x + radius*dx, y + radius*dy, r, g, b, a); // new point
305  }
306 
307  // Last triangle
308  end_angle *= M_PI/180;
309  dx = cos(end_angle);
310  dy = sin(end_angle);
311  SET_INDEXED_VERTEX(0); // center
312  SET_INDEXED_VERTEX(i); // last point
313  SET_UNTEXTURED_VERTEX(x + radius*dx, y + radius*dy, r, g, b, a); // new point
314  }
315 }
316 
317 
318 /*
319 Incremental rotation circle algorithm
320 */
321 
322 static void Circle(GPU_Renderer* renderer, GPU_Target* target, float x, float y, float radius, SDL_Color color)
323 {
324  float thickness = GetLineThickness(renderer);
325  float dx, dy;
326  int i;
327  float t = thickness/2;
328  float inner_radius = radius - t;
329  float outer_radius = radius + t;
330  float dt = (1.25f/sqrtf(outer_radius)); // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.
331  int numSegments = 2*M_PI/dt+1;
332 
333  float tempx;
334  float c = cos(dt);
335  float s = sin(dt);
336 
337  BEGIN_UNTEXTURED("GPU_Circle", GL_TRIANGLES, 2*(numSegments), 6*(numSegments));
338 
339  if(inner_radius < 0.0f)
340  inner_radius = 0.0f;
341 
342  dx = 1.0f;
343  dy = 0.0f;
344 
345  BEGIN_UNTEXTURED_SEGMENTS(x+inner_radius*dx, y+inner_radius*dy, x+outer_radius*dx, y+outer_radius*dy, r, g, b, a);
346 
347  for(i = 1; i < numSegments; i++)
348  {
349  tempx = c * dx - s * dy;
350  dy = s * dx + c * dy;
351  dx = tempx;
352 
353  SET_UNTEXTURED_SEGMENTS(x+inner_radius*dx, y+inner_radius*dy, x+outer_radius*dx, y+outer_radius*dy, r, g, b, a);
354  }
355 
356  LOOP_UNTEXTURED_SEGMENTS(); // back to the beginning
357 }
358 
359 static void CircleFilled(GPU_Renderer* renderer, GPU_Target* target, float x, float y, float radius, SDL_Color color)
360 {
361  float dt = (1.25f/sqrtf(radius)); // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.
362  float dx, dy;
363  int numSegments = 2*M_PI/dt+1;
364  int i;
365 
366  float tempx;
367  float c = cos(dt);
368  float s = sin(dt);
369 
370  BEGIN_UNTEXTURED("GPU_CircleFilled", GL_TRIANGLES, 3 + (numSegments-2), 3 + (numSegments-2)*3 + 3);
371 
372  // First triangle
373  SET_UNTEXTURED_VERTEX(x, y, r, g, b, a); // Center
374 
375  dx = 1.0f;
376  dy = 0.0f;
377  SET_UNTEXTURED_VERTEX(x+radius*dx, y+radius*dy, r, g, b, a); // first point
378 
379  tempx = c * dx - s * dy;
380  dy = s * dx + c * dy;
381  dx = tempx;
382  SET_UNTEXTURED_VERTEX(x+radius*dx, y+radius*dy, r, g, b, a); // new point
383 
384  for(i = 2; i < numSegments; i++)
385  {
386  tempx = c * dx - s * dy;
387  dy = s * dx + c * dy;
388  dx = tempx;
389  SET_INDEXED_VERTEX(0); // center
390  SET_INDEXED_VERTEX(i); // last point
391  SET_UNTEXTURED_VERTEX(x+radius*dx, y+radius*dy, r, g, b, a); // new point
392  }
393 
394  SET_INDEXED_VERTEX(0); // center
395  SET_INDEXED_VERTEX(i); // last point
396  SET_INDEXED_VERTEX(1); // first point
397 }
398 
399 static void Ellipse(GPU_Renderer* renderer, GPU_Target* target, float x, float y, float rx, float ry, float degrees, SDL_Color color)
400 {
401  float thickness = GetLineThickness(renderer);
402  float dx, dy;
403  int i;
404  float t = thickness/2;
405  float rot_x = cos(degrees*M_PI/180);
406  float rot_y = sin(degrees*M_PI/180);
407  float inner_radius_x = rx - t;
408  float outer_radius_x = rx + t;
409  float inner_radius_y = ry - t;
410  float outer_radius_y = ry + t;
411  float dt = (1.25f/sqrtf(outer_radius_x > outer_radius_y? outer_radius_x : outer_radius_y)); // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.
412  int numSegments = 2*M_PI/dt+1;
413 
414  float tempx;
415  float c = cos(dt);
416  float s = sin(dt);
417  float inner_trans_x, inner_trans_y;
418  float outer_trans_x, outer_trans_y;
419 
420  BEGIN_UNTEXTURED("GPU_Ellipse", GL_TRIANGLES, 2*(numSegments), 6*(numSegments));
421 
422  if(inner_radius_x < 0.0f)
423  inner_radius_x = 0.0f;
424  if(inner_radius_y < 0.0f)
425  inner_radius_y = 0.0f;
426 
427  dx = 1.0f;
428  dy = 0.0f;
429 
430  inner_trans_x = rot_x * inner_radius_x*dx - rot_y * inner_radius_y*dy;
431  inner_trans_y = rot_y * inner_radius_x*dx + rot_x * inner_radius_y*dy;
432  outer_trans_x = rot_x * outer_radius_x*dx - rot_y * outer_radius_y*dy;
433  outer_trans_y = rot_y * outer_radius_x*dx + rot_x * outer_radius_y*dy;
434  BEGIN_UNTEXTURED_SEGMENTS(x+inner_trans_x, y+inner_trans_y, x+outer_trans_x, y+outer_trans_y, r, g, b, a);
435 
436  for(i = 1; i < numSegments; i++)
437  {
438  tempx = c * dx - s * dy;
439  dy = (s * dx + c * dy);
440  dx = tempx;
441 
442  inner_trans_x = rot_x * inner_radius_x*dx - rot_y * inner_radius_y*dy;
443  inner_trans_y = rot_y * inner_radius_x*dx + rot_x * inner_radius_y*dy;
444  outer_trans_x = rot_x * outer_radius_x*dx - rot_y * outer_radius_y*dy;
445  outer_trans_y = rot_y * outer_radius_x*dx + rot_x * outer_radius_y*dy;
446  SET_UNTEXTURED_SEGMENTS(x+inner_trans_x, y+inner_trans_y, x+outer_trans_x, y+outer_trans_y, r, g, b, a);
447  }
448 
449  LOOP_UNTEXTURED_SEGMENTS(); // back to the beginning
450 }
451 
452 static void EllipseFilled(GPU_Renderer* renderer, GPU_Target* target, float x, float y, float rx, float ry, float degrees, SDL_Color color)
453 {
454  float dx, dy;
455  int i;
456  float rot_x = cos(degrees*M_PI/180);
457  float rot_y = sin(degrees*M_PI/180);
458  float dt = (1.25f/sqrtf(rx > ry? rx : ry)); // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.
459  int numSegments = 2*M_PI/dt+1;
460 
461  float tempx;
462  float c = cos(dt);
463  float s = sin(dt);
464  float trans_x, trans_y;
465 
466  BEGIN_UNTEXTURED("GPU_EllipseFilled", GL_TRIANGLES, 3 + (numSegments-2), 3 + (numSegments-2)*3 + 3);
467 
468  // First triangle
469  SET_UNTEXTURED_VERTEX(x, y, r, g, b, a); // Center
470 
471  dx = 1.0f;
472  dy = 0.0f;
473  trans_x = rot_x * rx*dx - rot_y * ry*dy;
474  trans_y = rot_y * rx*dx + rot_x * ry*dy;
475  SET_UNTEXTURED_VERTEX(x+trans_x, y+trans_y, r, g, b, a); // first point
476 
477  tempx = c * dx - s * dy;
478  dy = s * dx + c * dy;
479  dx = tempx;
480 
481  trans_x = rot_x * rx*dx - rot_y * ry*dy;
482  trans_y = rot_y * rx*dx + rot_x * ry*dy;
483  SET_UNTEXTURED_VERTEX(x+trans_x, y+trans_y, r, g, b, a); // new point
484 
485  for(i = 2; i < numSegments; i++)
486  {
487  tempx = c * dx - s * dy;
488  dy = (s * dx + c * dy);
489  dx = tempx;
490 
491  trans_x = rot_x * rx*dx - rot_y * ry*dy;
492  trans_y = rot_y * rx*dx + rot_x * ry*dy;
493 
494  SET_INDEXED_VERTEX(0); // center
495  SET_INDEXED_VERTEX(i); // last point
496  SET_UNTEXTURED_VERTEX(x+trans_x, y+trans_y, r, g, b, a); // new point
497  }
498 
499  SET_INDEXED_VERTEX(0); // center
500  SET_INDEXED_VERTEX(i); // last point
501  SET_INDEXED_VERTEX(1); // first point
502 }
503 
504 static void Sector(GPU_Renderer* renderer, GPU_Target* target, float x, float y, float inner_radius, float outer_radius, float start_angle, float end_angle, SDL_Color color)
505 {
506  GPU_bool circled;
507  float dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4;
508 
509  if(inner_radius < 0.0f)
510  inner_radius = 0.0f;
511  if(outer_radius < 0.0f)
512  outer_radius = 0.0f;
513 
514  if(inner_radius > outer_radius)
515  {
516  float s = inner_radius;
517  inner_radius = outer_radius;
518  outer_radius = s;
519  }
520 
521  if(start_angle > end_angle)
522  {
523  float swapa = end_angle;
524  end_angle = start_angle;
525  start_angle = swapa;
526  }
527  if(start_angle == end_angle)
528  return;
529 
530  if(inner_radius == outer_radius)
531  {
532  Arc(renderer, target, x, y, inner_radius, start_angle, end_angle, color);
533  return;
534  }
535 
536  circled = (end_angle - start_angle >= 360);
537  // Composited shape... But that means error codes may be confusing. :-/
538  Arc(renderer, target, x, y, inner_radius, start_angle, end_angle, color);
539 
540  if(!circled)
541  {
542  dx1 = inner_radius*cos(end_angle*RADPERDEG);
543  dy1 = inner_radius*sin(end_angle*RADPERDEG);
544  dx2 = outer_radius*cos(end_angle*RADPERDEG);
545  dy2 = outer_radius*sin(end_angle*RADPERDEG);
546  Line(renderer, target, x+dx1, y+dy1, x+dx2, y+dy2, color);
547  }
548 
549  Arc(renderer, target, x, y, outer_radius, start_angle, end_angle, color);
550 
551  if(!circled)
552  {
553  dx3 = inner_radius*cos(start_angle*RADPERDEG);
554  dy3 = inner_radius*sin(start_angle*RADPERDEG);
555  dx4 = outer_radius*cos(start_angle*RADPERDEG);
556  dy4 = outer_radius*sin(start_angle*RADPERDEG);
557  Line(renderer, target, x+dx3, y+dy3, x+dx4, y+dy4, color);
558  }
559 }
560 
561 static void SectorFilled(GPU_Renderer* renderer, GPU_Target* target, float x, float y, float inner_radius, float outer_radius, float start_angle, float end_angle, SDL_Color color)
562 {
563  float t;
564  float dt;
565  float dx, dy;
566 
567  int numSegments;
568 
569  if(inner_radius < 0.0f)
570  inner_radius = 0.0f;
571  if(outer_radius < 0.0f)
572  outer_radius = 0.0f;
573 
574  if(inner_radius > outer_radius)
575  {
576  float s = inner_radius;
577  inner_radius = outer_radius;
578  outer_radius = s;
579  }
580 
581  if(inner_radius == outer_radius)
582  {
583  Arc(renderer, target, x, y, inner_radius, start_angle, end_angle, color);
584  return;
585  }
586 
587 
588  if(start_angle > end_angle)
589  {
590  float swapa = end_angle;
591  end_angle = start_angle;
592  start_angle = swapa;
593  }
594  if(start_angle == end_angle)
595  return;
596 
597  if(end_angle - start_angle >= 360)
598  end_angle = start_angle + 360;
599 
600 
601  t = start_angle;
602  dt = ((end_angle - start_angle)/360)*(1.25f/sqrtf(outer_radius)) * DEGPERRAD; // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.
603 
604  numSegments = fabs(end_angle - start_angle)/dt;
605  if(numSegments == 0)
606  return;
607 
608  {
609  int i;
610  GPU_bool use_inner;
611  BEGIN_UNTEXTURED("GPU_SectorFilled", GL_TRIANGLES, 3 + (numSegments - 1) + 1, 3 + (numSegments - 1) * 3 + 3);
612 
613  use_inner = GPU_FALSE; // Switches between the radii for the next point
614 
615  // First triangle
616  dx = inner_radius*cos(t*RADPERDEG);
617  dy = inner_radius*sin(t*RADPERDEG);
618  SET_UNTEXTURED_VERTEX(x + dx, y + dy, r, g, b, a);
619 
620  dx = outer_radius*cos(t*RADPERDEG);
621  dy = outer_radius*sin(t*RADPERDEG);
622  SET_UNTEXTURED_VERTEX(x + dx, y + dy, r, g, b, a);
623  t += dt;
624  dx = inner_radius*cos(t*RADPERDEG);
625  dy = inner_radius*sin(t*RADPERDEG);
626  SET_UNTEXTURED_VERTEX(x + dx, y + dy, r, g, b, a);
627  t += dt;
628 
629  for (i = 2; i < numSegments + 1; i++)
630  {
631  SET_INDEXED_VERTEX(i - 1);
633  if (use_inner)
634  {
635  dx = inner_radius*cos(t*RADPERDEG);
636  dy = inner_radius*sin(t*RADPERDEG);
637  }
638  else
639  {
640  dx = outer_radius*cos(t*RADPERDEG);
641  dy = outer_radius*sin(t*RADPERDEG);
642  }
643  SET_UNTEXTURED_VERTEX(x + dx, y + dy, r, g, b, a); // new point
644  t += dt;
645  use_inner = !use_inner;
646  }
647 
648  // Last quad
649  t = end_angle;
650  if (use_inner)
651  {
652  dx = inner_radius*cos(t*RADPERDEG);
653  dy = inner_radius*sin(t*RADPERDEG);
654  }
655  else
656  {
657  dx = outer_radius*cos(t*RADPERDEG);
658  dy = outer_radius*sin(t*RADPERDEG);
659  }
660  SET_INDEXED_VERTEX(i - 1);
662  SET_UNTEXTURED_VERTEX(x + dx, y + dy, r, g, b, a); // new point
663  use_inner = !use_inner;
664  i++;
665 
666  if (use_inner)
667  {
668  dx = inner_radius*cos(t*RADPERDEG);
669  dy = inner_radius*sin(t*RADPERDEG);
670  }
671  else
672  {
673  dx = outer_radius*cos(t*RADPERDEG);
674  dy = outer_radius*sin(t*RADPERDEG);
675  }
676  SET_INDEXED_VERTEX(i - 1);
678  SET_UNTEXTURED_VERTEX(x + dx, y + dy, r, g, b, a); // new point
679  }
680 }
681 
682 static void Tri(GPU_Renderer* renderer, GPU_Target* target, float x1, float y1, float x2, float y2, float x3, float y3, SDL_Color color)
683 {
684  BEGIN_UNTEXTURED("GPU_Tri", GL_LINES, 3, 6);
685 
686  SET_UNTEXTURED_VERTEX(x1, y1, r, g, b, a);
687  SET_UNTEXTURED_VERTEX(x2, y2, r, g, b, a);
688 
690  SET_UNTEXTURED_VERTEX(x3, y3, r, g, b, a);
691 
694 }
695 
696 static void TriFilled(GPU_Renderer* renderer, GPU_Target* target, float x1, float y1, float x2, float y2, float x3, float y3, SDL_Color color)
697 {
698  BEGIN_UNTEXTURED("GPU_TriFilled", GL_TRIANGLES, 3, 3);
699 
700  SET_UNTEXTURED_VERTEX(x1, y1, r, g, b, a);
701  SET_UNTEXTURED_VERTEX(x2, y2, r, g, b, a);
702  SET_UNTEXTURED_VERTEX(x3, y3, r, g, b, a);
703 }
704 
705 static void Rectangle(GPU_Renderer* renderer, GPU_Target* target, float x1, float y1, float x2, float y2, SDL_Color color)
706 {
707  if(y2 < y1)
708  {
709  float y = y1;
710  y1 = y2;
711  y2 = y;
712  }
713  if(x2 < x1)
714  {
715  float x = x1;
716  x1 = x2;
717  x2 = x;
718  }
719 
720  {
721  float thickness = GetLineThickness(renderer);
722 
723  // Thickness offsets
724  float outer = thickness / 2;
725  float inner_x = outer;
726  float inner_y = outer;
727 
728  // Thick lines via filled triangles
729 
730  BEGIN_UNTEXTURED("GPU_Rectangle", GL_TRIANGLES, 12, 24);
731 
732  // Adjust inner thickness offsets to avoid overdraw on narrow/small rects
733  if(x1 + inner_x > x2 - inner_x)
734  inner_x = (x2 - x1)/2;
735  if(y1 + inner_y > y2 - inner_y)
736  inner_y = (y2 - y1)/2;
737 
738  // First triangle
739  SET_UNTEXTURED_VERTEX(x1 - outer, y1 - outer, r, g, b, a); // 0
740  SET_UNTEXTURED_VERTEX(x1 - outer, y1 + inner_y, r, g, b, a); // 1
741  SET_UNTEXTURED_VERTEX(x2 + outer, y1 - outer, r, g, b, a); // 2
742 
745  SET_UNTEXTURED_VERTEX(x2 + outer, y1 + inner_y, r, g, b, a); // 3
746 
748  SET_UNTEXTURED_VERTEX(x2 - inner_x, y1 + inner_y, r, g, b, a); // 4
749  SET_UNTEXTURED_VERTEX(x2 - inner_x, y2 - inner_y, r, g, b, a); // 5
750 
753  SET_UNTEXTURED_VERTEX(x2 + outer, y2 - inner_y, r, g, b, a); // 6
754 
756  SET_UNTEXTURED_VERTEX(x1 - outer, y2 - inner_y, r, g, b, a); // 7
757  SET_UNTEXTURED_VERTEX(x2 + outer, y2 + outer, r, g, b, a); // 8
758 
760  SET_UNTEXTURED_VERTEX(x1 - outer, y2 + outer, r, g, b, a); // 9
762 
764  SET_UNTEXTURED_VERTEX(x1 + inner_x, y2 - inner_y, r, g, b, a); // 10
766 
768  SET_INDEXED_VERTEX(10);
769  SET_UNTEXTURED_VERTEX(x1 + inner_x, y1 + inner_y, r, g, b, a); // 11
770  }
771 }
772 
773 static void RectangleFilled(GPU_Renderer* renderer, GPU_Target* target, float x1, float y1, float x2, float y2, SDL_Color color)
774 {
775  BEGIN_UNTEXTURED("GPU_RectangleFilled", GL_TRIANGLES, 4, 6);
776 
777  SET_UNTEXTURED_VERTEX(x1, y1, r, g, b, a);
778  SET_UNTEXTURED_VERTEX(x1, y2, r, g, b, a);
779  SET_UNTEXTURED_VERTEX(x2, y1, r, g, b, a);
780 
783  SET_UNTEXTURED_VERTEX(x2, y2, r, g, b, a);
784 }
785 
786 #define INCREMENT_CIRCLE \
787  tempx = c * dx - s * dy; \
788  dy = s * dx + c * dy; \
789  dx = tempx; \
790  ++i;
791 
792 static void RectangleRound(GPU_Renderer* renderer, GPU_Target* target, float x1, float y1, float x2, float y2, float radius, SDL_Color color)
793 {
794  if(y2 < y1)
795  {
796  float temp = y2;
797  y2 = y1;
798  y1 = temp;
799  }
800  if(x2 < x1)
801  {
802  float temp = x2;
803  x2 = x1;
804  x1 = temp;
805  }
806 
807  if(radius > (x2-x1)/2)
808  radius = (x2-x1)/2;
809  if(radius > (y2-y1)/2)
810  radius = (y2 - y1) / 2;
811 
812  x1 += radius;
813  y1 += radius;
814  x2 -= radius;
815  y2 -= radius;
816 
817  {
818  float thickness = GetLineThickness(renderer);
819  float dx, dy;
820  int i = 0;
821  float t = thickness/2;
822  float inner_radius = radius - t;
823  float outer_radius = radius + t;
824  float dt = (1.25f/sqrtf(outer_radius)); // s = rA, so dA = ds/r. ds of 1.25*sqrt(radius) is good, use A in degrees.
825  int numSegments = 2*M_PI/dt+1;
826  if(numSegments < 4)
827  numSegments = 4;
828 
829  // Make a multiple of 4 so we can have even corners
830  numSegments += numSegments % 4;
831 
832  dt = 2*M_PI/(numSegments-1);
833 
834  {
835  float x, y;
836  int go_to_second = numSegments / 4;
837  int go_to_third = numSegments / 2;
838  int go_to_fourth = 3*numSegments / 4;
839 
840  float tempx;
841  float c = cos(dt);
842  float s = sin(dt);
843 
844  // Add another 4 for the extra corner vertices
845  BEGIN_UNTEXTURED("GPU_RectangleRound", GL_TRIANGLES, 2*(numSegments + 4), 6*(numSegments + 4));
846 
847  if(inner_radius < 0.0f)
848  inner_radius = 0.0f;
849 
850  dx = 1.0f;
851  dy = 0.0f;
852 
853  x = x2;
854  y = y2;
855  BEGIN_UNTEXTURED_SEGMENTS(x+inner_radius, y, x+outer_radius, y, r, g, b, a);
856  while(i < go_to_second-1)
857  {
859 
860  SET_UNTEXTURED_SEGMENTS(x+inner_radius*dx, y+inner_radius*dy, x+outer_radius*dx, y+outer_radius*dy, r, g, b, a);
861  }
863 
864  SET_UNTEXTURED_SEGMENTS(x, y+inner_radius, x, y+outer_radius, r, g, b, a);
865  x = x1;
866  y = y2;
867  SET_UNTEXTURED_SEGMENTS(x, y+inner_radius, x, y+outer_radius, r, g, b, a);
868  while(i < go_to_third-1)
869  {
871 
872  SET_UNTEXTURED_SEGMENTS(x+inner_radius*dx, y+inner_radius*dy, x+outer_radius*dx, y+outer_radius*dy, r, g, b, a);
873  }
875 
876  SET_UNTEXTURED_SEGMENTS(x-inner_radius, y, x-outer_radius, y, r, g, b, a);
877  x = x1;
878  y = y1;
879  SET_UNTEXTURED_SEGMENTS(x-inner_radius, y, x-outer_radius, y, r, g, b, a);
880  while(i < go_to_fourth-1)
881  {
883 
884  SET_UNTEXTURED_SEGMENTS(x+inner_radius*dx, y+inner_radius*dy, x+outer_radius*dx, y+outer_radius*dy, r, g, b, a);
885  }
887 
888  SET_UNTEXTURED_SEGMENTS(x, y-inner_radius, x, y-outer_radius, r, g, b, a);
889  x = x2;
890  y = y1;
891  SET_UNTEXTURED_SEGMENTS(x, y-inner_radius, x, y-outer_radius, r, g, b, a);
892  while(i < numSegments-1)
893  {
895 
896  SET_UNTEXTURED_SEGMENTS(x+inner_radius*dx, y+inner_radius*dy, x+outer_radius*dx, y+outer_radius*dy, r, g, b, a);
897  }
898  SET_UNTEXTURED_SEGMENTS(x+inner_radius, y, x+outer_radius, y, r, g, b, a);
899 
900  LOOP_UNTEXTURED_SEGMENTS(); // back to the beginning
901  }
902  }
903 }
904 
905 static void RectangleRoundFilled(GPU_Renderer* renderer, GPU_Target* target, float x1, float y1, float x2, float y2, float radius, SDL_Color color)
906 {
907  if(y2 < y1)
908  {
909  float temp = y2;
910  y2 = y1;
911  y1 = temp;
912  }
913  if(x2 < x1)
914  {
915  float temp = x2;
916  x2 = x1;
917  x1 = temp;
918  }
919 
920  if(radius > (x2-x1)/2)
921  radius = (x2-x1)/2;
922  if(radius > (y2-y1)/2)
923  radius = (y2 - y1) / 2;
924 
925  {
926  float tau = 2 * M_PI;
927 
928  int verts_per_corner = 7;
929  float corner_angle_increment = (tau / 4) / (verts_per_corner - 1); // 0, 15, 30, 45, 60, 75, 90
930 
931  // Starting angle
932  float angle = tau*0.75f;
933  int last_index = 2;
934  int i;
935 
936  BEGIN_UNTEXTURED("GPU_RectangleRoundFilled", GL_TRIANGLES, 6 + 4 * (verts_per_corner - 1) - 1, 15 + 4 * (verts_per_corner - 1) * 3 - 3);
937 
938 
939  // First triangle
940  SET_UNTEXTURED_VERTEX((x2 + x1) / 2, (y2 + y1) / 2, r, g, b, a); // Center
941  SET_UNTEXTURED_VERTEX(x2 - radius + cos(angle)*radius, y1 + radius + sin(angle)*radius, r, g, b, a);
942  angle += corner_angle_increment;
943  SET_UNTEXTURED_VERTEX(x2 - radius + cos(angle)*radius, y1 + radius + sin(angle)*radius, r, g, b, a);
944  angle += corner_angle_increment;
945 
946  for (i = 2; i < verts_per_corner; i++)
947  {
949  SET_INDEXED_VERTEX(last_index++);
950  SET_UNTEXTURED_VERTEX(x2 - radius + cos(angle)*radius, y1 + radius + sin(angle)*radius, r, g, b, a);
951  angle += corner_angle_increment;
952  }
953 
955  SET_INDEXED_VERTEX(last_index++);
956  SET_UNTEXTURED_VERTEX(x2 - radius + cos(angle)*radius, y2 - radius + sin(angle)*radius, r, g, b, a);
957  for (i = 1; i < verts_per_corner; i++)
958  {
960  SET_INDEXED_VERTEX(last_index++);
961  SET_UNTEXTURED_VERTEX(x2 - radius + cos(angle)*radius, y2 - radius + sin(angle)*radius, r, g, b, a);
962  angle += corner_angle_increment;
963  }
964 
966  SET_INDEXED_VERTEX(last_index++);
967  SET_UNTEXTURED_VERTEX(x1 + radius + cos(angle)*radius, y2 - radius + sin(angle)*radius, r, g, b, a);
968  for (i = 1; i < verts_per_corner; i++)
969  {
971  SET_INDEXED_VERTEX(last_index++);
972  SET_UNTEXTURED_VERTEX(x1 + radius + cos(angle)*radius, y2 - radius + sin(angle)*radius, r, g, b, a);
973  angle += corner_angle_increment;
974  }
975 
977  SET_INDEXED_VERTEX(last_index++);
978  SET_UNTEXTURED_VERTEX(x1 + radius + cos(angle)*radius, y1 + radius + sin(angle)*radius, r, g, b, a);
979  for (i = 1; i < verts_per_corner; i++)
980  {
982  SET_INDEXED_VERTEX(last_index++);
983  SET_UNTEXTURED_VERTEX(x1 + radius + cos(angle)*radius, y1 + radius + sin(angle)*radius, r, g, b, a);
984  angle += corner_angle_increment;
985  }
986 
987  // Last triangle
989  SET_INDEXED_VERTEX(last_index++);
991  }
992 }
993 
994 static void Polygon(GPU_Renderer* renderer, GPU_Target* target, unsigned int num_vertices, float* vertices, SDL_Color color)
995 {
996  if(num_vertices < 3)
997  return;
998 
999  {
1000  int numSegments = 2 * num_vertices;
1001  int last_index = 0;
1002  int i;
1003 
1004  BEGIN_UNTEXTURED("GPU_Polygon", GL_LINES, num_vertices, numSegments);
1005 
1006  SET_UNTEXTURED_VERTEX(vertices[0], vertices[1], r, g, b, a);
1007  for (i = 2; i < numSegments; i += 2)
1008  {
1009  SET_UNTEXTURED_VERTEX(vertices[i], vertices[i + 1], r, g, b, a);
1010  last_index++;
1011  SET_INDEXED_VERTEX(last_index); // Double the last one for the next line
1012  }
1013  SET_INDEXED_VERTEX(0);
1014  }
1015 }
1016 
1017 static void PolygonFilled(GPU_Renderer* renderer, GPU_Target* target, unsigned int num_vertices, float* vertices, SDL_Color color)
1018 {
1019  if(num_vertices < 3)
1020  return;
1021 
1022  {
1023  int numSegments = 2 * num_vertices;
1024 
1025  // Using a fan of triangles assumes that the polygon is convex
1026  BEGIN_UNTEXTURED("GPU_PolygonFilled", GL_TRIANGLES, num_vertices, 3 + (num_vertices - 3) * 3);
1027 
1028  // First triangle
1029  SET_UNTEXTURED_VERTEX(vertices[0], vertices[1], r, g, b, a);
1030  SET_UNTEXTURED_VERTEX(vertices[2], vertices[3], r, g, b, a);
1031  SET_UNTEXTURED_VERTEX(vertices[4], vertices[5], r, g, b, a);
1032 
1033  if (num_vertices > 3)
1034  {
1035  int last_index = 2;
1036 
1037  int i;
1038  for (i = 6; i < numSegments; i += 2)
1039  {
1040  SET_INDEXED_VERTEX(0); // Start from the first vertex
1041  SET_INDEXED_VERTEX(last_index); // Double the last one
1042  SET_UNTEXTURED_VERTEX(vertices[i], vertices[i + 1], r, g, b, a);
1043  last_index++;
1044  }
1045  }
1046  }
1047 }
1048 
#define END_UNTEXTURED_SEGMENTS(x1, y1, x2, y2, r, g, b, a)
float line_thickness
Definition: SDL_gpu.h:380
#define RADPERDEG
GPU_Target * current_context_target
Definition: SDL_gpu.h:667
#define INCREMENT_CIRCLE
#define SET_INDEXED_VERTEX(offset)
#define BEGIN_UNTEXTURED_SEGMENTS(x1, y1, x2, y2, r, g, b, a)
#define M_PI
#define SET_UNTEXTURED_SEGMENTS(x1, y1, x2, y2, r, g, b, a)
struct GPU_RendererImpl * impl
Definition: SDL_gpu.h:676
#define GPU_FALSE
Definition: SDL_gpu.h:62
#define LOOP_UNTEXTURED_SEGMENTS()
#define SET_UNTEXTURED_VERTEX(x, y, r, g, b, a)
#define BEGIN_UNTEXTURED(function_name, shape, num_additional_vertices, num_additional_indices)
GPU_Context * context
Definition: SDL_gpu.h:424
#define DEGPERRAD
#define GPU_bool
Definition: SDL_gpu.h:59