rays 0.3.11 → 0.3.12

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,14 @@ namespace Rays
23
24
  {
24
25
 
25
26
 
27
+ struct Vector4 : Coord4
28
+ {
29
+
30
+ Vector4 (const Coord3& p) {Coord4::operator=(p);}
31
+
32
+ };// Vector4
33
+
34
+
26
35
  struct OpenGLState
27
36
  {
28
37
 
@@ -128,6 +137,43 @@ namespace Rays
128
137
  };// DefaultIndices
129
138
 
130
139
 
140
+ struct Batcher
141
+ {
142
+
143
+ int count = 0;
144
+
145
+ Shader shader;
146
+
147
+ Texture texture;
148
+
149
+ std::vector<Vector4> points;
150
+
151
+ std::vector<uint> indices;
152
+
153
+ std::vector<Color> colors;
154
+
155
+ std::vector<Vector4> texcoords;
156
+
157
+ std::vector<Coord3> texcoord_mins;
158
+
159
+ std::vector<Coord3> texcoord_maxes;
160
+
161
+ void clear ()
162
+ {
163
+ count = 0;
164
+ shader = Shader();
165
+ texture = Texture();
166
+ points .clear();
167
+ indices .clear();
168
+ colors .clear();
169
+ texcoords .clear();
170
+ texcoord_mins .clear();
171
+ texcoord_maxes.clear();
172
+ }
173
+
174
+ };// Batcher
175
+
176
+
131
177
  struct PainterData : Painter::Data
132
178
  {
133
179
 
@@ -141,6 +187,10 @@ namespace Rays
141
187
 
142
188
  std::vector<GLuint> buffers;
143
189
 
190
+ std::vector<GLuint> triangle_fan_indices_buffer;
191
+
192
+ Batcher batcher;
193
+
144
194
  GLuint create_and_bind_buffer (GLenum target, const void* data, GLsizeiptr size)
145
195
  {
146
196
  GLuint id = 0;
@@ -206,32 +256,6 @@ namespace Rays
206
256
  OpenGL_check_error(__FILE__, __LINE__);
207
257
  }
208
258
 
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;
215
-
216
- const Texture* tex =
217
- self->state.texture ? &Image_get_texture(self->state.texture) : NULL;
218
- if (!tex) return NULL;
219
-
220
- ptr.reset(new TextureInfo(*tex, 0, 0, tex->width(), tex->height()));
221
- return ptr.get();
222
- }
223
-
224
- static const Shader*
225
- setup_shader (
226
- PainterData* self, const Shader* shader, bool for_texture)
227
- {
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();
233
- }
234
-
235
259
  static void
236
260
  apply_uniform (
237
261
  const ShaderProgram& program, const char* name,
@@ -245,34 +269,11 @@ namespace Rays
245
269
  }
246
270
 
247
271
  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 (
272
+ apply_uniforms (
261
273
  const ShaderProgram& program, const ShaderBuiltinVariableNames& names,
262
- const Matrix& position_matrix, const State& state,
263
- const TextureInfo* texinfo)
274
+ const Matrix& position_matrix, const Matrix& texcoord_matrix,
275
+ const Texture* texture)
264
276
  {
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
277
  for (const auto& name : names.uniform_position_matrix_names)
277
278
  {
278
279
  apply_uniform(program, name, [&](GLint loc) {
@@ -286,43 +287,28 @@ namespace Rays
286
287
  });
287
288
  }
288
289
 
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)
290
+ if (texture && *texture)
316
291
  {
317
- apply_uniform(program, name, [&](GLint loc) {
318
- glActiveTexture(GL_TEXTURE0);
319
- OpenGL_check_error(__FILE__, __LINE__);
292
+ Point pixel_size(
293
+ 1 / texture->reserved_width(),
294
+ 1 / texture->reserved_height());
295
+ for (const auto& name : names.uniform_texcoord_pixel_names)
296
+ {
297
+ apply_uniform(
298
+ program, name, [&](GLint loc) {glUniform3fv(loc, 1, pixel_size.array);});
299
+ }
300
+ for (const auto& name : names.uniform_texture_names)
301
+ {
302
+ apply_uniform(program, name, [&](GLint loc) {
303
+ glActiveTexture(GL_TEXTURE0);
304
+ OpenGL_check_error(__FILE__, __LINE__);
320
305
 
321
- glBindTexture(GL_TEXTURE_2D, Texture_get_id(*texture));
322
- OpenGL_check_error(__FILE__, __LINE__);
306
+ glBindTexture(GL_TEXTURE_2D, Texture_get_id(*texture));
307
+ OpenGL_check_error(__FILE__, __LINE__);
323
308
 
324
- glUniform1i(loc, 0);
325
- });
309
+ glUniform1i(loc, 0);
310
+ });
311
+ }
326
312
  }
327
313
  }
328
314
 
@@ -336,6 +322,18 @@ namespace Rays
336
322
  return GL_FLOAT;
337
323
  }
338
324
 
325
+ static void
326
+ apply_attribute (
327
+ const ShaderProgram& program, const char* name,
328
+ std::function<void(GLint)> apply_fun)
329
+ {
330
+ GLint loc = glGetAttribLocation(program.id(), name);
331
+ if (loc < 0) return;
332
+
333
+ apply_fun(loc);
334
+ OpenGL_check_error(__FILE__, __LINE__);
335
+ }
336
+
339
337
  template <typename CoordN>
340
338
  static void
341
339
  apply_attribute (
@@ -355,7 +353,8 @@ namespace Rays
355
353
  }
356
354
  #endif
357
355
 
358
- apply_attribute(program, name, [&](GLint loc) {
356
+ apply_attribute(program, name, [&](GLint loc)
357
+ {
359
358
  glEnableVertexAttribArray(loc);
360
359
  OpenGL_check_error(
361
360
  __FILE__, __LINE__, "loc: %d %s\n", loc, name.c_str());
@@ -371,12 +370,16 @@ namespace Rays
371
370
  OpenGL_check_error(__FILE__, __LINE__);
372
371
  }
373
372
 
373
+ template <typename CoordN>
374
374
  static void
375
375
  apply_attributes (
376
376
  PainterData* self,
377
377
  const ShaderProgram& program, const ShaderBuiltinVariableNames& names,
378
- const Coord3* points, size_t npoints, const Coord3* texcoords,
379
- const Color* color, const Color* colors)
378
+ const CoordN* points, size_t npoints,
379
+ const Color* color, const Color* colors,
380
+ const CoordN* texcoords,
381
+ const Coord3* texcoord_min, const Coord3* texcoord_max,
382
+ const Coord3* texcoord_mins, const Coord3* texcoord_maxes)
380
383
  {
381
384
  assert(npoints > 0);
382
385
  assert(!!color != !!colors);
@@ -385,10 +388,6 @@ namespace Rays
385
388
  self, program, names.attribute_position_names,
386
389
  points, npoints);
387
390
 
388
- apply_attribute(
389
- self, program, names.attribute_texcoord_names,
390
- texcoords ? texcoords : points, npoints);
391
-
392
391
  if (colors)
393
392
  {
394
393
  apply_attribute(
@@ -407,18 +406,51 @@ namespace Rays
407
406
  #else
408
407
  for (const auto& name : names.attribute_color_names)
409
408
  {
410
- apply_attribute(program, name, [&](GLint loc) {
411
- glVertexAttrib4fv(loc, color->array);
412
- });
409
+ apply_attribute(
410
+ program, name, [&](GLint loc) {glVertexAttrib4fv(loc, color->array);});
413
411
  }
414
412
  #endif
415
413
  }
414
+
415
+ apply_attribute(
416
+ self, program, names.attribute_texcoord_names,
417
+ texcoords ? texcoords : points, npoints);
418
+
419
+ if (texcoord_mins)
420
+ {
421
+ apply_attribute(
422
+ self, program, names.attribute_texcoord_min_names,
423
+ texcoord_mins, npoints);
424
+ }
425
+ else if (texcoord_min)
426
+ {
427
+ for (const auto& name : names.attribute_texcoord_min_names)
428
+ {
429
+ apply_attribute(
430
+ program, name, [&](GLint loc) {glVertexAttrib3fv(loc, texcoord_min->array);});
431
+ }
432
+ }
433
+
434
+ if (texcoord_maxes)
435
+ {
436
+ apply_attribute(
437
+ self, program, names.attribute_texcoord_max_names,
438
+ texcoord_maxes, npoints);
439
+ }
440
+ else if (texcoord_max)
441
+ {
442
+ for (const auto& name : names.attribute_texcoord_max_names)
443
+ {
444
+ apply_attribute(
445
+ program, name, [&](GLint loc) {glVertexAttrib3fv(loc, texcoord_max->array);});
446
+ }
447
+ }
416
448
  }
417
449
 
418
450
  static void
419
451
  draw_indices (
420
- PainterData* self,
421
- GLenum mode, const uint* indices, size_t nindices, size_t npoints)
452
+ PainterData* self, PrimitiveMode mode,
453
+ const uint* indices, size_t nindices, size_t npoints)
422
454
  {
423
455
  if (!indices || nindices <= 0)
424
456
  {
@@ -428,13 +460,13 @@ namespace Rays
428
460
  }
429
461
 
430
462
  #ifdef IOS
431
- glDrawElements(mode, (GLsizei) nindices, GL_UNSIGNED_INT, indices);
463
+ glDrawElements((GLenum) mode, (GLsizei) nindices, GL_UNSIGNED_INT, indices);
432
464
  OpenGL_check_error(__FILE__, __LINE__);
433
465
  #else
434
466
  self->create_and_bind_buffer(
435
467
  GL_ELEMENT_ARRAY_BUFFER, indices, sizeof(uint) * nindices);
436
468
 
437
- glDrawElements(mode, (GLsizei) nindices, GL_UNSIGNED_INT, 0);
469
+ glDrawElements((GLenum) mode, (GLsizei) nindices, GL_UNSIGNED_INT, 0);
438
470
  OpenGL_check_error(__FILE__, __LINE__);
439
471
 
440
472
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@@ -442,6 +474,218 @@ namespace Rays
442
474
  #endif
443
475
  }
444
476
 
477
+ static void
478
+ setup_texcoord_variables (
479
+ Matrix* matrix, Point* min, Point* max,
480
+ const State& state, const TextureInfo& texinfo)
481
+ {
482
+ if (!texinfo.texture) return;
483
+
484
+ coord tw = texinfo.texture.reserved_width();
485
+ coord th = texinfo.texture.reserved_height();
486
+
487
+ bool normal = state.texcoord_mode == TEXCOORD_NORMAL;
488
+ matrix->scale(
489
+ (normal ? texinfo.texture.width() : 1.0) / tw,
490
+ (normal ? texinfo.texture.height() : 1.0) / th);
491
+
492
+ min->reset(texinfo.min.x / tw, texinfo.min.y / th);
493
+ max->reset(texinfo.max.x / tw, texinfo.max.y / th);
494
+ }
495
+
496
+ static void
497
+ draw (
498
+ PainterData* self, PrimitiveMode mode,
499
+ const Color* color,
500
+ const Coord3* points, size_t npoints,
501
+ const uint* indices, size_t nindices,
502
+ const Color* colors,
503
+ const Coord3* texcoords, const TextureInfo* texinfo,
504
+ const Shader& shader, const Matrix& position_matrix)
505
+ {
506
+ const ShaderProgram* program = Shader_get_program(shader);
507
+ if (!program || !*program) return;
508
+
509
+ ShaderProgram_activate(*program);
510
+
511
+ Matrix texcoord_matrix(1);
512
+ Point texcoord_min(0, 0), texcoord_max(1, 1);
513
+ if (texinfo)
514
+ {
515
+ setup_texcoord_variables(
516
+ &texcoord_matrix, &texcoord_min, &texcoord_max, self->state, *texinfo);
517
+ }
518
+
519
+ const auto& names = Shader_get_builtin_variable_names(shader);
520
+ apply_uniforms(
521
+ *program, names, position_matrix, texcoord_matrix,
522
+ texinfo ? &texinfo->texture : NULL);
523
+ apply_attributes(
524
+ self, *program, names, points, npoints, color, colors,
525
+ texcoords, &texcoord_min, &texcoord_max, NULL, NULL);
526
+ draw_indices(self, mode, indices, nindices, npoints);
527
+ self->cleanup();
528
+
529
+ ShaderProgram_deactivate();
530
+ }
531
+
532
+ static void
533
+ draw_batch (PainterData* self)
534
+ {
535
+ Batcher& batcher = self->batcher;
536
+ if (batcher.points.empty()) return;
537
+
538
+ const ShaderProgram* program = Shader_get_program(batcher.shader);
539
+ if (!program || !*program)
540
+ return batcher.clear();
541
+
542
+ ShaderProgram_activate(*program);
543
+
544
+ const auto& names = Shader_get_builtin_variable_names(batcher.shader);
545
+ Matrix identity(1);
546
+ apply_uniforms(
547
+ *program, names, identity, identity, batcher.texture ? &batcher.texture : NULL);
548
+ apply_attributes(
549
+ self, *program, names, &batcher.points[0], batcher.points.size(),
550
+ NULL, &batcher.colors[0],
551
+ &batcher.texcoords[0],
552
+ NULL, NULL, &batcher.texcoord_mins[0], &batcher.texcoord_maxes[0]);
553
+ draw_indices(
554
+ self, MODE_TRIANGLES,
555
+ &batcher.indices[0], batcher.indices.size(), batcher.points.size());
556
+ self->cleanup();
557
+
558
+ ShaderProgram_deactivate();
559
+ batcher.clear();
560
+ }
561
+
562
+ static inline Vector4
563
+ apply_matrix (const Matrix& matrix, const Coord3& point)
564
+ {
565
+ return to_rays<Vector4>(to_glm(matrix) * Vec4(point.x, point.y, point.z, 1));
566
+ }
567
+
568
+ static void
569
+ batch (
570
+ Painter* painter, PrimitiveMode mode, const Color* color,
571
+ const Coord3* points, size_t npoints,
572
+ const uint* indices, size_t nindices,
573
+ const Color* colors,
574
+ const Coord3* texcoords, const TextureInfo* texinfo,
575
+ const Shader& shader)
576
+ {
577
+ PainterData* self = get_data(painter);
578
+ Batcher& batcher = self->batcher;
579
+
580
+ Texture texture = texinfo ? texinfo->texture : Texture();
581
+ if (
582
+ batcher.points.empty() ||
583
+ batcher.shader != shader ||
584
+ batcher.texture != texture)
585
+ {
586
+ Painter_flush(painter);
587
+ batcher.shader = shader;
588
+ batcher.texture = texture;
589
+ }
590
+
591
+ if (++batcher.count <= 5)
592
+ {
593
+ return draw(
594
+ self, mode, color, points, npoints, indices, nindices, colors,
595
+ texcoords, texinfo, shader, self->position_matrix);
596
+ }
597
+
598
+ size_t points0 = batcher.points.size();
599
+
600
+ for (size_t i = 0; i < npoints; ++i)
601
+ batcher.points.push_back(apply_matrix(self->position_matrix, points[i]));
602
+
603
+ if (indices && nindices > 0)
604
+ {
605
+ for (size_t i = 0; i < nindices; ++i)
606
+ batcher.indices.push_back((uint) (points0 + indices[i]));
607
+ }
608
+ else
609
+ {
610
+ for (size_t i = 0; i < npoints; ++i)
611
+ batcher.indices.push_back((uint) (points0 + i));
612
+ }
613
+
614
+ if (colors)
615
+ batcher.colors.insert(batcher.colors.end(), colors, colors + npoints);
616
+ else if (color)
617
+ batcher.colors.insert(batcher.colors.end(), npoints, *color);
618
+
619
+ if (texture)
620
+ {
621
+ Matrix matrix(1);
622
+ Point min(0, 0), max(1, 1);
623
+ setup_texcoord_variables(&matrix, &min, &max, self->state, *texinfo);
624
+
625
+ const Coord3* src = texcoords ? texcoords : points;
626
+ for (size_t i = 0; i < npoints; ++i)
627
+ batcher.texcoords.push_back(apply_matrix(matrix, src[i]));
628
+
629
+ batcher.texcoord_mins .insert(batcher.texcoord_mins.end(), npoints, min);
630
+ batcher.texcoord_maxes.insert(batcher.texcoord_maxes.end(), npoints, max);
631
+ }
632
+ else
633
+ {
634
+ const Coord3* src = texcoords ? texcoords : points;
635
+ batcher.texcoords .insert(batcher.texcoords.end(), src, src + npoints);
636
+ batcher.texcoord_mins .insert(batcher.texcoord_mins.end(), npoints, Point(0, 0));
637
+ batcher.texcoord_maxes.insert(batcher.texcoord_maxes.end(), npoints, Point(1, 1));
638
+ }
639
+ }
640
+
641
+ void
642
+ Painter_flush (Painter* painter)
643
+ {
644
+ draw_batch(get_data(painter));
645
+ }
646
+
647
+ static const TextureInfo*
648
+ setup_texinfo (
649
+ PainterData* self, const TextureInfo* texinfo,
650
+ std::unique_ptr<TextureInfo>* ptr)
651
+ {
652
+ assert(ptr);
653
+
654
+ if (texinfo) return texinfo;
655
+
656
+ const Texture* tex =
657
+ self->state.texture ? &Image_get_texture(self->state.texture) : NULL;
658
+ if (!tex) return NULL;
659
+
660
+ ptr->reset(new TextureInfo(*tex, 0, 0, tex->width(), tex->height()));
661
+ return ptr->get();
662
+ }
663
+
664
+ static const Shader*
665
+ setup_shader (PainterData* self, const Shader* shader, bool for_texture)
666
+ {
667
+ if (self->state.shader) return &self->state.shader;
668
+ if (shader) return shader;
669
+ return for_texture
670
+ ? &Shader_get_default_shader_for_texture(self->state.texcoord_wrap)
671
+ : &Shader_get_default_shader_for_shape();
672
+ }
673
+
674
+ static bool
675
+ setup_triangle_fan_indices (auto* indices, size_t npoints)
676
+ {
677
+ if (npoints < 3) return false;
678
+
679
+ indices->reserve((npoints - 2) * 3);
680
+ for (size_t i = 1; i + 1 < npoints; ++i)
681
+ {
682
+ indices->push_back(0);
683
+ indices->push_back((uint) i);
684
+ indices->push_back((uint) (i + 1));
685
+ }
686
+ return true;
687
+ }
688
+
445
689
  void
446
690
  Painter_draw (
447
691
  Painter* painter, PrimitiveMode mode, const Color* color,
@@ -459,27 +703,40 @@ namespace Rays
459
703
 
460
704
  PainterData* self = get_data(painter);
461
705
 
462
- if (!self->painting)
706
+ if (!self->is_painting())
463
707
  invalid_state_error(__FILE__, __LINE__, "'painting' should be true.");
464
708
 
465
709
  std::unique_ptr<TextureInfo> ptexinfo;
466
- texinfo = setup_texinfo(self, texinfo, ptexinfo);
710
+ texinfo = setup_texinfo(self, texinfo, &ptexinfo);
467
711
  shader = setup_shader(self, shader, texinfo);
468
712
 
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();
713
+ bool batchable =
714
+ painter->has_flag(Painter::FLAG_BATCHING) &&
715
+ !Painter::debug() &&
716
+ !self->state.shader;
717
+ if (batchable && mode == MODE_TRIANGLES)
718
+ {
719
+ batch(
720
+ painter, mode, color, points, npoints, indices, nindices,
721
+ colors, texcoords, texinfo, *shader);
722
+ }
723
+ else if (batchable && mode == MODE_TRIANGLE_FAN && (!indices || nindices == 0))
724
+ {
725
+ auto& fan_indices = self->triangle_fan_indices_buffer;
726
+ fan_indices.clear();
727
+ if (!setup_triangle_fan_indices(&fan_indices, npoints))
728
+ return;
729
+ batch(
730
+ painter, MODE_TRIANGLES, color, points, npoints, &fan_indices[0], fan_indices.size(),
731
+ colors, texcoords, texinfo, *shader);
732
+ }
733
+ else
734
+ {
735
+ Painter_flush(painter);
736
+ draw(
737
+ self, mode, color, points, npoints, indices, nindices,
738
+ colors, texcoords, texinfo, *shader, self->position_matrix);
739
+ }
483
740
  }
484
741
 
485
742
  static inline void
@@ -560,7 +817,7 @@ namespace Rays
560
817
  painter, self->text_image,
561
818
  0, 0, str_w, str_h,
562
819
  x, y, str_w, str_h,
563
- false, true, &Shader_get_shader_for_text());
820
+ &Shader_get_shader_for_text());
564
821
 
565
822
  debug_draw_text_line(painter, font, x, y, str_w / density, str_h / density);
566
823
  }
@@ -577,7 +834,7 @@ namespace Rays
577
834
  if (!image)
578
835
  argument_error(__FILE__, __LINE__, "invalid image.");
579
836
 
580
- if (self->painting)
837
+ if (self->is_painting())
581
838
  invalid_state_error(__FILE__, __LINE__, "painting flag should be false.");
582
839
 
583
840
  FrameBuffer fb(Image_get_texture(image));
@@ -593,7 +850,7 @@ namespace Rays
593
850
  void
594
851
  Painter::unbind ()
595
852
  {
596
- if (self->painting)
853
+ if (self->is_painting())
597
854
  invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
598
855
 
599
856
  get_data(this)->frame_buffer = FrameBuffer();
@@ -604,7 +861,7 @@ namespace Rays
604
861
  {
605
862
  PainterData* self = get_data(this);
606
863
 
607
- if (self->painting)
864
+ if (self->is_painting())
608
865
  invalid_state_error(__FILE__, __LINE__, "painting flag should be false.");
609
866
 
610
867
  self->opengl_state.push();
@@ -651,7 +908,7 @@ namespace Rays
651
908
 
652
909
  Painter_update_clip(this);
653
910
 
654
- self->painting = true;
911
+ Xot::add_flag(&self->flags, Painter::Data::PAINTING);
655
912
 
656
913
  glClear(GL_DEPTH_BUFFER_BIT);
657
914
  }
@@ -661,7 +918,7 @@ namespace Rays
661
918
  {
662
919
  PainterData* self = get_data(this);
663
920
 
664
- if (!self->painting)
921
+ if (!self->is_painting())
665
922
  invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
666
923
 
667
924
  if (!self->state_stack.empty())
@@ -670,7 +927,9 @@ namespace Rays
670
927
  if (!self->position_matrix_stack.empty())
671
928
  invalid_state_error(__FILE__, __LINE__, "position matrix stack is not empty.");
672
929
 
673
- self->painting = false;
930
+ Painter_flush(this);
931
+
932
+ Xot::remove_flag(&self->flags, Painter::Data::PAINTING);
674
933
  self->opengl_state.pop();
675
934
  self->default_indices.clear();
676
935
 
@@ -683,9 +942,11 @@ namespace Rays
683
942
  void
684
943
  Painter::clear ()
685
944
  {
686
- if (!self->painting)
945
+ if (!self->is_painting())
687
946
  invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
688
947
 
948
+ Painter_flush(this);
949
+
689
950
  const Color& c = self->state.background;
690
951
  glClearColor(c.red, c.green, c.blue, c.alpha);
691
952
  glClear(GL_COLOR_BUFFER_BIT);
@@ -695,6 +956,9 @@ namespace Rays
695
956
  void
696
957
  Painter::set_blend_mode (BlendMode mode)
697
958
  {
959
+ if (self->state.blend_mode != mode)
960
+ Painter_flush(this);
961
+
698
962
  self->state.blend_mode = mode;
699
963
  switch (mode)
700
964
  {
@@ -57,7 +57,7 @@ namespace Rays
57
57
 
58
58
  glRenderbufferStorage(
59
59
  GL_RENDERBUFFER,
60
- #ifdef IOS
60
+ #if defined(IOS) || defined(WASM)
61
61
  GL_DEPTH_COMPONENT16,
62
62
  #else
63
63
  GL_DEPTH_COMPONENT24,