rays 0.3.10 → 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/polygon.cpp +1 -1
- data/.doc/ext/rays/shader.cpp +8 -6
- data/.github/workflows/release-gem.yml +4 -1
- data/.github/workflows/test.yml +4 -4
- data/.github/workflows/utils.rb +88 -17
- data/ChangeLog.md +24 -0
- data/Gemfile.lock +6 -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/polygon.cpp +1 -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/bitmap.h +4 -0
- data/src/color_space.cpp +2 -42
- data/src/coord.h +10 -0
- data/src/font.cpp +1 -1
- data/src/image.cpp +85 -11
- data/src/ios/bitmap.mm +5 -32
- data/src/ios/rays.mm +3 -3
- data/src/opengl/bitmap.cpp +41 -0
- data/src/opengl/color_space.cpp +51 -0
- data/src/{color_space.h → opengl/color_space.h} +2 -2
- data/src/{frame_buffer.cpp → opengl/frame_buffer.cpp} +1 -1
- data/src/{frame_buffer.h → opengl/frame_buffer.h} +2 -2
- data/src/{ios → opengl/ios}/opengl.mm +3 -3
- data/src/{opengl.h → opengl/opengl.h} +2 -6
- data/src/{osx → opengl/osx}/opengl.mm +3 -3
- data/src/opengl/painter.cpp +1020 -0
- data/src/{render_buffer.cpp → opengl/render_buffer.cpp} +1 -1
- data/src/{render_buffer.h → opengl/render_buffer.h} +2 -2
- data/src/{sdl → opengl/sdl}/opengl.cpp +10 -3
- data/src/{shader.cpp → opengl/shader.cpp} +69 -53
- data/src/{shader.h → opengl/shader.h} +12 -8
- data/src/{shader_program.cpp → opengl/shader_program.cpp} +24 -10
- data/src/{shader_program.h → opengl/shader_program.h} +4 -3
- data/src/{shader_source.cpp → opengl/shader_source.cpp} +2 -4
- data/src/{shader_source.h → opengl/shader_source.h} +2 -2
- data/src/{texture.cpp → opengl/texture.cpp} +18 -7
- data/src/opengl/texture.h +21 -0
- data/src/{win32 → opengl/win32}/opengl.cpp +4 -3
- data/src/osx/bitmap.mm +6 -34
- data/src/osx/rays.mm +3 -3
- data/src/painter.cpp +96 -925
- data/src/painter.h +223 -11
- data/src/polygon.cpp +38 -13
- data/src/renderer.h +22 -0
- data/src/sdl/bitmap.cpp +5 -33
- data/src/sdl/font.cpp +358 -9
- data/src/sdl/rays.cpp +8 -3
- data/src/texture.h +6 -3
- data/src/win32/bitmap.cpp +6 -34
- data/src/win32/rays.cpp +3 -3
- data/test/test_painter.rb +36 -25
- data/test/test_painter_batch.rb +254 -0
- metadata +31 -24
- /data/src/{opengl.cpp → opengl/opengl.cpp} +0 -0
|
@@ -0,0 +1,1020 @@
|
|
|
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 "../coord.h"
|
|
13
|
+
#include "../bitmap.h"
|
|
14
|
+
#include "../image.h"
|
|
15
|
+
#include "../font.h"
|
|
16
|
+
#include "opengl.h"
|
|
17
|
+
#include "texture.h"
|
|
18
|
+
#include "frame_buffer.h"
|
|
19
|
+
#include "shader.h"
|
|
20
|
+
#include "shader_program.h"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
namespace Rays
|
|
24
|
+
{
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
struct Vector4 : Coord4
|
|
28
|
+
{
|
|
29
|
+
|
|
30
|
+
Vector4 (const Coord3& p) {Coord4::operator=(p);}
|
|
31
|
+
|
|
32
|
+
};// Vector4
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
struct OpenGLState
|
|
36
|
+
{
|
|
37
|
+
|
|
38
|
+
GLint viewport[4];
|
|
39
|
+
|
|
40
|
+
GLclampf color_clear[4];
|
|
41
|
+
|
|
42
|
+
GLboolean depth_test;
|
|
43
|
+
GLint depth_func;
|
|
44
|
+
|
|
45
|
+
GLboolean scissor_test;
|
|
46
|
+
GLint scissor_box[4];
|
|
47
|
+
|
|
48
|
+
GLboolean blend;
|
|
49
|
+
GLint blend_equation_rgb, blend_equation_alpha;
|
|
50
|
+
GLint blend_src_rgb, blend_src_alpha, blend_dst_rgb, blend_dst_alpha;
|
|
51
|
+
|
|
52
|
+
GLint framebuffer_binding;
|
|
53
|
+
|
|
54
|
+
void push ()
|
|
55
|
+
{
|
|
56
|
+
glGetIntegerv(GL_VIEWPORT, viewport);
|
|
57
|
+
|
|
58
|
+
glGetFloatv(GL_COLOR_CLEAR_VALUE, color_clear);
|
|
59
|
+
|
|
60
|
+
glGetBooleanv(GL_DEPTH_TEST, &depth_test);
|
|
61
|
+
glGetIntegerv(GL_DEPTH_FUNC, &depth_func);
|
|
62
|
+
|
|
63
|
+
glGetBooleanv(GL_SCISSOR_TEST, &scissor_test);
|
|
64
|
+
glGetIntegerv(GL_SCISSOR_BOX, scissor_box);
|
|
65
|
+
|
|
66
|
+
glGetBooleanv(GL_BLEND, &blend);
|
|
67
|
+
glGetIntegerv(GL_BLEND_EQUATION_RGB, &blend_equation_rgb);
|
|
68
|
+
glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &blend_equation_alpha);
|
|
69
|
+
glGetIntegerv(GL_BLEND_SRC_RGB, &blend_src_rgb);
|
|
70
|
+
glGetIntegerv(GL_BLEND_SRC_ALPHA, &blend_src_alpha);
|
|
71
|
+
glGetIntegerv(GL_BLEND_DST_RGB, &blend_dst_rgb);
|
|
72
|
+
glGetIntegerv(GL_BLEND_DST_ALPHA, &blend_dst_alpha);
|
|
73
|
+
|
|
74
|
+
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &framebuffer_binding);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
void pop ()
|
|
78
|
+
{
|
|
79
|
+
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
|
80
|
+
|
|
81
|
+
glClearColor(
|
|
82
|
+
color_clear[0], color_clear[1], color_clear[2], color_clear[3]);
|
|
83
|
+
|
|
84
|
+
enable(GL_DEPTH_TEST, depth_test);
|
|
85
|
+
glDepthFunc(depth_func);
|
|
86
|
+
|
|
87
|
+
enable(GL_SCISSOR_TEST, scissor_test);
|
|
88
|
+
glScissor(scissor_box[0], scissor_box[1], scissor_box[2], scissor_box[3]);
|
|
89
|
+
|
|
90
|
+
enable(GL_BLEND, blend);
|
|
91
|
+
glBlendEquationSeparate(blend_equation_rgb, blend_equation_alpha);
|
|
92
|
+
glBlendFuncSeparate(
|
|
93
|
+
blend_src_rgb, blend_dst_rgb, blend_src_alpha, blend_dst_alpha);
|
|
94
|
+
|
|
95
|
+
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_binding);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private:
|
|
99
|
+
|
|
100
|
+
void enable(GLenum type, GLboolean value)
|
|
101
|
+
{
|
|
102
|
+
if (value)
|
|
103
|
+
glEnable(type);
|
|
104
|
+
else
|
|
105
|
+
glDisable(type);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
};// OpenGLState
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class DefaultIndices
|
|
112
|
+
{
|
|
113
|
+
|
|
114
|
+
public:
|
|
115
|
+
|
|
116
|
+
void resize (size_t size)
|
|
117
|
+
{
|
|
118
|
+
indices.reserve(size);
|
|
119
|
+
while (indices.size() < size)
|
|
120
|
+
indices.emplace_back(indices.size());
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
void clear ()
|
|
124
|
+
{
|
|
125
|
+
decltype(indices)().swap(indices);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const uint* get () const
|
|
129
|
+
{
|
|
130
|
+
return &indices[0];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private:
|
|
134
|
+
|
|
135
|
+
std::vector<uint> indices;
|
|
136
|
+
|
|
137
|
+
};// DefaultIndices
|
|
138
|
+
|
|
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
|
+
|
|
177
|
+
struct PainterData : Painter::Data
|
|
178
|
+
{
|
|
179
|
+
|
|
180
|
+
FrameBuffer frame_buffer;
|
|
181
|
+
|
|
182
|
+
OpenGLState opengl_state;
|
|
183
|
+
|
|
184
|
+
DefaultIndices default_indices;
|
|
185
|
+
|
|
186
|
+
std::vector<GLint> locations;
|
|
187
|
+
|
|
188
|
+
std::vector<GLuint> buffers;
|
|
189
|
+
|
|
190
|
+
std::vector<GLuint> triangle_fan_indices_buffer;
|
|
191
|
+
|
|
192
|
+
Batcher batcher;
|
|
193
|
+
|
|
194
|
+
GLuint create_and_bind_buffer (GLenum target, const void* data, GLsizeiptr size)
|
|
195
|
+
{
|
|
196
|
+
GLuint id = 0;
|
|
197
|
+
glGenBuffers(1, &id);
|
|
198
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
199
|
+
|
|
200
|
+
buffers.push_back(id);
|
|
201
|
+
|
|
202
|
+
glBindBuffer(target, id);
|
|
203
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
204
|
+
|
|
205
|
+
glBufferData(target, size, data, GL_STREAM_DRAW);
|
|
206
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
207
|
+
|
|
208
|
+
return id;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
void cleanup ()
|
|
212
|
+
{
|
|
213
|
+
for (auto loc : locations)
|
|
214
|
+
{
|
|
215
|
+
glDisableVertexAttribArray(loc);
|
|
216
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (!buffers.empty())
|
|
220
|
+
{
|
|
221
|
+
glDeleteBuffers((GLsizei) buffers.size(), &buffers[0]);
|
|
222
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
locations.clear();
|
|
226
|
+
buffers.clear();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
};// PainterData
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
static PainterData*
|
|
233
|
+
get_data (Painter* painter)
|
|
234
|
+
{
|
|
235
|
+
return (PainterData*) painter->self.get();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
void
|
|
239
|
+
Painter_update_clip (Painter* painter)
|
|
240
|
+
{
|
|
241
|
+
PainterData* self = get_data(painter);
|
|
242
|
+
const Bounds& clip = self->state.clip;
|
|
243
|
+
if (clip)
|
|
244
|
+
{
|
|
245
|
+
coord y = self->frame_buffer ? clip.y : self->viewport.h - (clip.y + clip.h);
|
|
246
|
+
glEnable(GL_SCISSOR_TEST);
|
|
247
|
+
glScissor(
|
|
248
|
+
self->pixel_density * clip.x,
|
|
249
|
+
self->pixel_density * y,
|
|
250
|
+
self->pixel_density * clip.width,
|
|
251
|
+
self->pixel_density * clip.height);
|
|
252
|
+
}
|
|
253
|
+
else
|
|
254
|
+
glDisable(GL_SCISSOR_TEST);
|
|
255
|
+
|
|
256
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
static void
|
|
260
|
+
apply_uniform (
|
|
261
|
+
const ShaderProgram& program, const char* name,
|
|
262
|
+
std::function<void(GLint)> apply_fun)
|
|
263
|
+
{
|
|
264
|
+
GLint loc = glGetUniformLocation(program.id(), name);
|
|
265
|
+
if (loc < 0) return;
|
|
266
|
+
|
|
267
|
+
apply_fun(loc);
|
|
268
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
static void
|
|
272
|
+
apply_uniforms (
|
|
273
|
+
const ShaderProgram& program, const ShaderBuiltinVariableNames& names,
|
|
274
|
+
const Matrix& position_matrix, const Matrix& texcoord_matrix,
|
|
275
|
+
const Texture* texture)
|
|
276
|
+
{
|
|
277
|
+
for (const auto& name : names.uniform_position_matrix_names)
|
|
278
|
+
{
|
|
279
|
+
apply_uniform(program, name, [&](GLint loc) {
|
|
280
|
+
glUniformMatrix4fv(loc, 1, GL_FALSE, position_matrix.array);
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
for (const auto& name : names.uniform_texcoord_matrix_names)
|
|
284
|
+
{
|
|
285
|
+
apply_uniform(program, name, [&](GLint loc) {
|
|
286
|
+
glUniformMatrix4fv(loc, 1, GL_FALSE, texcoord_matrix.array);
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (texture && *texture)
|
|
291
|
+
{
|
|
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__);
|
|
305
|
+
|
|
306
|
+
glBindTexture(GL_TEXTURE_2D, Texture_get_id(*texture));
|
|
307
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
308
|
+
|
|
309
|
+
glUniform1i(loc, 0);
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
template <typename COORD>
|
|
316
|
+
static GLenum get_gl_type ();
|
|
317
|
+
|
|
318
|
+
template <>
|
|
319
|
+
GLenum
|
|
320
|
+
get_gl_type<float> ()
|
|
321
|
+
{
|
|
322
|
+
return GL_FLOAT;
|
|
323
|
+
}
|
|
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
|
+
|
|
337
|
+
template <typename CoordN>
|
|
338
|
+
static void
|
|
339
|
+
apply_attribute (
|
|
340
|
+
PainterData* self,
|
|
341
|
+
const ShaderProgram& program, const auto& names,
|
|
342
|
+
const CoordN* values, size_t nvalues)
|
|
343
|
+
{
|
|
344
|
+
GLuint buffer = 0;
|
|
345
|
+
for (const auto& name : names)
|
|
346
|
+
{
|
|
347
|
+
#ifndef IOS
|
|
348
|
+
if (buffer == 0)
|
|
349
|
+
{
|
|
350
|
+
buffer = self->create_and_bind_buffer(
|
|
351
|
+
GL_ARRAY_BUFFER, values, sizeof(CoordN) * nvalues);
|
|
352
|
+
values = 0;
|
|
353
|
+
}
|
|
354
|
+
#endif
|
|
355
|
+
|
|
356
|
+
apply_attribute(program, name, [&](GLint loc)
|
|
357
|
+
{
|
|
358
|
+
glEnableVertexAttribArray(loc);
|
|
359
|
+
OpenGL_check_error(
|
|
360
|
+
__FILE__, __LINE__, "loc: %d %s\n", loc, name.c_str());
|
|
361
|
+
|
|
362
|
+
glVertexAttribPointer(
|
|
363
|
+
loc, CoordN::SIZE, get_gl_type<coord>(), GL_FALSE, 0, values);
|
|
364
|
+
|
|
365
|
+
self->locations.push_back(loc);
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
370
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
template <typename CoordN>
|
|
374
|
+
static void
|
|
375
|
+
apply_attributes (
|
|
376
|
+
PainterData* self,
|
|
377
|
+
const ShaderProgram& program, const ShaderBuiltinVariableNames& names,
|
|
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)
|
|
383
|
+
{
|
|
384
|
+
assert(npoints > 0);
|
|
385
|
+
assert(!!color != !!colors);
|
|
386
|
+
|
|
387
|
+
apply_attribute(
|
|
388
|
+
self, program, names.attribute_position_names,
|
|
389
|
+
points, npoints);
|
|
390
|
+
|
|
391
|
+
if (colors)
|
|
392
|
+
{
|
|
393
|
+
apply_attribute(
|
|
394
|
+
self, program, names.attribute_color_names,
|
|
395
|
+
colors, npoints);
|
|
396
|
+
}
|
|
397
|
+
else if (color)
|
|
398
|
+
{
|
|
399
|
+
#if defined(GL_VERSION_2_1) && !defined(GL_VERSION_3_0)
|
|
400
|
+
// to fix that GL 2.1 with glVertexAttrib4fv() draws nothing
|
|
401
|
+
// with specific glsl 'attribute' name.
|
|
402
|
+
std::vector<Color> colors_(npoints, *color);
|
|
403
|
+
apply_attribute(
|
|
404
|
+
self, program, names.attribute_color_names,
|
|
405
|
+
(const Coord4*) &colors_[0], npoints);
|
|
406
|
+
#else
|
|
407
|
+
for (const auto& name : names.attribute_color_names)
|
|
408
|
+
{
|
|
409
|
+
apply_attribute(
|
|
410
|
+
program, name, [&](GLint loc) {glVertexAttrib4fv(loc, color->array);});
|
|
411
|
+
}
|
|
412
|
+
#endif
|
|
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
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
static void
|
|
451
|
+
draw_indices (
|
|
452
|
+
PainterData* self, PrimitiveMode mode,
|
|
453
|
+
const uint* indices, size_t nindices, size_t npoints)
|
|
454
|
+
{
|
|
455
|
+
if (!indices || nindices <= 0)
|
|
456
|
+
{
|
|
457
|
+
self->default_indices.resize(npoints);
|
|
458
|
+
indices = self->default_indices.get();
|
|
459
|
+
nindices = npoints;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
#ifdef IOS
|
|
463
|
+
glDrawElements((GLenum) mode, (GLsizei) nindices, GL_UNSIGNED_INT, indices);
|
|
464
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
465
|
+
#else
|
|
466
|
+
self->create_and_bind_buffer(
|
|
467
|
+
GL_ELEMENT_ARRAY_BUFFER, indices, sizeof(uint) * nindices);
|
|
468
|
+
|
|
469
|
+
glDrawElements((GLenum) mode, (GLsizei) nindices, GL_UNSIGNED_INT, 0);
|
|
470
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
471
|
+
|
|
472
|
+
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
473
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
474
|
+
#endif
|
|
475
|
+
}
|
|
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
|
+
|
|
689
|
+
void
|
|
690
|
+
Painter_draw (
|
|
691
|
+
Painter* painter, PrimitiveMode mode, const Color* color,
|
|
692
|
+
const Coord3* points, size_t npoints,
|
|
693
|
+
const uint* indices, size_t nindices,
|
|
694
|
+
const Color* colors,
|
|
695
|
+
const Coord3* texcoords,
|
|
696
|
+
const TextureInfo* texinfo,
|
|
697
|
+
const Shader* shader)
|
|
698
|
+
{
|
|
699
|
+
if (!points)
|
|
700
|
+
argument_error(__FILE__, __LINE__);
|
|
701
|
+
if (npoints <= 0)
|
|
702
|
+
argument_error(__FILE__, __LINE__);
|
|
703
|
+
|
|
704
|
+
PainterData* self = get_data(painter);
|
|
705
|
+
|
|
706
|
+
if (!self->is_painting())
|
|
707
|
+
invalid_state_error(__FILE__, __LINE__, "'painting' should be true.");
|
|
708
|
+
|
|
709
|
+
std::unique_ptr<TextureInfo> ptexinfo;
|
|
710
|
+
texinfo = setup_texinfo(self, texinfo, &ptexinfo);
|
|
711
|
+
shader = setup_shader(self, shader, texinfo);
|
|
712
|
+
|
|
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
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
static inline void
|
|
743
|
+
debug_draw_text_line (
|
|
744
|
+
Painter* painter, const Font& font,
|
|
745
|
+
coord x, coord y, coord str_width, coord str_height)
|
|
746
|
+
{
|
|
747
|
+
#if 0
|
|
748
|
+
painter->self->text_image.save("/tmp/font.png");
|
|
749
|
+
|
|
750
|
+
painter->push_state();
|
|
751
|
+
{
|
|
752
|
+
coord asc, desc, lead;
|
|
753
|
+
font.get_height(&asc, &desc, &lead);
|
|
754
|
+
//printf("%f %f %f %f \n", str_height, asc, desc, lead);
|
|
755
|
+
|
|
756
|
+
painter->set_stroke(0.5, 0.5, 1);
|
|
757
|
+
painter->no_fill();
|
|
758
|
+
painter->rect(x - 1, y - 1, str_width + 2, str_height + 2);
|
|
759
|
+
|
|
760
|
+
coord yy = y;
|
|
761
|
+
painter->set_stroke(1, 0.5, 0.5, 0.4);
|
|
762
|
+
painter->rect(x, yy, str_width, asc);//str_height);
|
|
763
|
+
|
|
764
|
+
yy += asc;
|
|
765
|
+
painter->set_stroke(1, 1, 0.5, 0.4);
|
|
766
|
+
painter->rect(x, yy, str_width, desc);
|
|
767
|
+
|
|
768
|
+
yy += desc;
|
|
769
|
+
painter->set_stroke(1, 0.5, 1, 0.4);
|
|
770
|
+
painter->rect(x, yy, str_width, lead);
|
|
771
|
+
}
|
|
772
|
+
painter->pop_state();
|
|
773
|
+
#endif
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
void
|
|
777
|
+
Painter_draw_text_line (
|
|
778
|
+
Painter* painter, const Font& font,
|
|
779
|
+
const char* line, coord x, coord y,
|
|
780
|
+
coord width, coord height)
|
|
781
|
+
{
|
|
782
|
+
assert(painter && font && line && *line != '\0');
|
|
783
|
+
|
|
784
|
+
Painter::Data* self = painter->self.get();
|
|
785
|
+
|
|
786
|
+
float density = self->pixel_density;
|
|
787
|
+
const RawFont& rawfont = Font_get_raw(font, density);
|
|
788
|
+
coord str_w = rawfont.get_width(line);
|
|
789
|
+
coord str_h = rawfont.get_height();
|
|
790
|
+
int tex_w = ceil(str_w);
|
|
791
|
+
int tex_h = ceil(str_h);
|
|
792
|
+
const Texture& texture = Image_get_texture(self->text_image);
|
|
793
|
+
if (
|
|
794
|
+
texture.width() < tex_w ||
|
|
795
|
+
texture.height() < tex_h ||
|
|
796
|
+
self->text_image.pixel_density() != density)
|
|
797
|
+
{
|
|
798
|
+
int bmp_w = std::max(texture.width(), tex_w);
|
|
799
|
+
int bmp_h = std::max(texture.height(), tex_h);
|
|
800
|
+
self->text_image = Image(Bitmap(bmp_w, bmp_h), density);
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
if (!self->text_image)
|
|
804
|
+
invalid_state_error(__FILE__, __LINE__);
|
|
805
|
+
|
|
806
|
+
assert(self->text_image.pixel_density() == density);
|
|
807
|
+
|
|
808
|
+
Bitmap_draw_string(
|
|
809
|
+
&self->text_image.bitmap(), rawfont, line, 0, 0, font.smooth());
|
|
810
|
+
|
|
811
|
+
str_w /= density;
|
|
812
|
+
str_h /= density;
|
|
813
|
+
if (width == 0) width = str_w;
|
|
814
|
+
if (height == 0) height = str_h;
|
|
815
|
+
|
|
816
|
+
Painter_draw_image(
|
|
817
|
+
painter, self->text_image,
|
|
818
|
+
0, 0, str_w, str_h,
|
|
819
|
+
x, y, str_w, str_h,
|
|
820
|
+
&Shader_get_shader_for_text());
|
|
821
|
+
|
|
822
|
+
debug_draw_text_line(painter, font, x, y, str_w / density, str_h / density);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
Painter::Painter ()
|
|
827
|
+
: self(new PainterData())
|
|
828
|
+
{
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
void
|
|
832
|
+
Painter::bind (const Image& image)
|
|
833
|
+
{
|
|
834
|
+
if (!image)
|
|
835
|
+
argument_error(__FILE__, __LINE__, "invalid image.");
|
|
836
|
+
|
|
837
|
+
if (self->is_painting())
|
|
838
|
+
invalid_state_error(__FILE__, __LINE__, "painting flag should be false.");
|
|
839
|
+
|
|
840
|
+
FrameBuffer fb(Image_get_texture(image));
|
|
841
|
+
if (!fb)
|
|
842
|
+
rays_error(__FILE__, __LINE__, "invalid frame buffer.");
|
|
843
|
+
|
|
844
|
+
unbind();
|
|
845
|
+
|
|
846
|
+
get_data(this)->frame_buffer = fb;
|
|
847
|
+
canvas(0, 0, image.width(), image.height(), image.pixel_density());
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
void
|
|
851
|
+
Painter::unbind ()
|
|
852
|
+
{
|
|
853
|
+
if (self->is_painting())
|
|
854
|
+
invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
|
|
855
|
+
|
|
856
|
+
get_data(this)->frame_buffer = FrameBuffer();
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
void
|
|
860
|
+
Painter::begin ()
|
|
861
|
+
{
|
|
862
|
+
PainterData* self = get_data(this);
|
|
863
|
+
|
|
864
|
+
if (self->is_painting())
|
|
865
|
+
invalid_state_error(__FILE__, __LINE__, "painting flag should be false.");
|
|
866
|
+
|
|
867
|
+
self->opengl_state.push();
|
|
868
|
+
|
|
869
|
+
//glEnable(GL_CULL_FACE);
|
|
870
|
+
|
|
871
|
+
glEnable(GL_DEPTH_TEST);
|
|
872
|
+
glDepthFunc(GL_LEQUAL);
|
|
873
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
874
|
+
|
|
875
|
+
glEnable(GL_BLEND);
|
|
876
|
+
set_blend_mode(self->state.blend_mode);
|
|
877
|
+
|
|
878
|
+
FrameBuffer& fb = self->frame_buffer;
|
|
879
|
+
if (fb)
|
|
880
|
+
{
|
|
881
|
+
FrameBuffer_bind(fb.id());
|
|
882
|
+
|
|
883
|
+
Texture& tex = fb.texture();
|
|
884
|
+
if (tex) tex.set_modified();
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
const Bounds& vp = self->viewport;
|
|
888
|
+
float density = self->pixel_density;
|
|
889
|
+
glViewport(
|
|
890
|
+
(int) (vp.x * density), (int) (vp.y * density),
|
|
891
|
+
(int) (vp.width * density), (int) (vp.height * density));
|
|
892
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
893
|
+
|
|
894
|
+
coord x1 = vp.x, x2 = vp.x + vp.width;
|
|
895
|
+
coord y1 = vp.y, y2 = vp.y + vp.height;
|
|
896
|
+
coord z1 = vp.z, z2 = vp.z + vp.depth;
|
|
897
|
+
if (z1 == 0 && z2 == 0) {z1 = -1000; z2 = 1000;}
|
|
898
|
+
if (!fb) std::swap(y1, y2);
|
|
899
|
+
|
|
900
|
+
self->position_matrix.reset(1);
|
|
901
|
+
self->position_matrix *= to_rays(glm::ortho(x1, x2, y1, y2));
|
|
902
|
+
|
|
903
|
+
// map z to 0.0-1.0
|
|
904
|
+
self->position_matrix.scale(1, 1, 1.0 / (z2 - z1));
|
|
905
|
+
self->position_matrix.translate(0, 0, -z2);
|
|
906
|
+
|
|
907
|
+
//self->position_matrix.translate(0.375f, 0.375f);
|
|
908
|
+
|
|
909
|
+
Painter_update_clip(this);
|
|
910
|
+
|
|
911
|
+
Xot::add_flag(&self->flags, Painter::Data::PAINTING);
|
|
912
|
+
|
|
913
|
+
glClear(GL_DEPTH_BUFFER_BIT);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
void
|
|
917
|
+
Painter::end ()
|
|
918
|
+
{
|
|
919
|
+
PainterData* self = get_data(this);
|
|
920
|
+
|
|
921
|
+
if (!self->is_painting())
|
|
922
|
+
invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
|
|
923
|
+
|
|
924
|
+
if (!self->state_stack.empty())
|
|
925
|
+
invalid_state_error(__FILE__, __LINE__, "state stack is not empty.");
|
|
926
|
+
|
|
927
|
+
if (!self->position_matrix_stack.empty())
|
|
928
|
+
invalid_state_error(__FILE__, __LINE__, "position matrix stack is not empty.");
|
|
929
|
+
|
|
930
|
+
Painter_flush(this);
|
|
931
|
+
|
|
932
|
+
Xot::remove_flag(&self->flags, Painter::Data::PAINTING);
|
|
933
|
+
self->opengl_state.pop();
|
|
934
|
+
self->default_indices.clear();
|
|
935
|
+
|
|
936
|
+
glFinish();
|
|
937
|
+
|
|
938
|
+
if (self->frame_buffer)
|
|
939
|
+
FrameBuffer_unbind();
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
void
|
|
943
|
+
Painter::clear ()
|
|
944
|
+
{
|
|
945
|
+
if (!self->is_painting())
|
|
946
|
+
invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
|
|
947
|
+
|
|
948
|
+
Painter_flush(this);
|
|
949
|
+
|
|
950
|
+
const Color& c = self->state.background;
|
|
951
|
+
glClearColor(c.red, c.green, c.blue, c.alpha);
|
|
952
|
+
glClear(GL_COLOR_BUFFER_BIT);
|
|
953
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
void
|
|
957
|
+
Painter::set_blend_mode (BlendMode mode)
|
|
958
|
+
{
|
|
959
|
+
if (self->state.blend_mode != mode)
|
|
960
|
+
Painter_flush(this);
|
|
961
|
+
|
|
962
|
+
self->state.blend_mode = mode;
|
|
963
|
+
switch (mode)
|
|
964
|
+
{
|
|
965
|
+
case BLEND_NORMAL:
|
|
966
|
+
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
|
|
967
|
+
glBlendFuncSeparate(
|
|
968
|
+
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
|
|
969
|
+
break;
|
|
970
|
+
|
|
971
|
+
case BLEND_ADD:
|
|
972
|
+
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
|
|
973
|
+
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE);
|
|
974
|
+
break;
|
|
975
|
+
|
|
976
|
+
case BLEND_SUBTRACT:
|
|
977
|
+
glBlendEquationSeparate(GL_FUNC_REVERSE_SUBTRACT, GL_FUNC_ADD);
|
|
978
|
+
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE);
|
|
979
|
+
break;
|
|
980
|
+
|
|
981
|
+
case BLEND_LIGHTEST:
|
|
982
|
+
glBlendEquationSeparate(GL_MAX, GL_FUNC_ADD);
|
|
983
|
+
glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ONE);
|
|
984
|
+
break;
|
|
985
|
+
|
|
986
|
+
case BLEND_DARKEST:
|
|
987
|
+
glBlendEquationSeparate(GL_MIN, GL_FUNC_ADD);
|
|
988
|
+
glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ONE);
|
|
989
|
+
break;
|
|
990
|
+
|
|
991
|
+
case BLEND_EXCLUSION:
|
|
992
|
+
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
|
|
993
|
+
glBlendFuncSeparate(
|
|
994
|
+
GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_ONE, GL_ONE);
|
|
995
|
+
break;
|
|
996
|
+
|
|
997
|
+
case BLEND_MULTIPLY:
|
|
998
|
+
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
|
|
999
|
+
glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ONE, GL_ONE);
|
|
1000
|
+
break;
|
|
1001
|
+
|
|
1002
|
+
case BLEND_SCREEN:
|
|
1003
|
+
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
|
|
1004
|
+
glBlendFuncSeparate(GL_ONE_MINUS_DST_COLOR, GL_ONE, GL_ONE, GL_ONE);
|
|
1005
|
+
break;
|
|
1006
|
+
|
|
1007
|
+
case BLEND_REPLACE:
|
|
1008
|
+
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
|
|
1009
|
+
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO);
|
|
1010
|
+
break;
|
|
1011
|
+
|
|
1012
|
+
default:
|
|
1013
|
+
argument_error(__FILE__, __LINE__, "unknown blend mode");
|
|
1014
|
+
break;
|
|
1015
|
+
}
|
|
1016
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
|
|
1020
|
+
}// Rays
|