rays 0.3.10 → 0.3.11

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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.doc/ext/rays/polygon.cpp +1 -1
  3. data/.github/workflows/release-gem.yml +1 -1
  4. data/.github/workflows/test.yml +4 -4
  5. data/ChangeLog.md +7 -0
  6. data/Gemfile.lock +6 -5
  7. data/VERSION +1 -1
  8. data/ext/rays/polygon.cpp +1 -1
  9. data/rays.gemspec +2 -2
  10. data/src/bitmap.h +4 -0
  11. data/src/color_space.cpp +1 -41
  12. data/src/image.cpp +0 -1
  13. data/src/ios/bitmap.mm +5 -32
  14. data/src/ios/rays.mm +3 -3
  15. data/src/opengl/bitmap.cpp +41 -0
  16. data/src/opengl/color_space.cpp +51 -0
  17. data/src/{color_space.h → opengl/color_space.h} +2 -2
  18. data/src/{frame_buffer.cpp → opengl/frame_buffer.cpp} +1 -1
  19. data/src/{frame_buffer.h → opengl/frame_buffer.h} +2 -2
  20. data/src/{ios → opengl/ios}/opengl.mm +3 -3
  21. data/src/{opengl.h → opengl/opengl.h} +2 -6
  22. data/src/{osx → opengl/osx}/opengl.mm +3 -3
  23. data/src/opengl/painter.cpp +756 -0
  24. data/src/{render_buffer.h → opengl/render_buffer.h} +2 -2
  25. data/src/{sdl → opengl/sdl}/opengl.cpp +4 -3
  26. data/src/{shader.cpp → opengl/shader.cpp} +1 -2
  27. data/src/{shader.h → opengl/shader.h} +2 -2
  28. data/src/{shader_program.cpp → opengl/shader_program.cpp} +3 -3
  29. data/src/{shader_program.h → opengl/shader_program.h} +2 -2
  30. data/src/{shader_source.h → opengl/shader_source.h} +2 -2
  31. data/src/{texture.cpp → opengl/texture.cpp} +2 -3
  32. data/src/opengl/texture.h +21 -0
  33. data/src/{win32 → opengl/win32}/opengl.cpp +4 -3
  34. data/src/osx/bitmap.mm +5 -33
  35. data/src/osx/rays.mm +3 -3
  36. data/src/painter.cpp +21 -905
  37. data/src/painter.h +210 -11
  38. data/src/polygon.cpp +38 -13
  39. data/src/renderer.h +22 -0
  40. data/src/sdl/bitmap.cpp +5 -33
  41. data/src/sdl/rays.cpp +3 -3
  42. data/src/texture.h +0 -3
  43. data/src/win32/bitmap.cpp +6 -34
  44. data/src/win32/rays.cpp +3 -3
  45. metadata +29 -24
  46. /data/src/{opengl.cpp → opengl/opengl.cpp} +0 -0
  47. /data/src/{render_buffer.cpp → opengl/render_buffer.cpp} +0 -0
  48. /data/src/{shader_source.cpp → opengl/shader_source.cpp} +0 -0
@@ -0,0 +1,756 @@
1
+ #include "../painter.h"
2
+
3
+
4
+ #include <math.h>
5
+ #include <assert.h>
6
+ #include <memory>
7
+ #include <vector>
8
+ #include <algorithm>
9
+ #include <functional>
10
+ #include "rays/exception.h"
11
+ #include "../glm.h"
12
+ #include "../bitmap.h"
13
+ #include "../image.h"
14
+ #include "../font.h"
15
+ #include "opengl.h"
16
+ #include "texture.h"
17
+ #include "frame_buffer.h"
18
+ #include "shader.h"
19
+ #include "shader_program.h"
20
+
21
+
22
+ namespace Rays
23
+ {
24
+
25
+
26
+ struct OpenGLState
27
+ {
28
+
29
+ GLint viewport[4];
30
+
31
+ GLclampf color_clear[4];
32
+
33
+ GLboolean depth_test;
34
+ GLint depth_func;
35
+
36
+ GLboolean scissor_test;
37
+ GLint scissor_box[4];
38
+
39
+ GLboolean blend;
40
+ GLint blend_equation_rgb, blend_equation_alpha;
41
+ GLint blend_src_rgb, blend_src_alpha, blend_dst_rgb, blend_dst_alpha;
42
+
43
+ GLint framebuffer_binding;
44
+
45
+ void push ()
46
+ {
47
+ glGetIntegerv(GL_VIEWPORT, viewport);
48
+
49
+ glGetFloatv(GL_COLOR_CLEAR_VALUE, color_clear);
50
+
51
+ glGetBooleanv(GL_DEPTH_TEST, &depth_test);
52
+ glGetIntegerv(GL_DEPTH_FUNC, &depth_func);
53
+
54
+ glGetBooleanv(GL_SCISSOR_TEST, &scissor_test);
55
+ glGetIntegerv(GL_SCISSOR_BOX, scissor_box);
56
+
57
+ glGetBooleanv(GL_BLEND, &blend);
58
+ glGetIntegerv(GL_BLEND_EQUATION_RGB, &blend_equation_rgb);
59
+ glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &blend_equation_alpha);
60
+ glGetIntegerv(GL_BLEND_SRC_RGB, &blend_src_rgb);
61
+ glGetIntegerv(GL_BLEND_SRC_ALPHA, &blend_src_alpha);
62
+ glGetIntegerv(GL_BLEND_DST_RGB, &blend_dst_rgb);
63
+ glGetIntegerv(GL_BLEND_DST_ALPHA, &blend_dst_alpha);
64
+
65
+ glGetIntegerv(GL_FRAMEBUFFER_BINDING, &framebuffer_binding);
66
+ }
67
+
68
+ void pop ()
69
+ {
70
+ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
71
+
72
+ glClearColor(
73
+ color_clear[0], color_clear[1], color_clear[2], color_clear[3]);
74
+
75
+ enable(GL_DEPTH_TEST, depth_test);
76
+ glDepthFunc(depth_func);
77
+
78
+ enable(GL_SCISSOR_TEST, scissor_test);
79
+ glScissor(scissor_box[0], scissor_box[1], scissor_box[2], scissor_box[3]);
80
+
81
+ enable(GL_BLEND, blend);
82
+ glBlendEquationSeparate(blend_equation_rgb, blend_equation_alpha);
83
+ glBlendFuncSeparate(
84
+ blend_src_rgb, blend_dst_rgb, blend_src_alpha, blend_dst_alpha);
85
+
86
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_binding);
87
+ }
88
+
89
+ private:
90
+
91
+ void enable(GLenum type, GLboolean value)
92
+ {
93
+ if (value)
94
+ glEnable(type);
95
+ else
96
+ glDisable(type);
97
+ }
98
+
99
+ };// OpenGLState
100
+
101
+
102
+ class DefaultIndices
103
+ {
104
+
105
+ public:
106
+
107
+ void resize (size_t size)
108
+ {
109
+ indices.reserve(size);
110
+ while (indices.size() < size)
111
+ indices.emplace_back(indices.size());
112
+ }
113
+
114
+ void clear ()
115
+ {
116
+ decltype(indices)().swap(indices);
117
+ }
118
+
119
+ const uint* get () const
120
+ {
121
+ return &indices[0];
122
+ }
123
+
124
+ private:
125
+
126
+ std::vector<uint> indices;
127
+
128
+ };// DefaultIndices
129
+
130
+
131
+ struct PainterData : Painter::Data
132
+ {
133
+
134
+ FrameBuffer frame_buffer;
135
+
136
+ OpenGLState opengl_state;
137
+
138
+ DefaultIndices default_indices;
139
+
140
+ std::vector<GLint> locations;
141
+
142
+ std::vector<GLuint> buffers;
143
+
144
+ GLuint create_and_bind_buffer (GLenum target, const void* data, GLsizeiptr size)
145
+ {
146
+ GLuint id = 0;
147
+ glGenBuffers(1, &id);
148
+ OpenGL_check_error(__FILE__, __LINE__);
149
+
150
+ buffers.push_back(id);
151
+
152
+ glBindBuffer(target, id);
153
+ OpenGL_check_error(__FILE__, __LINE__);
154
+
155
+ glBufferData(target, size, data, GL_STREAM_DRAW);
156
+ OpenGL_check_error(__FILE__, __LINE__);
157
+
158
+ return id;
159
+ }
160
+
161
+ void cleanup ()
162
+ {
163
+ for (auto loc : locations)
164
+ {
165
+ glDisableVertexAttribArray(loc);
166
+ OpenGL_check_error(__FILE__, __LINE__);
167
+ }
168
+
169
+ if (!buffers.empty())
170
+ {
171
+ glDeleteBuffers((GLsizei) buffers.size(), &buffers[0]);
172
+ OpenGL_check_error(__FILE__, __LINE__);
173
+ }
174
+
175
+ locations.clear();
176
+ buffers.clear();
177
+ }
178
+
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)
194
+ {
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);
202
+ }
203
+ else
204
+ glDisable(GL_SCISSOR_TEST);
205
+
206
+ OpenGL_check_error(__FILE__, __LINE__);
207
+ }
208
+
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
+ static void
236
+ apply_uniform (
237
+ const ShaderProgram& program, const char* name,
238
+ std::function<void(GLint)> apply_fun)
239
+ {
240
+ GLint loc = glGetUniformLocation(program.id(), name);
241
+ if (loc < 0) return;
242
+
243
+ apply_fun(loc);
244
+ OpenGL_check_error(__FILE__, __LINE__);
245
+ }
246
+
247
+ 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 (
261
+ const ShaderProgram& program, const ShaderBuiltinVariableNames& names,
262
+ const Matrix& position_matrix, const State& state,
263
+ const TextureInfo* texinfo)
264
+ {
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
+ for (const auto& name : names.uniform_position_matrix_names)
277
+ {
278
+ apply_uniform(program, name, [&](GLint loc) {
279
+ glUniformMatrix4fv(loc, 1, GL_FALSE, position_matrix.array);
280
+ });
281
+ }
282
+ for (const auto& name : names.uniform_texcoord_matrix_names)
283
+ {
284
+ apply_uniform(program, name, [&](GLint loc) {
285
+ glUniformMatrix4fv(loc, 1, GL_FALSE, texcoord_matrix.array);
286
+ });
287
+ }
288
+
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)
316
+ {
317
+ apply_uniform(program, name, [&](GLint loc) {
318
+ glActiveTexture(GL_TEXTURE0);
319
+ OpenGL_check_error(__FILE__, __LINE__);
320
+
321
+ glBindTexture(GL_TEXTURE_2D, Texture_get_id(*texture));
322
+ OpenGL_check_error(__FILE__, __LINE__);
323
+
324
+ glUniform1i(loc, 0);
325
+ });
326
+ }
327
+ }
328
+
329
+ template <typename COORD>
330
+ static GLenum get_gl_type ();
331
+
332
+ template <>
333
+ GLenum
334
+ get_gl_type<float> ()
335
+ {
336
+ return GL_FLOAT;
337
+ }
338
+
339
+ template <typename CoordN>
340
+ static void
341
+ apply_attribute (
342
+ PainterData* self,
343
+ const ShaderProgram& program, const auto& names,
344
+ const CoordN* values, size_t nvalues)
345
+ {
346
+ GLuint buffer = 0;
347
+ for (const auto& name : names)
348
+ {
349
+ #ifndef IOS
350
+ if (buffer == 0)
351
+ {
352
+ buffer = self->create_and_bind_buffer(
353
+ GL_ARRAY_BUFFER, values, sizeof(CoordN) * nvalues);
354
+ values = 0;
355
+ }
356
+ #endif
357
+
358
+ apply_attribute(program, name, [&](GLint loc) {
359
+ glEnableVertexAttribArray(loc);
360
+ OpenGL_check_error(
361
+ __FILE__, __LINE__, "loc: %d %s\n", loc, name.c_str());
362
+
363
+ glVertexAttribPointer(
364
+ loc, CoordN::SIZE, get_gl_type<coord>(), GL_FALSE, 0, values);
365
+
366
+ self->locations.push_back(loc);
367
+ });
368
+ }
369
+
370
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
371
+ OpenGL_check_error(__FILE__, __LINE__);
372
+ }
373
+
374
+ static void
375
+ apply_attributes (
376
+ PainterData* self,
377
+ const ShaderProgram& program, const ShaderBuiltinVariableNames& names,
378
+ const Coord3* points, size_t npoints, const Coord3* texcoords,
379
+ const Color* color, const Color* colors)
380
+ {
381
+ assert(npoints > 0);
382
+ assert(!!color != !!colors);
383
+
384
+ apply_attribute(
385
+ self, program, names.attribute_position_names,
386
+ points, npoints);
387
+
388
+ apply_attribute(
389
+ self, program, names.attribute_texcoord_names,
390
+ texcoords ? texcoords : points, npoints);
391
+
392
+ if (colors)
393
+ {
394
+ apply_attribute(
395
+ self, program, names.attribute_color_names,
396
+ colors, npoints);
397
+ }
398
+ else if (color)
399
+ {
400
+ #if defined(GL_VERSION_2_1) && !defined(GL_VERSION_3_0)
401
+ // to fix that GL 2.1 with glVertexAttrib4fv() draws nothing
402
+ // with specific glsl 'attribute' name.
403
+ std::vector<Color> colors_(npoints, *color);
404
+ apply_attribute(
405
+ self, program, names.attribute_color_names,
406
+ (const Coord4*) &colors_[0], npoints);
407
+ #else
408
+ for (const auto& name : names.attribute_color_names)
409
+ {
410
+ apply_attribute(program, name, [&](GLint loc) {
411
+ glVertexAttrib4fv(loc, color->array);
412
+ });
413
+ }
414
+ #endif
415
+ }
416
+ }
417
+
418
+ static void
419
+ draw_indices (
420
+ PainterData* self,
421
+ GLenum mode, const uint* indices, size_t nindices, size_t npoints)
422
+ {
423
+ if (!indices || nindices <= 0)
424
+ {
425
+ self->default_indices.resize(npoints);
426
+ indices = self->default_indices.get();
427
+ nindices = npoints;
428
+ }
429
+
430
+ #ifdef IOS
431
+ glDrawElements(mode, (GLsizei) nindices, GL_UNSIGNED_INT, indices);
432
+ OpenGL_check_error(__FILE__, __LINE__);
433
+ #else
434
+ self->create_and_bind_buffer(
435
+ GL_ELEMENT_ARRAY_BUFFER, indices, sizeof(uint) * nindices);
436
+
437
+ glDrawElements(mode, (GLsizei) nindices, GL_UNSIGNED_INT, 0);
438
+ OpenGL_check_error(__FILE__, __LINE__);
439
+
440
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
441
+ OpenGL_check_error(__FILE__, __LINE__);
442
+ #endif
443
+ }
444
+
445
+ void
446
+ Painter_draw (
447
+ Painter* painter, PrimitiveMode mode, const Color* color,
448
+ const Coord3* points, size_t npoints,
449
+ const uint* indices, size_t nindices,
450
+ const Color* colors,
451
+ const Coord3* texcoords,
452
+ const TextureInfo* texinfo,
453
+ const Shader* shader)
454
+ {
455
+ if (!points)
456
+ argument_error(__FILE__, __LINE__);
457
+ if (npoints <= 0)
458
+ argument_error(__FILE__, __LINE__);
459
+
460
+ PainterData* self = get_data(painter);
461
+
462
+ if (!self->painting)
463
+ invalid_state_error(__FILE__, __LINE__, "'painting' should be true.");
464
+
465
+ std::unique_ptr<TextureInfo> ptexinfo;
466
+ texinfo = setup_texinfo(self, texinfo, ptexinfo);
467
+ shader = setup_shader(self, shader, texinfo);
468
+
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();
483
+ }
484
+
485
+ static inline void
486
+ debug_draw_text_line (
487
+ Painter* painter, const Font& font,
488
+ coord x, coord y, coord str_width, coord str_height)
489
+ {
490
+ #if 0
491
+ painter->self->text_image.save("/tmp/font.png");
492
+
493
+ painter->push_state();
494
+ {
495
+ coord asc, desc, lead;
496
+ font.get_height(&asc, &desc, &lead);
497
+ //printf("%f %f %f %f \n", str_height, asc, desc, lead);
498
+
499
+ painter->set_stroke(0.5, 0.5, 1);
500
+ painter->no_fill();
501
+ painter->rect(x - 1, y - 1, str_width + 2, str_height + 2);
502
+
503
+ coord yy = y;
504
+ painter->set_stroke(1, 0.5, 0.5, 0.4);
505
+ painter->rect(x, yy, str_width, asc);//str_height);
506
+
507
+ yy += asc;
508
+ painter->set_stroke(1, 1, 0.5, 0.4);
509
+ painter->rect(x, yy, str_width, desc);
510
+
511
+ yy += desc;
512
+ painter->set_stroke(1, 0.5, 1, 0.4);
513
+ painter->rect(x, yy, str_width, lead);
514
+ }
515
+ painter->pop_state();
516
+ #endif
517
+ }
518
+
519
+ void
520
+ Painter_draw_text_line (
521
+ Painter* painter, const Font& font,
522
+ const char* line, coord x, coord y,
523
+ coord width, coord height)
524
+ {
525
+ assert(painter && font && line && *line != '\0');
526
+
527
+ Painter::Data* self = painter->self.get();
528
+
529
+ float density = self->pixel_density;
530
+ const RawFont& rawfont = Font_get_raw(font, density);
531
+ coord str_w = rawfont.get_width(line);
532
+ coord str_h = rawfont.get_height();
533
+ int tex_w = ceil(str_w);
534
+ int tex_h = ceil(str_h);
535
+ const Texture& texture = Image_get_texture(self->text_image);
536
+ if (
537
+ texture.width() < tex_w ||
538
+ texture.height() < tex_h ||
539
+ self->text_image.pixel_density() != density)
540
+ {
541
+ int bmp_w = std::max(texture.width(), tex_w);
542
+ int bmp_h = std::max(texture.height(), tex_h);
543
+ self->text_image = Image(Bitmap(bmp_w, bmp_h), density);
544
+ }
545
+
546
+ if (!self->text_image)
547
+ invalid_state_error(__FILE__, __LINE__);
548
+
549
+ assert(self->text_image.pixel_density() == density);
550
+
551
+ Bitmap_draw_string(
552
+ &self->text_image.bitmap(), rawfont, line, 0, 0, font.smooth());
553
+
554
+ str_w /= density;
555
+ str_h /= density;
556
+ if (width == 0) width = str_w;
557
+ if (height == 0) height = str_h;
558
+
559
+ Painter_draw_image(
560
+ painter, self->text_image,
561
+ 0, 0, str_w, str_h,
562
+ x, y, str_w, str_h,
563
+ false, true, &Shader_get_shader_for_text());
564
+
565
+ debug_draw_text_line(painter, font, x, y, str_w / density, str_h / density);
566
+ }
567
+
568
+
569
+ Painter::Painter ()
570
+ : self(new PainterData())
571
+ {
572
+ }
573
+
574
+ void
575
+ Painter::bind (const Image& image)
576
+ {
577
+ if (!image)
578
+ argument_error(__FILE__, __LINE__, "invalid image.");
579
+
580
+ if (self->painting)
581
+ invalid_state_error(__FILE__, __LINE__, "painting flag should be false.");
582
+
583
+ FrameBuffer fb(Image_get_texture(image));
584
+ if (!fb)
585
+ rays_error(__FILE__, __LINE__, "invalid frame buffer.");
586
+
587
+ unbind();
588
+
589
+ get_data(this)->frame_buffer = fb;
590
+ canvas(0, 0, image.width(), image.height(), image.pixel_density());
591
+ }
592
+
593
+ void
594
+ Painter::unbind ()
595
+ {
596
+ if (self->painting)
597
+ invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
598
+
599
+ get_data(this)->frame_buffer = FrameBuffer();
600
+ }
601
+
602
+ void
603
+ Painter::begin ()
604
+ {
605
+ PainterData* self = get_data(this);
606
+
607
+ if (self->painting)
608
+ invalid_state_error(__FILE__, __LINE__, "painting flag should be false.");
609
+
610
+ self->opengl_state.push();
611
+
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
+ FrameBuffer& fb = self->frame_buffer;
622
+ if (fb)
623
+ {
624
+ FrameBuffer_bind(fb.id());
625
+
626
+ Texture& tex = fb.texture();
627
+ if (tex) tex.set_modified();
628
+ }
629
+
630
+ const Bounds& vp = self->viewport;
631
+ float density = self->pixel_density;
632
+ glViewport(
633
+ (int) (vp.x * density), (int) (vp.y * density),
634
+ (int) (vp.width * density), (int) (vp.height * density));
635
+ OpenGL_check_error(__FILE__, __LINE__);
636
+
637
+ coord x1 = vp.x, x2 = vp.x + vp.width;
638
+ coord y1 = vp.y, y2 = vp.y + vp.height;
639
+ coord z1 = vp.z, z2 = vp.z + vp.depth;
640
+ if (z1 == 0 && z2 == 0) {z1 = -1000; z2 = 1000;}
641
+ if (!fb) std::swap(y1, y2);
642
+
643
+ self->position_matrix.reset(1);
644
+ self->position_matrix *= to_rays(glm::ortho(x1, x2, y1, y2));
645
+
646
+ // map z to 0.0-1.0
647
+ self->position_matrix.scale(1, 1, 1.0 / (z2 - z1));
648
+ self->position_matrix.translate(0, 0, -z2);
649
+
650
+ //self->position_matrix.translate(0.375f, 0.375f);
651
+
652
+ Painter_update_clip(this);
653
+
654
+ self->painting = true;
655
+
656
+ glClear(GL_DEPTH_BUFFER_BIT);
657
+ }
658
+
659
+ void
660
+ Painter::end ()
661
+ {
662
+ PainterData* self = get_data(this);
663
+
664
+ if (!self->painting)
665
+ invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
666
+
667
+ if (!self->state_stack.empty())
668
+ invalid_state_error(__FILE__, __LINE__, "state stack is not empty.");
669
+
670
+ if (!self->position_matrix_stack.empty())
671
+ invalid_state_error(__FILE__, __LINE__, "position matrix stack is not empty.");
672
+
673
+ self->painting = false;
674
+ self->opengl_state.pop();
675
+ self->default_indices.clear();
676
+
677
+ glFinish();
678
+
679
+ if (self->frame_buffer)
680
+ FrameBuffer_unbind();
681
+ }
682
+
683
+ void
684
+ Painter::clear ()
685
+ {
686
+ if (!self->painting)
687
+ invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
688
+
689
+ const Color& c = self->state.background;
690
+ glClearColor(c.red, c.green, c.blue, c.alpha);
691
+ glClear(GL_COLOR_BUFFER_BIT);
692
+ OpenGL_check_error(__FILE__, __LINE__);
693
+ }
694
+
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
+
756
+ }// Rays