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.
- checksums.yaml +4 -4
- data/.doc/ext/rays/image.cpp +10 -0
- data/.doc/ext/rays/painter.cpp +49 -1
- data/.doc/ext/rays/shader.cpp +8 -6
- data/.github/workflows/release-gem.yml +5 -16
- data/.github/workflows/utils.rb +88 -17
- data/ChangeLog.md +26 -0
- data/README.md +164 -5
- data/Rakefile +3 -3
- data/VERSION +1 -1
- data/ext/rays/extconf.rb +3 -4
- data/ext/rays/image.cpp +11 -0
- data/ext/rays/painter.cpp +53 -1
- data/ext/rays/shader.cpp +8 -6
- data/include/rays/coord.h +6 -6
- data/include/rays/defs.h +2 -0
- data/include/rays/image.h +11 -1
- data/include/rays/painter.h +19 -0
- data/include/rays/ruby.h +2 -2
- data/include/rays/shader.h +5 -3
- data/include/rays.h +2 -2
- data/lib/rays/extension.rb +8 -2
- data/lib/rays/image.rb +2 -1
- data/lib/rays/shader.rb +13 -4
- data/rays.gemspec +3 -4
- data/src/color_space.cpp +1 -1
- data/src/coord.h +10 -0
- data/src/font.cpp +1 -1
- data/src/image.cpp +85 -10
- data/src/opengl/painter.cpp +559 -214
- data/src/opengl/render_buffer.cpp +1 -1
- data/src/opengl/sdl/opengl.cpp +6 -0
- data/src/opengl/shader.cpp +68 -51
- data/src/opengl/shader.h +10 -6
- data/src/opengl/shader_program.cpp +21 -7
- data/src/opengl/shader_program.h +2 -1
- data/src/opengl/shader_source.cpp +2 -4
- data/src/opengl/texture.cpp +18 -6
- data/src/osx/bitmap.mm +1 -1
- data/src/painter.cpp +80 -26
- data/src/painter.h +26 -13
- data/src/sdl/font.cpp +358 -9
- data/src/sdl/rays.cpp +5 -0
- data/src/texture.h +6 -0
- data/test/test_painter.rb +36 -25
- data/test/test_painter_batch.rb +254 -0
- metadata +8 -6
data/src/opengl/painter.cpp
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
|
|
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
|
-
|
|
210
|
-
|
|
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
|
-
|
|
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
|
|
225
|
-
|
|
226
|
-
PainterData* self, const Shader* shader, bool for_texture)
|
|
340
|
+
static PainterData*
|
|
341
|
+
get_data (Painter* painter)
|
|
227
342
|
{
|
|
228
|
-
|
|
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
|
-
|
|
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
|
|
263
|
-
const
|
|
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 (
|
|
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
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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
|
-
|
|
322
|
-
|
|
393
|
+
glBindTexture(GL_TEXTURE_2D, Texture_get_id(*texture));
|
|
394
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
323
395
|
|
|
324
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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->
|
|
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
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
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
|
-
|
|
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->
|
|
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->
|
|
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->
|
|
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
|
-
|
|
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->
|
|
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->
|
|
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
|
-
|
|
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->
|
|
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
|