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.
- 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 +3 -0
- data/.github/workflows/utils.rb +88 -17
- data/ChangeLog.md +17 -0
- 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 +388 -124
- 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 +79 -24
- data/src/painter.h +15 -2
- 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,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
|
-
|
|
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
|
|
263
|
-
const
|
|
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 (
|
|
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
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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
|
-
|
|
322
|
-
|
|
306
|
+
glBindTexture(GL_TEXTURE_2D, Texture_get_id(*texture));
|
|
307
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
323
308
|
|
|
324
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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->
|
|
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
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
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
|
-
|
|
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->
|
|
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->
|
|
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->
|
|
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->
|
|
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->
|
|
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
|
-
|
|
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->
|
|
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
|
{
|