rays 0.3.11 → 0.3.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,6 +9,7 @@
9
9
  #include <functional>
10
10
  #include "rays/exception.h"
11
11
  #include "../glm.h"
12
+ #include "../coord.h"
12
13
  #include "../bitmap.h"
13
14
  #include "../image.h"
14
15
  #include "../font.h"
@@ -23,6 +24,19 @@ namespace Rays
23
24
  {
24
25
 
25
26
 
27
+ static const Shader INVALID_SHADER;
28
+
29
+ static const Texture INVALID_TEXTURE;
30
+
31
+
32
+ struct Vector4 : Coord4
33
+ {
34
+
35
+ Vector4 (const Coord3& p) {Coord4::operator=(p);}
36
+
37
+ };// Vector4
38
+
39
+
26
40
  struct OpenGLState
27
41
  {
28
42
 
@@ -128,6 +142,69 @@ namespace Rays
128
142
  };// DefaultIndices
129
143
 
130
144
 
145
+ struct Batcher
146
+ {
147
+
148
+ GLuint cached_shader_id = 0;
149
+
150
+ GLuint cached_texture_id = 0;
151
+
152
+ int count = 0;
153
+
154
+ BlendMode blend_mode;
155
+
156
+ TexCoordMode texcoord_mode;
157
+
158
+ TexCoordWrap texcoord_wrap;
159
+
160
+ Bounds clip;
161
+
162
+ Shader shader = INVALID_SHADER;
163
+
164
+ Texture texture = INVALID_TEXTURE;
165
+
166
+ std::vector<Vector4> points;
167
+
168
+ std::vector<uint> indices;
169
+
170
+ std::vector<Color> colors;
171
+
172
+ std::vector<Vector4> texcoords;
173
+
174
+ std::vector<Coord3> texcoord_mins;
175
+
176
+ std::vector<Coord3> texcoord_maxes;
177
+
178
+ void init (const PainterState& state)
179
+ {
180
+ cached_shader_id = 0;
181
+ cached_texture_id = 0;
182
+ blend_mode = state.blend_mode;
183
+ texcoord_mode = state.texcoord_mode;
184
+ texcoord_wrap = state.texcoord_wrap;
185
+ clip = state.clip;
186
+ }
187
+
188
+ void cleanup ()
189
+ {
190
+ shader = INVALID_SHADER;
191
+ texture = INVALID_TEXTURE;
192
+ }
193
+
194
+ void clear_buffers ()
195
+ {
196
+ count = 0;
197
+ points .clear();
198
+ indices .clear();
199
+ colors .clear();
200
+ texcoords .clear();
201
+ texcoord_mins .clear();
202
+ texcoord_maxes.clear();
203
+ }
204
+
205
+ };// Batcher
206
+
207
+
131
208
  struct PainterData : Painter::Data
132
209
  {
133
210
 
@@ -141,6 +218,10 @@ namespace Rays
141
218
 
142
219
  std::vector<GLuint> buffers;
143
220
 
221
+ std::vector<GLuint> triangle_fan_indices_buffer;
222
+
223
+ Batcher batcher;
224
+
144
225
  GLuint create_and_bind_buffer (GLenum target, const void* data, GLsizeiptr size)
145
226
  {
146
227
  GLuint id = 0;
@@ -176,60 +257,90 @@ namespace Rays
176
257
  buffers.clear();
177
258
  }
178
259
 
179
- };// PainterData
180
-
181
-
182
- static PainterData*
183
- get_data (Painter* painter)
184
- {
185
- return (PainterData*) painter->self.get();
186
- }
187
-
188
- void
189
- Painter_update_clip (Painter* painter)
190
- {
191
- PainterData* self = get_data(painter);
192
- const Bounds& clip = self->state.clip;
193
- if (clip)
260
+ void apply_blend_mode ()
194
261
  {
195
- coord y = self->frame_buffer ? clip.y : self->viewport.h - (clip.y + clip.h);
196
- glEnable(GL_SCISSOR_TEST);
197
- glScissor(
198
- self->pixel_density * clip.x,
199
- self->pixel_density * y,
200
- self->pixel_density * clip.width,
201
- self->pixel_density * clip.height);
262
+ switch (state.blend_mode)
263
+ {
264
+ case BLEND_NORMAL:
265
+ glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
266
+ glBlendFuncSeparate(
267
+ GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
268
+ break;
269
+
270
+ case BLEND_ADD:
271
+ glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
272
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE);
273
+ break;
274
+
275
+ case BLEND_SUBTRACT:
276
+ glBlendEquationSeparate(GL_FUNC_REVERSE_SUBTRACT, GL_FUNC_ADD);
277
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE);
278
+ break;
279
+
280
+ case BLEND_LIGHTEST:
281
+ glBlendEquationSeparate(GL_MAX, GL_FUNC_ADD);
282
+ glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ONE);
283
+ break;
284
+
285
+ case BLEND_DARKEST:
286
+ glBlendEquationSeparate(GL_MIN, GL_FUNC_ADD);
287
+ glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ONE);
288
+ break;
289
+
290
+ case BLEND_EXCLUSION:
291
+ glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
292
+ glBlendFuncSeparate(
293
+ GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_ONE, GL_ONE);
294
+ break;
295
+
296
+ case BLEND_MULTIPLY:
297
+ glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
298
+ glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ONE, GL_ONE);
299
+ break;
300
+
301
+ case BLEND_SCREEN:
302
+ glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
303
+ glBlendFuncSeparate(GL_ONE_MINUS_DST_COLOR, GL_ONE, GL_ONE, GL_ONE);
304
+ break;
305
+
306
+ case BLEND_REPLACE:
307
+ glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
308
+ glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO);
309
+ break;
310
+
311
+ default:
312
+ argument_error(__FILE__, __LINE__, "unknown blend mode");
313
+ break;
314
+ }
315
+ OpenGL_check_error(__FILE__, __LINE__);
202
316
  }
203
- else
204
- glDisable(GL_SCISSOR_TEST);
205
317
 
206
- OpenGL_check_error(__FILE__, __LINE__);
207
- }
318
+ void apply_clipping ()
319
+ {
320
+ const Bounds& clip = state.clip;
321
+ if (clip)
322
+ {
323
+ coord y = frame_buffer ? clip.y : viewport.h - (clip.y + clip.h);
324
+ glEnable(GL_SCISSOR_TEST);
325
+ glScissor(
326
+ pixel_density * clip.x,
327
+ pixel_density * y,
328
+ pixel_density * clip.width,
329
+ pixel_density * clip.height);
330
+ }
331
+ else
332
+ glDisable(GL_SCISSOR_TEST);
208
333
 
209
- static const TextureInfo*
210
- setup_texinfo (
211
- PainterData* self, const TextureInfo* texinfo,
212
- std::unique_ptr<TextureInfo>& ptr)
213
- {
214
- if (texinfo) return texinfo;
334
+ OpenGL_check_error(__FILE__, __LINE__);
335
+ }
215
336
 
216
- const Texture* tex =
217
- self->state.texture ? &Image_get_texture(self->state.texture) : NULL;
218
- if (!tex) return NULL;
337
+ };// PainterData
219
338
 
220
- ptr.reset(new TextureInfo(*tex, 0, 0, tex->width(), tex->height()));
221
- return ptr.get();
222
- }
223
339
 
224
- static const Shader*
225
- setup_shader (
226
- PainterData* self, const Shader* shader, bool for_texture)
340
+ static PainterData*
341
+ get_data (Painter* painter)
227
342
  {
228
- if (self->state.shader) return &self->state.shader;
229
- if (shader) return shader;
230
- return for_texture
231
- ? &Shader_get_default_shader_for_texture(self->state.texcoord_wrap)
232
- : &Shader_get_default_shader_for_shape();
343
+ return (PainterData*) painter->self.get();
233
344
  }
234
345
 
235
346
  static void
@@ -245,34 +356,11 @@ namespace Rays
245
356
  }
246
357
 
247
358
  static void
248
- apply_attribute (
249
- const ShaderProgram& program, const char* name,
250
- std::function<void(GLint)> apply_fun)
251
- {
252
- GLint loc = glGetAttribLocation(program.id(), name);
253
- if (loc < 0) return;
254
-
255
- apply_fun(loc);
256
- OpenGL_check_error(__FILE__, __LINE__);
257
- }
258
-
259
- static void
260
- apply_builtin_uniforms (
359
+ apply_uniforms (
261
360
  const ShaderProgram& program, const ShaderBuiltinVariableNames& names,
262
- const Matrix& position_matrix, const State& state,
263
- const TextureInfo* texinfo)
361
+ const Matrix& position_matrix, const Matrix& texcoord_matrix,
362
+ const Texture* texture)
264
363
  {
265
- const Texture* texture = texinfo ? &texinfo->texture : NULL;
266
-
267
- Matrix texcoord_matrix(1);
268
- if (texture && *texture)
269
- {
270
- bool normal = state.texcoord_mode == TEXCOORD_NORMAL;
271
- texcoord_matrix.scale(
272
- (normal ? texture->width() : 1.0) / texture->reserved_width(),
273
- (normal ? texture->height() : 1.0) / texture->reserved_height());
274
- }
275
-
276
364
  for (const auto& name : names.uniform_position_matrix_names)
277
365
  {
278
366
  apply_uniform(program, name, [&](GLint loc) {
@@ -286,43 +374,28 @@ namespace Rays
286
374
  });
287
375
  }
288
376
 
289
- if (!texinfo || !texture || !*texture) return;
290
-
291
- coord tw = texture->reserved_width();
292
- coord th = texture->reserved_height();
293
- Point min(texinfo->min.x / tw, texinfo->min.y / th);
294
- Point max(texinfo->max.x / tw, texinfo->max.y / th);
295
- Point offset( 1 / tw, 1 / th);
296
-
297
- for (const auto& name : names.uniform_texcoord_min_names)
298
- {
299
- apply_uniform(program, name, [&](GLint loc) {
300
- glUniform3fv(loc, 1, min.array);
301
- });
302
- }
303
- for (const auto& name : names.uniform_texcoord_max_names)
304
- {
305
- apply_uniform(program, name, [&](GLint loc) {
306
- glUniform3fv(loc, 1, max.array);
307
- });
308
- }
309
- for (const auto& name : names.uniform_texcoord_offset_names)
310
- {
311
- apply_uniform(program, name, [&](GLint loc) {
312
- glUniform3fv(loc, 1, offset.array);
313
- });
314
- }
315
- for (const auto& name : names.uniform_texture_names)
377
+ if (texture && *texture)
316
378
  {
317
- apply_uniform(program, name, [&](GLint loc) {
318
- glActiveTexture(GL_TEXTURE0);
319
- OpenGL_check_error(__FILE__, __LINE__);
379
+ Point pixel_size(
380
+ 1 / texture->reserved_width(),
381
+ 1 / texture->reserved_height());
382
+ for (const auto& name : names.uniform_texcoord_pixel_names)
383
+ {
384
+ apply_uniform(
385
+ program, name, [&](GLint loc) {glUniform3fv(loc, 1, pixel_size.array);});
386
+ }
387
+ for (const auto& name : names.uniform_texture_names)
388
+ {
389
+ apply_uniform(program, name, [&](GLint loc) {
390
+ glActiveTexture(GL_TEXTURE0);
391
+ OpenGL_check_error(__FILE__, __LINE__);
320
392
 
321
- glBindTexture(GL_TEXTURE_2D, Texture_get_id(*texture));
322
- OpenGL_check_error(__FILE__, __LINE__);
393
+ glBindTexture(GL_TEXTURE_2D, Texture_get_id(*texture));
394
+ OpenGL_check_error(__FILE__, __LINE__);
323
395
 
324
- glUniform1i(loc, 0);
325
- });
396
+ glUniform1i(loc, 0);
397
+ });
398
+ }
326
399
  }
327
400
  }
328
401
 
@@ -336,6 +409,18 @@ namespace Rays
336
409
  return GL_FLOAT;
337
410
  }
338
411
 
412
+ static void
413
+ apply_attribute (
414
+ const ShaderProgram& program, const char* name,
415
+ std::function<void(GLint)> apply_fun)
416
+ {
417
+ GLint loc = glGetAttribLocation(program.id(), name);
418
+ if (loc < 0) return;
419
+
420
+ apply_fun(loc);
421
+ OpenGL_check_error(__FILE__, __LINE__);
422
+ }
423
+
339
424
  template <typename CoordN>
340
425
  static void
341
426
  apply_attribute (
@@ -355,7 +440,8 @@ namespace Rays
355
440
  }
356
441
  #endif
357
442
 
358
- apply_attribute(program, name, [&](GLint loc) {
443
+ apply_attribute(program, name, [&](GLint loc)
444
+ {
359
445
  glEnableVertexAttribArray(loc);
360
446
  OpenGL_check_error(
361
447
  __FILE__, __LINE__, "loc: %d %s\n", loc, name.c_str());
@@ -371,12 +457,16 @@ namespace Rays
371
457
  OpenGL_check_error(__FILE__, __LINE__);
372
458
  }
373
459
 
460
+ template <typename CoordN>
374
461
  static void
375
462
  apply_attributes (
376
463
  PainterData* self,
377
464
  const ShaderProgram& program, const ShaderBuiltinVariableNames& names,
378
- const Coord3* points, size_t npoints, const Coord3* texcoords,
379
- const Color* color, const Color* colors)
465
+ const CoordN* points, size_t npoints,
466
+ const Color* color, const Color* colors,
467
+ const CoordN* texcoords,
468
+ const Coord3* texcoord_min, const Coord3* texcoord_max,
469
+ const Coord3* texcoord_mins, const Coord3* texcoord_maxes)
380
470
  {
381
471
  assert(npoints > 0);
382
472
  assert(!!color != !!colors);
@@ -385,10 +475,6 @@ namespace Rays
385
475
  self, program, names.attribute_position_names,
386
476
  points, npoints);
387
477
 
388
- apply_attribute(
389
- self, program, names.attribute_texcoord_names,
390
- texcoords ? texcoords : points, npoints);
391
-
392
478
  if (colors)
393
479
  {
394
480
  apply_attribute(
@@ -407,18 +493,51 @@ namespace Rays
407
493
  #else
408
494
  for (const auto& name : names.attribute_color_names)
409
495
  {
410
- apply_attribute(program, name, [&](GLint loc) {
411
- glVertexAttrib4fv(loc, color->array);
412
- });
496
+ apply_attribute(
497
+ program, name, [&](GLint loc) {glVertexAttrib4fv(loc, color->array);});
413
498
  }
414
499
  #endif
415
500
  }
501
+
502
+ apply_attribute(
503
+ self, program, names.attribute_texcoord_names,
504
+ texcoords ? texcoords : points, npoints);
505
+
506
+ if (texcoord_mins)
507
+ {
508
+ apply_attribute(
509
+ self, program, names.attribute_texcoord_min_names,
510
+ texcoord_mins, npoints);
511
+ }
512
+ else if (texcoord_min)
513
+ {
514
+ for (const auto& name : names.attribute_texcoord_min_names)
515
+ {
516
+ apply_attribute(
517
+ program, name, [&](GLint loc) {glVertexAttrib3fv(loc, texcoord_min->array);});
518
+ }
519
+ }
520
+
521
+ if (texcoord_maxes)
522
+ {
523
+ apply_attribute(
524
+ self, program, names.attribute_texcoord_max_names,
525
+ texcoord_maxes, npoints);
526
+ }
527
+ else if (texcoord_max)
528
+ {
529
+ for (const auto& name : names.attribute_texcoord_max_names)
530
+ {
531
+ apply_attribute(
532
+ program, name, [&](GLint loc) {glVertexAttrib3fv(loc, texcoord_max->array);});
533
+ }
534
+ }
416
535
  }
417
536
 
418
537
  static void
419
538
  draw_indices (
420
- PainterData* self,
421
- GLenum mode, const uint* indices, size_t nindices, size_t npoints)
539
+ PainterData* self, PrimitiveMode mode,
540
+ const uint* indices, size_t nindices, size_t npoints)
422
541
  {
423
542
  if (!indices || nindices <= 0)
424
543
  {
@@ -428,13 +547,13 @@ namespace Rays
428
547
  }
429
548
 
430
549
  #ifdef IOS
431
- glDrawElements(mode, (GLsizei) nindices, GL_UNSIGNED_INT, indices);
550
+ glDrawElements((GLenum) mode, (GLsizei) nindices, GL_UNSIGNED_INT, indices);
432
551
  OpenGL_check_error(__FILE__, __LINE__);
433
552
  #else
434
553
  self->create_and_bind_buffer(
435
554
  GL_ELEMENT_ARRAY_BUFFER, indices, sizeof(uint) * nindices);
436
555
 
437
- glDrawElements(mode, (GLsizei) nindices, GL_UNSIGNED_INT, 0);
556
+ glDrawElements((GLenum) mode, (GLsizei) nindices, GL_UNSIGNED_INT, 0);
438
557
  OpenGL_check_error(__FILE__, __LINE__);
439
558
 
440
559
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@@ -442,6 +561,266 @@ namespace Rays
442
561
  #endif
443
562
  }
444
563
 
564
+ static void
565
+ setup_texcoord_variables (
566
+ Matrix* matrix, Point* min, Point* max,
567
+ const PainterState& state, const TextureInfo& texinfo)
568
+ {
569
+ if (!texinfo.texture) return;
570
+
571
+ coord tw = texinfo.texture.reserved_width();
572
+ coord th = texinfo.texture.reserved_height();
573
+
574
+ bool normal = state.texcoord_mode == TEXCOORD_NORMAL;
575
+ matrix->scale(
576
+ (normal ? texinfo.texture.width() : 1.0) / tw,
577
+ (normal ? texinfo.texture.height() : 1.0) / th);
578
+
579
+ min->reset(texinfo.min.x / tw, texinfo.min.y / th);
580
+ max->reset(texinfo.max.x / tw, texinfo.max.y / th);
581
+ }
582
+
583
+ static void
584
+ draw (
585
+ PainterData* self, PrimitiveMode mode,
586
+ const Color* color,
587
+ const Coord3* points, size_t npoints,
588
+ const uint* indices, size_t nindices,
589
+ const Color* colors,
590
+ const Coord3* texcoords, const TextureInfo* texinfo,
591
+ const Shader& shader, const Matrix& position_matrix)
592
+ {
593
+ const ShaderProgram* program = Shader_get_program(shader);
594
+ if (!program || !*program) return;
595
+
596
+ ShaderProgram_activate(*program);
597
+
598
+ Matrix texcoord_matrix(1);
599
+ Point texcoord_min(0, 0), texcoord_max(1, 1);
600
+ if (texinfo)
601
+ {
602
+ setup_texcoord_variables(
603
+ &texcoord_matrix, &texcoord_min, &texcoord_max, self->state, *texinfo);
604
+ }
605
+
606
+ const auto& names = Shader_get_builtin_variable_names(shader);
607
+ apply_uniforms(
608
+ *program, names, position_matrix, texcoord_matrix,
609
+ texinfo ? &texinfo->texture : NULL);
610
+ apply_attributes(
611
+ self, *program, names, points, npoints, color, colors,
612
+ texcoords, &texcoord_min, &texcoord_max, NULL, NULL);
613
+ draw_indices(self, mode, indices, nindices, npoints);
614
+ self->cleanup();
615
+
616
+ ShaderProgram_deactivate();
617
+ }
618
+
619
+ static void
620
+ draw_batch (PainterData* self)
621
+ {
622
+ Batcher& batcher = self->batcher;
623
+ if (batcher.points.empty()) return;
624
+
625
+ const ShaderProgram* program = Shader_get_program(batcher.shader);
626
+ if (!program || !*program)
627
+ return batcher.clear_buffers();
628
+
629
+ ShaderProgram_activate(*program);
630
+
631
+ const auto& names = Shader_get_builtin_variable_names(batcher.shader);
632
+ Matrix identity(1);
633
+ apply_uniforms(
634
+ *program, names, identity, identity, batcher.texture ? &batcher.texture : NULL);
635
+ apply_attributes(
636
+ self, *program, names, &batcher.points[0], batcher.points.size(),
637
+ NULL, &batcher.colors[0],
638
+ &batcher.texcoords[0],
639
+ NULL, NULL, &batcher.texcoord_mins[0], &batcher.texcoord_maxes[0]);
640
+ draw_indices(
641
+ self, MODE_TRIANGLES,
642
+ &batcher.indices[0], batcher.indices.size(), batcher.points.size());
643
+ self->cleanup();
644
+
645
+ ShaderProgram_deactivate();
646
+ batcher.clear_buffers();
647
+ }
648
+
649
+ static inline GLuint
650
+ get_shader_program_id (const Shader& shader)
651
+ {
652
+ const ShaderProgram* p = Shader_get_program(shader);
653
+ return p ? p->id() : 0;
654
+ }
655
+
656
+ static void
657
+ ensure_state_and_flush_batch (
658
+ Painter* painter, const Shader& shader, const Texture& texture)
659
+ {
660
+ PainterData* self = get_data(painter);
661
+ Batcher& b = self->batcher;
662
+ const PainterState& s = self->state;
663
+ GLuint shader_id = get_shader_program_id(shader);
664
+ GLuint texture_id = Texture_get_id(texture);
665
+
666
+ bool state_changed = Xot::check_and_remove_flag(
667
+ &self->flags, Painter::Data::UNBATCHABLE_STATE_CHANGED);
668
+ if (
669
+ !state_changed &&
670
+ b.cached_shader_id == shader_id &&
671
+ b.cached_texture_id == texture_id)
672
+ {
673
+ return;
674
+ }
675
+
676
+ bool blend_changed = b.blend_mode != s.blend_mode;
677
+ bool clip_changed = b.clip != s.clip;
678
+ if (
679
+ b.count > 0 &&
680
+ (
681
+ blend_changed ||
682
+ clip_changed ||
683
+ b.cached_shader_id != shader_id ||
684
+ b.cached_texture_id != texture_id ||
685
+ b.texcoord_mode != s.texcoord_mode ||
686
+ b.texcoord_wrap != s.texcoord_wrap
687
+ ))
688
+ {
689
+ Painter_flush(painter);
690
+ }
691
+
692
+ if (blend_changed) self->apply_blend_mode();
693
+ if (clip_changed) self->apply_clipping();
694
+
695
+ b.cached_shader_id = shader_id;
696
+ b.cached_texture_id = texture_id;
697
+ b.blend_mode = s.blend_mode;
698
+ b.texcoord_mode = s.texcoord_mode;
699
+ b.texcoord_wrap = s.texcoord_wrap;
700
+ b.clip = s.clip;
701
+ b.shader = shader;
702
+ b.texture = texture;
703
+ }
704
+
705
+ static inline Vector4
706
+ apply_matrix (const Matrix& matrix, const Coord3& point)
707
+ {
708
+ return to_rays<Vector4>(to_glm(matrix) * Vec4(point.x, point.y, point.z, 1));
709
+ }
710
+
711
+ static void
712
+ batch (
713
+ Painter* painter, PrimitiveMode mode, const Color* color,
714
+ const Coord3* points, size_t npoints,
715
+ const uint* indices, size_t nindices,
716
+ const Color* colors,
717
+ const Coord3* texcoords, const TextureInfo* texinfo,
718
+ const Shader& shader)
719
+ {
720
+ PainterData* self = get_data(painter);
721
+ Batcher& batcher = self->batcher;
722
+
723
+ Texture texture = texinfo ? texinfo->texture : INVALID_TEXTURE;
724
+ ensure_state_and_flush_batch(painter, shader, texture);
725
+
726
+ if (++batcher.count <= 5)
727
+ {
728
+ return draw(
729
+ self, mode, color, points, npoints, indices, nindices, colors,
730
+ texcoords, texinfo, shader, self->position_matrix);
731
+ }
732
+
733
+ size_t points0 = batcher.points.size();
734
+
735
+ for (size_t i = 0; i < npoints; ++i)
736
+ batcher.points.push_back(apply_matrix(self->position_matrix, points[i]));
737
+
738
+ if (indices && nindices > 0)
739
+ {
740
+ for (size_t i = 0; i < nindices; ++i)
741
+ batcher.indices.push_back((uint) (points0 + indices[i]));
742
+ }
743
+ else
744
+ {
745
+ for (size_t i = 0; i < npoints; ++i)
746
+ batcher.indices.push_back((uint) (points0 + i));
747
+ }
748
+
749
+ if (colors)
750
+ batcher.colors.insert(batcher.colors.end(), colors, colors + npoints);
751
+ else if (color)
752
+ batcher.colors.insert(batcher.colors.end(), npoints, *color);
753
+
754
+ if (texture)
755
+ {
756
+ Matrix matrix(1);
757
+ Point min(0, 0), max(1, 1);
758
+ setup_texcoord_variables(&matrix, &min, &max, self->state, *texinfo);
759
+
760
+ const Coord3* src = texcoords ? texcoords : points;
761
+ for (size_t i = 0; i < npoints; ++i)
762
+ batcher.texcoords.push_back(apply_matrix(matrix, src[i]));
763
+
764
+ batcher.texcoord_mins .insert(batcher.texcoord_mins.end(), npoints, min);
765
+ batcher.texcoord_maxes.insert(batcher.texcoord_maxes.end(), npoints, max);
766
+ }
767
+ else
768
+ {
769
+ const Coord3* src = texcoords ? texcoords : points;
770
+ batcher.texcoords .insert(batcher.texcoords.end(), src, src + npoints);
771
+ batcher.texcoord_mins .insert(batcher.texcoord_mins.end(), npoints, Point(0, 0));
772
+ batcher.texcoord_maxes.insert(batcher.texcoord_maxes.end(), npoints, Point(1, 1));
773
+ }
774
+ }
775
+
776
+ void
777
+ Painter_flush (Painter* painter)
778
+ {
779
+ draw_batch(get_data(painter));
780
+ }
781
+
782
+ static const TextureInfo*
783
+ setup_texinfo (
784
+ PainterData* self, const TextureInfo* texinfo,
785
+ std::unique_ptr<TextureInfo>* ptr)
786
+ {
787
+ assert(ptr);
788
+
789
+ if (texinfo) return texinfo;
790
+
791
+ const Texture* tex =
792
+ self->state.texture ? &Image_get_texture(self->state.texture) : NULL;
793
+ if (!tex) return NULL;
794
+
795
+ ptr->reset(new TextureInfo(*tex, 0, 0, tex->width(), tex->height()));
796
+ return ptr->get();
797
+ }
798
+
799
+ static const Shader*
800
+ setup_shader (PainterData* self, const Shader* shader, bool for_texture)
801
+ {
802
+ if (self->state.shader) return &self->state.shader;
803
+ if (shader) return shader;
804
+ return for_texture
805
+ ? &Shader_get_default_shader_for_texture(self->state.texcoord_wrap)
806
+ : &Shader_get_default_shader_for_shape();
807
+ }
808
+
809
+ static bool
810
+ setup_triangle_fan_indices (auto* indices, size_t npoints)
811
+ {
812
+ if (npoints < 3) return false;
813
+
814
+ indices->reserve((npoints - 2) * 3);
815
+ for (size_t i = 1; i + 1 < npoints; ++i)
816
+ {
817
+ indices->push_back(0);
818
+ indices->push_back((uint) i);
819
+ indices->push_back((uint) (i + 1));
820
+ }
821
+ return true;
822
+ }
823
+
445
824
  void
446
825
  Painter_draw (
447
826
  Painter* painter, PrimitiveMode mode, const Color* color,
@@ -459,27 +838,41 @@ namespace Rays
459
838
 
460
839
  PainterData* self = get_data(painter);
461
840
 
462
- if (!self->painting)
841
+ if (!self->is_painting())
463
842
  invalid_state_error(__FILE__, __LINE__, "'painting' should be true.");
464
843
 
465
844
  std::unique_ptr<TextureInfo> ptexinfo;
466
- texinfo = setup_texinfo(self, texinfo, ptexinfo);
845
+ texinfo = setup_texinfo(self, texinfo, &ptexinfo);
467
846
  shader = setup_shader(self, shader, texinfo);
468
847
 
469
- const ShaderProgram* program = Shader_get_program(*shader);
470
- if (!program || !*program) return;
471
-
472
- ShaderProgram_activate(*program);
473
-
474
- const auto& names = Shader_get_builtin_variable_names(*shader);
475
- apply_builtin_uniforms(
476
- *program, names, self->position_matrix, self->state, texinfo);
477
- apply_attributes(
478
- self, *program, names, points, npoints, texcoords, color, colors);
479
- draw_indices(self, (GLenum) mode, indices, nindices, npoints);
480
- self->cleanup();
481
-
482
- ShaderProgram_deactivate();
848
+ bool batchable =
849
+ painter->has_flag(Painter::FLAG_BATCHING) &&
850
+ !Painter::debug() &&
851
+ !self->state.shader;
852
+ if (batchable && mode == MODE_TRIANGLES)
853
+ {
854
+ batch(
855
+ painter, mode, color, points, npoints, indices, nindices,
856
+ colors, texcoords, texinfo, *shader);
857
+ }
858
+ else if (batchable && mode == MODE_TRIANGLE_FAN && (!indices || nindices == 0))
859
+ {
860
+ auto& fan_indices = self->triangle_fan_indices_buffer;
861
+ fan_indices.clear();
862
+ if (!setup_triangle_fan_indices(&fan_indices, npoints))
863
+ return;
864
+ batch(
865
+ painter, MODE_TRIANGLES, color, points, npoints, &fan_indices[0], fan_indices.size(),
866
+ colors, texcoords, texinfo, *shader);
867
+ }
868
+ else
869
+ {
870
+ ensure_state_and_flush_batch(
871
+ painter, *shader, texinfo ? texinfo->texture : INVALID_TEXTURE);
872
+ draw(
873
+ self, mode, color, points, npoints, indices, nindices,
874
+ colors, texcoords, texinfo, *shader, self->position_matrix);
875
+ }
483
876
  }
484
877
 
485
878
  static inline void
@@ -524,6 +917,10 @@ namespace Rays
524
917
  {
525
918
  assert(painter && font && line && *line != '\0');
526
919
 
920
+ // exclude text rendering from batching for now;
921
+ // text_image is shared and gets overwritten by next text draw
922
+ Painter_flush(painter);
923
+
527
924
  Painter::Data* self = painter->self.get();
528
925
 
529
926
  float density = self->pixel_density;
@@ -560,7 +957,7 @@ namespace Rays
560
957
  painter, self->text_image,
561
958
  0, 0, str_w, str_h,
562
959
  x, y, str_w, str_h,
563
- false, true, &Shader_get_shader_for_text());
960
+ &Shader_get_shader_for_text());
564
961
 
565
962
  debug_draw_text_line(painter, font, x, y, str_w / density, str_h / density);
566
963
  }
@@ -577,7 +974,7 @@ namespace Rays
577
974
  if (!image)
578
975
  argument_error(__FILE__, __LINE__, "invalid image.");
579
976
 
580
- if (self->painting)
977
+ if (self->is_painting())
581
978
  invalid_state_error(__FILE__, __LINE__, "painting flag should be false.");
582
979
 
583
980
  FrameBuffer fb(Image_get_texture(image));
@@ -593,7 +990,7 @@ namespace Rays
593
990
  void
594
991
  Painter::unbind ()
595
992
  {
596
- if (self->painting)
993
+ if (self->is_painting())
597
994
  invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
598
995
 
599
996
  get_data(this)->frame_buffer = FrameBuffer();
@@ -604,20 +1001,11 @@ namespace Rays
604
1001
  {
605
1002
  PainterData* self = get_data(this);
606
1003
 
607
- if (self->painting)
1004
+ if (self->is_painting())
608
1005
  invalid_state_error(__FILE__, __LINE__, "painting flag should be false.");
609
1006
 
610
1007
  self->opengl_state.push();
611
1008
 
612
- //glEnable(GL_CULL_FACE);
613
-
614
- glEnable(GL_DEPTH_TEST);
615
- glDepthFunc(GL_LEQUAL);
616
- OpenGL_check_error(__FILE__, __LINE__);
617
-
618
- glEnable(GL_BLEND);
619
- set_blend_mode(self->state.blend_mode);
620
-
621
1009
  FrameBuffer& fb = self->frame_buffer;
622
1010
  if (fb)
623
1011
  {
@@ -649,9 +1037,20 @@ namespace Rays
649
1037
 
650
1038
  //self->position_matrix.translate(0.375f, 0.375f);
651
1039
 
652
- Painter_update_clip(this);
1040
+ //glEnable(GL_CULL_FACE);
1041
+
1042
+ glEnable(GL_DEPTH_TEST);
1043
+ glDepthFunc(GL_LEQUAL);
1044
+ OpenGL_check_error(__FILE__, __LINE__);
1045
+
1046
+ glEnable(GL_BLEND);
1047
+ self->apply_blend_mode();
1048
+ self->apply_clipping();
1049
+
1050
+ self->batcher.init(self->state);
653
1051
 
654
- self->painting = true;
1052
+ Xot::remove_flag(&self->flags, Painter::Data::UNBATCHABLE_STATE_CHANGED);
1053
+ Xot:: add_flag(&self->flags, Painter::Data::PAINTING);
655
1054
 
656
1055
  glClear(GL_DEPTH_BUFFER_BIT);
657
1056
  }
@@ -661,7 +1060,7 @@ namespace Rays
661
1060
  {
662
1061
  PainterData* self = get_data(this);
663
1062
 
664
- if (!self->painting)
1063
+ if (!self->is_painting())
665
1064
  invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
666
1065
 
667
1066
  if (!self->state_stack.empty())
@@ -670,7 +1069,9 @@ namespace Rays
670
1069
  if (!self->position_matrix_stack.empty())
671
1070
  invalid_state_error(__FILE__, __LINE__, "position matrix stack is not empty.");
672
1071
 
673
- self->painting = false;
1072
+ Painter_flush(this);
1073
+
1074
+ Xot::remove_flag(&self->flags, Painter::Data::PAINTING);
674
1075
  self->opengl_state.pop();
675
1076
  self->default_indices.clear();
676
1077
 
@@ -678,79 +1079,23 @@ namespace Rays
678
1079
 
679
1080
  if (self->frame_buffer)
680
1081
  FrameBuffer_unbind();
1082
+
1083
+ self->batcher.cleanup();
681
1084
  }
682
1085
 
683
1086
  void
684
1087
  Painter::clear ()
685
1088
  {
686
- if (!self->painting)
1089
+ if (!self->is_painting())
687
1090
  invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
688
1091
 
1092
+ Painter_flush(this);
1093
+
689
1094
  const Color& c = self->state.background;
690
1095
  glClearColor(c.red, c.green, c.blue, c.alpha);
691
1096
  glClear(GL_COLOR_BUFFER_BIT);
692
1097
  OpenGL_check_error(__FILE__, __LINE__);
693
1098
  }
694
1099
 
695
- void
696
- Painter::set_blend_mode (BlendMode mode)
697
- {
698
- self->state.blend_mode = mode;
699
- switch (mode)
700
- {
701
- case BLEND_NORMAL:
702
- glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
703
- glBlendFuncSeparate(
704
- GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
705
- break;
706
-
707
- case BLEND_ADD:
708
- glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
709
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE);
710
- break;
711
-
712
- case BLEND_SUBTRACT:
713
- glBlendEquationSeparate(GL_FUNC_REVERSE_SUBTRACT, GL_FUNC_ADD);
714
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE);
715
- break;
716
-
717
- case BLEND_LIGHTEST:
718
- glBlendEquationSeparate(GL_MAX, GL_FUNC_ADD);
719
- glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ONE);
720
- break;
721
-
722
- case BLEND_DARKEST:
723
- glBlendEquationSeparate(GL_MIN, GL_FUNC_ADD);
724
- glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ONE);
725
- break;
726
-
727
- case BLEND_EXCLUSION:
728
- glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
729
- glBlendFuncSeparate(
730
- GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_ONE, GL_ONE);
731
- break;
732
-
733
- case BLEND_MULTIPLY:
734
- glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
735
- glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ONE, GL_ONE);
736
- break;
737
-
738
- case BLEND_SCREEN:
739
- glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
740
- glBlendFuncSeparate(GL_ONE_MINUS_DST_COLOR, GL_ONE, GL_ONE, GL_ONE);
741
- break;
742
-
743
- case BLEND_REPLACE:
744
- glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
745
- glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO);
746
- break;
747
-
748
- default:
749
- argument_error(__FILE__, __LINE__, "unknown blend mode");
750
- break;
751
- }
752
- OpenGL_check_error(__FILE__, __LINE__);
753
- }
754
-
755
1100
 
756
1101
  }// Rays