rays 0.3.10 → 0.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.doc/ext/rays/polygon.cpp +1 -1
- data/.github/workflows/release-gem.yml +1 -1
- data/.github/workflows/test.yml +4 -4
- data/ChangeLog.md +7 -0
- data/Gemfile.lock +6 -5
- data/VERSION +1 -1
- data/ext/rays/polygon.cpp +1 -1
- data/rays.gemspec +2 -2
- data/src/bitmap.h +4 -0
- data/src/color_space.cpp +1 -41
- data/src/image.cpp +0 -1
- 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 +756 -0
- data/src/{render_buffer.h → opengl/render_buffer.h} +2 -2
- data/src/{sdl → opengl/sdl}/opengl.cpp +4 -3
- data/src/{shader.cpp → opengl/shader.cpp} +1 -2
- data/src/{shader.h → opengl/shader.h} +2 -2
- data/src/{shader_program.cpp → opengl/shader_program.cpp} +3 -3
- data/src/{shader_program.h → opengl/shader_program.h} +2 -2
- data/src/{shader_source.h → opengl/shader_source.h} +2 -2
- data/src/{texture.cpp → opengl/texture.cpp} +2 -3
- data/src/opengl/texture.h +21 -0
- data/src/{win32 → opengl/win32}/opengl.cpp +4 -3
- data/src/osx/bitmap.mm +5 -33
- data/src/osx/rays.mm +3 -3
- data/src/painter.cpp +21 -905
- data/src/painter.h +210 -11
- data/src/polygon.cpp +38 -13
- data/src/renderer.h +22 -0
- data/src/sdl/bitmap.cpp +5 -33
- data/src/sdl/rays.cpp +3 -3
- data/src/texture.h +0 -3
- data/src/win32/bitmap.cpp +6 -34
- data/src/win32/rays.cpp +3 -3
- metadata +29 -24
- /data/src/{opengl.cpp → opengl/opengl.cpp} +0 -0
- /data/src/{render_buffer.cpp → opengl/render_buffer.cpp} +0 -0
- /data/src/{shader_source.cpp → opengl/shader_source.cpp} +0 -0
|
@@ -0,0 +1,756 @@
|
|
|
1
|
+
#include "../painter.h"
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
#include <math.h>
|
|
5
|
+
#include <assert.h>
|
|
6
|
+
#include <memory>
|
|
7
|
+
#include <vector>
|
|
8
|
+
#include <algorithm>
|
|
9
|
+
#include <functional>
|
|
10
|
+
#include "rays/exception.h"
|
|
11
|
+
#include "../glm.h"
|
|
12
|
+
#include "../bitmap.h"
|
|
13
|
+
#include "../image.h"
|
|
14
|
+
#include "../font.h"
|
|
15
|
+
#include "opengl.h"
|
|
16
|
+
#include "texture.h"
|
|
17
|
+
#include "frame_buffer.h"
|
|
18
|
+
#include "shader.h"
|
|
19
|
+
#include "shader_program.h"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
namespace Rays
|
|
23
|
+
{
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
struct OpenGLState
|
|
27
|
+
{
|
|
28
|
+
|
|
29
|
+
GLint viewport[4];
|
|
30
|
+
|
|
31
|
+
GLclampf color_clear[4];
|
|
32
|
+
|
|
33
|
+
GLboolean depth_test;
|
|
34
|
+
GLint depth_func;
|
|
35
|
+
|
|
36
|
+
GLboolean scissor_test;
|
|
37
|
+
GLint scissor_box[4];
|
|
38
|
+
|
|
39
|
+
GLboolean blend;
|
|
40
|
+
GLint blend_equation_rgb, blend_equation_alpha;
|
|
41
|
+
GLint blend_src_rgb, blend_src_alpha, blend_dst_rgb, blend_dst_alpha;
|
|
42
|
+
|
|
43
|
+
GLint framebuffer_binding;
|
|
44
|
+
|
|
45
|
+
void push ()
|
|
46
|
+
{
|
|
47
|
+
glGetIntegerv(GL_VIEWPORT, viewport);
|
|
48
|
+
|
|
49
|
+
glGetFloatv(GL_COLOR_CLEAR_VALUE, color_clear);
|
|
50
|
+
|
|
51
|
+
glGetBooleanv(GL_DEPTH_TEST, &depth_test);
|
|
52
|
+
glGetIntegerv(GL_DEPTH_FUNC, &depth_func);
|
|
53
|
+
|
|
54
|
+
glGetBooleanv(GL_SCISSOR_TEST, &scissor_test);
|
|
55
|
+
glGetIntegerv(GL_SCISSOR_BOX, scissor_box);
|
|
56
|
+
|
|
57
|
+
glGetBooleanv(GL_BLEND, &blend);
|
|
58
|
+
glGetIntegerv(GL_BLEND_EQUATION_RGB, &blend_equation_rgb);
|
|
59
|
+
glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &blend_equation_alpha);
|
|
60
|
+
glGetIntegerv(GL_BLEND_SRC_RGB, &blend_src_rgb);
|
|
61
|
+
glGetIntegerv(GL_BLEND_SRC_ALPHA, &blend_src_alpha);
|
|
62
|
+
glGetIntegerv(GL_BLEND_DST_RGB, &blend_dst_rgb);
|
|
63
|
+
glGetIntegerv(GL_BLEND_DST_ALPHA, &blend_dst_alpha);
|
|
64
|
+
|
|
65
|
+
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &framebuffer_binding);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void pop ()
|
|
69
|
+
{
|
|
70
|
+
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
|
71
|
+
|
|
72
|
+
glClearColor(
|
|
73
|
+
color_clear[0], color_clear[1], color_clear[2], color_clear[3]);
|
|
74
|
+
|
|
75
|
+
enable(GL_DEPTH_TEST, depth_test);
|
|
76
|
+
glDepthFunc(depth_func);
|
|
77
|
+
|
|
78
|
+
enable(GL_SCISSOR_TEST, scissor_test);
|
|
79
|
+
glScissor(scissor_box[0], scissor_box[1], scissor_box[2], scissor_box[3]);
|
|
80
|
+
|
|
81
|
+
enable(GL_BLEND, blend);
|
|
82
|
+
glBlendEquationSeparate(blend_equation_rgb, blend_equation_alpha);
|
|
83
|
+
glBlendFuncSeparate(
|
|
84
|
+
blend_src_rgb, blend_dst_rgb, blend_src_alpha, blend_dst_alpha);
|
|
85
|
+
|
|
86
|
+
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_binding);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private:
|
|
90
|
+
|
|
91
|
+
void enable(GLenum type, GLboolean value)
|
|
92
|
+
{
|
|
93
|
+
if (value)
|
|
94
|
+
glEnable(type);
|
|
95
|
+
else
|
|
96
|
+
glDisable(type);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
};// OpenGLState
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class DefaultIndices
|
|
103
|
+
{
|
|
104
|
+
|
|
105
|
+
public:
|
|
106
|
+
|
|
107
|
+
void resize (size_t size)
|
|
108
|
+
{
|
|
109
|
+
indices.reserve(size);
|
|
110
|
+
while (indices.size() < size)
|
|
111
|
+
indices.emplace_back(indices.size());
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
void clear ()
|
|
115
|
+
{
|
|
116
|
+
decltype(indices)().swap(indices);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const uint* get () const
|
|
120
|
+
{
|
|
121
|
+
return &indices[0];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private:
|
|
125
|
+
|
|
126
|
+
std::vector<uint> indices;
|
|
127
|
+
|
|
128
|
+
};// DefaultIndices
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
struct PainterData : Painter::Data
|
|
132
|
+
{
|
|
133
|
+
|
|
134
|
+
FrameBuffer frame_buffer;
|
|
135
|
+
|
|
136
|
+
OpenGLState opengl_state;
|
|
137
|
+
|
|
138
|
+
DefaultIndices default_indices;
|
|
139
|
+
|
|
140
|
+
std::vector<GLint> locations;
|
|
141
|
+
|
|
142
|
+
std::vector<GLuint> buffers;
|
|
143
|
+
|
|
144
|
+
GLuint create_and_bind_buffer (GLenum target, const void* data, GLsizeiptr size)
|
|
145
|
+
{
|
|
146
|
+
GLuint id = 0;
|
|
147
|
+
glGenBuffers(1, &id);
|
|
148
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
149
|
+
|
|
150
|
+
buffers.push_back(id);
|
|
151
|
+
|
|
152
|
+
glBindBuffer(target, id);
|
|
153
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
154
|
+
|
|
155
|
+
glBufferData(target, size, data, GL_STREAM_DRAW);
|
|
156
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
157
|
+
|
|
158
|
+
return id;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
void cleanup ()
|
|
162
|
+
{
|
|
163
|
+
for (auto loc : locations)
|
|
164
|
+
{
|
|
165
|
+
glDisableVertexAttribArray(loc);
|
|
166
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!buffers.empty())
|
|
170
|
+
{
|
|
171
|
+
glDeleteBuffers((GLsizei) buffers.size(), &buffers[0]);
|
|
172
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
locations.clear();
|
|
176
|
+
buffers.clear();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
};// PainterData
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
static PainterData*
|
|
183
|
+
get_data (Painter* painter)
|
|
184
|
+
{
|
|
185
|
+
return (PainterData*) painter->self.get();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
void
|
|
189
|
+
Painter_update_clip (Painter* painter)
|
|
190
|
+
{
|
|
191
|
+
PainterData* self = get_data(painter);
|
|
192
|
+
const Bounds& clip = self->state.clip;
|
|
193
|
+
if (clip)
|
|
194
|
+
{
|
|
195
|
+
coord y = self->frame_buffer ? clip.y : self->viewport.h - (clip.y + clip.h);
|
|
196
|
+
glEnable(GL_SCISSOR_TEST);
|
|
197
|
+
glScissor(
|
|
198
|
+
self->pixel_density * clip.x,
|
|
199
|
+
self->pixel_density * y,
|
|
200
|
+
self->pixel_density * clip.width,
|
|
201
|
+
self->pixel_density * clip.height);
|
|
202
|
+
}
|
|
203
|
+
else
|
|
204
|
+
glDisable(GL_SCISSOR_TEST);
|
|
205
|
+
|
|
206
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
static const TextureInfo*
|
|
210
|
+
setup_texinfo (
|
|
211
|
+
PainterData* self, const TextureInfo* texinfo,
|
|
212
|
+
std::unique_ptr<TextureInfo>& ptr)
|
|
213
|
+
{
|
|
214
|
+
if (texinfo) return texinfo;
|
|
215
|
+
|
|
216
|
+
const Texture* tex =
|
|
217
|
+
self->state.texture ? &Image_get_texture(self->state.texture) : NULL;
|
|
218
|
+
if (!tex) return NULL;
|
|
219
|
+
|
|
220
|
+
ptr.reset(new TextureInfo(*tex, 0, 0, tex->width(), tex->height()));
|
|
221
|
+
return ptr.get();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
static const Shader*
|
|
225
|
+
setup_shader (
|
|
226
|
+
PainterData* self, const Shader* shader, bool for_texture)
|
|
227
|
+
{
|
|
228
|
+
if (self->state.shader) return &self->state.shader;
|
|
229
|
+
if (shader) return shader;
|
|
230
|
+
return for_texture
|
|
231
|
+
? &Shader_get_default_shader_for_texture(self->state.texcoord_wrap)
|
|
232
|
+
: &Shader_get_default_shader_for_shape();
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
static void
|
|
236
|
+
apply_uniform (
|
|
237
|
+
const ShaderProgram& program, const char* name,
|
|
238
|
+
std::function<void(GLint)> apply_fun)
|
|
239
|
+
{
|
|
240
|
+
GLint loc = glGetUniformLocation(program.id(), name);
|
|
241
|
+
if (loc < 0) return;
|
|
242
|
+
|
|
243
|
+
apply_fun(loc);
|
|
244
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
static void
|
|
248
|
+
apply_attribute (
|
|
249
|
+
const ShaderProgram& program, const char* name,
|
|
250
|
+
std::function<void(GLint)> apply_fun)
|
|
251
|
+
{
|
|
252
|
+
GLint loc = glGetAttribLocation(program.id(), name);
|
|
253
|
+
if (loc < 0) return;
|
|
254
|
+
|
|
255
|
+
apply_fun(loc);
|
|
256
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
static void
|
|
260
|
+
apply_builtin_uniforms (
|
|
261
|
+
const ShaderProgram& program, const ShaderBuiltinVariableNames& names,
|
|
262
|
+
const Matrix& position_matrix, const State& state,
|
|
263
|
+
const TextureInfo* texinfo)
|
|
264
|
+
{
|
|
265
|
+
const Texture* texture = texinfo ? &texinfo->texture : NULL;
|
|
266
|
+
|
|
267
|
+
Matrix texcoord_matrix(1);
|
|
268
|
+
if (texture && *texture)
|
|
269
|
+
{
|
|
270
|
+
bool normal = state.texcoord_mode == TEXCOORD_NORMAL;
|
|
271
|
+
texcoord_matrix.scale(
|
|
272
|
+
(normal ? texture->width() : 1.0) / texture->reserved_width(),
|
|
273
|
+
(normal ? texture->height() : 1.0) / texture->reserved_height());
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
for (const auto& name : names.uniform_position_matrix_names)
|
|
277
|
+
{
|
|
278
|
+
apply_uniform(program, name, [&](GLint loc) {
|
|
279
|
+
glUniformMatrix4fv(loc, 1, GL_FALSE, position_matrix.array);
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
for (const auto& name : names.uniform_texcoord_matrix_names)
|
|
283
|
+
{
|
|
284
|
+
apply_uniform(program, name, [&](GLint loc) {
|
|
285
|
+
glUniformMatrix4fv(loc, 1, GL_FALSE, texcoord_matrix.array);
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (!texinfo || !texture || !*texture) return;
|
|
290
|
+
|
|
291
|
+
coord tw = texture->reserved_width();
|
|
292
|
+
coord th = texture->reserved_height();
|
|
293
|
+
Point min(texinfo->min.x / tw, texinfo->min.y / th);
|
|
294
|
+
Point max(texinfo->max.x / tw, texinfo->max.y / th);
|
|
295
|
+
Point offset( 1 / tw, 1 / th);
|
|
296
|
+
|
|
297
|
+
for (const auto& name : names.uniform_texcoord_min_names)
|
|
298
|
+
{
|
|
299
|
+
apply_uniform(program, name, [&](GLint loc) {
|
|
300
|
+
glUniform3fv(loc, 1, min.array);
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
for (const auto& name : names.uniform_texcoord_max_names)
|
|
304
|
+
{
|
|
305
|
+
apply_uniform(program, name, [&](GLint loc) {
|
|
306
|
+
glUniform3fv(loc, 1, max.array);
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
for (const auto& name : names.uniform_texcoord_offset_names)
|
|
310
|
+
{
|
|
311
|
+
apply_uniform(program, name, [&](GLint loc) {
|
|
312
|
+
glUniform3fv(loc, 1, offset.array);
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
for (const auto& name : names.uniform_texture_names)
|
|
316
|
+
{
|
|
317
|
+
apply_uniform(program, name, [&](GLint loc) {
|
|
318
|
+
glActiveTexture(GL_TEXTURE0);
|
|
319
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
320
|
+
|
|
321
|
+
glBindTexture(GL_TEXTURE_2D, Texture_get_id(*texture));
|
|
322
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
323
|
+
|
|
324
|
+
glUniform1i(loc, 0);
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
template <typename COORD>
|
|
330
|
+
static GLenum get_gl_type ();
|
|
331
|
+
|
|
332
|
+
template <>
|
|
333
|
+
GLenum
|
|
334
|
+
get_gl_type<float> ()
|
|
335
|
+
{
|
|
336
|
+
return GL_FLOAT;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
template <typename CoordN>
|
|
340
|
+
static void
|
|
341
|
+
apply_attribute (
|
|
342
|
+
PainterData* self,
|
|
343
|
+
const ShaderProgram& program, const auto& names,
|
|
344
|
+
const CoordN* values, size_t nvalues)
|
|
345
|
+
{
|
|
346
|
+
GLuint buffer = 0;
|
|
347
|
+
for (const auto& name : names)
|
|
348
|
+
{
|
|
349
|
+
#ifndef IOS
|
|
350
|
+
if (buffer == 0)
|
|
351
|
+
{
|
|
352
|
+
buffer = self->create_and_bind_buffer(
|
|
353
|
+
GL_ARRAY_BUFFER, values, sizeof(CoordN) * nvalues);
|
|
354
|
+
values = 0;
|
|
355
|
+
}
|
|
356
|
+
#endif
|
|
357
|
+
|
|
358
|
+
apply_attribute(program, name, [&](GLint loc) {
|
|
359
|
+
glEnableVertexAttribArray(loc);
|
|
360
|
+
OpenGL_check_error(
|
|
361
|
+
__FILE__, __LINE__, "loc: %d %s\n", loc, name.c_str());
|
|
362
|
+
|
|
363
|
+
glVertexAttribPointer(
|
|
364
|
+
loc, CoordN::SIZE, get_gl_type<coord>(), GL_FALSE, 0, values);
|
|
365
|
+
|
|
366
|
+
self->locations.push_back(loc);
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
371
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
static void
|
|
375
|
+
apply_attributes (
|
|
376
|
+
PainterData* self,
|
|
377
|
+
const ShaderProgram& program, const ShaderBuiltinVariableNames& names,
|
|
378
|
+
const Coord3* points, size_t npoints, const Coord3* texcoords,
|
|
379
|
+
const Color* color, const Color* colors)
|
|
380
|
+
{
|
|
381
|
+
assert(npoints > 0);
|
|
382
|
+
assert(!!color != !!colors);
|
|
383
|
+
|
|
384
|
+
apply_attribute(
|
|
385
|
+
self, program, names.attribute_position_names,
|
|
386
|
+
points, npoints);
|
|
387
|
+
|
|
388
|
+
apply_attribute(
|
|
389
|
+
self, program, names.attribute_texcoord_names,
|
|
390
|
+
texcoords ? texcoords : points, npoints);
|
|
391
|
+
|
|
392
|
+
if (colors)
|
|
393
|
+
{
|
|
394
|
+
apply_attribute(
|
|
395
|
+
self, program, names.attribute_color_names,
|
|
396
|
+
colors, npoints);
|
|
397
|
+
}
|
|
398
|
+
else if (color)
|
|
399
|
+
{
|
|
400
|
+
#if defined(GL_VERSION_2_1) && !defined(GL_VERSION_3_0)
|
|
401
|
+
// to fix that GL 2.1 with glVertexAttrib4fv() draws nothing
|
|
402
|
+
// with specific glsl 'attribute' name.
|
|
403
|
+
std::vector<Color> colors_(npoints, *color);
|
|
404
|
+
apply_attribute(
|
|
405
|
+
self, program, names.attribute_color_names,
|
|
406
|
+
(const Coord4*) &colors_[0], npoints);
|
|
407
|
+
#else
|
|
408
|
+
for (const auto& name : names.attribute_color_names)
|
|
409
|
+
{
|
|
410
|
+
apply_attribute(program, name, [&](GLint loc) {
|
|
411
|
+
glVertexAttrib4fv(loc, color->array);
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
#endif
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
static void
|
|
419
|
+
draw_indices (
|
|
420
|
+
PainterData* self,
|
|
421
|
+
GLenum mode, const uint* indices, size_t nindices, size_t npoints)
|
|
422
|
+
{
|
|
423
|
+
if (!indices || nindices <= 0)
|
|
424
|
+
{
|
|
425
|
+
self->default_indices.resize(npoints);
|
|
426
|
+
indices = self->default_indices.get();
|
|
427
|
+
nindices = npoints;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
#ifdef IOS
|
|
431
|
+
glDrawElements(mode, (GLsizei) nindices, GL_UNSIGNED_INT, indices);
|
|
432
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
433
|
+
#else
|
|
434
|
+
self->create_and_bind_buffer(
|
|
435
|
+
GL_ELEMENT_ARRAY_BUFFER, indices, sizeof(uint) * nindices);
|
|
436
|
+
|
|
437
|
+
glDrawElements(mode, (GLsizei) nindices, GL_UNSIGNED_INT, 0);
|
|
438
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
439
|
+
|
|
440
|
+
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
441
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
442
|
+
#endif
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
void
|
|
446
|
+
Painter_draw (
|
|
447
|
+
Painter* painter, PrimitiveMode mode, const Color* color,
|
|
448
|
+
const Coord3* points, size_t npoints,
|
|
449
|
+
const uint* indices, size_t nindices,
|
|
450
|
+
const Color* colors,
|
|
451
|
+
const Coord3* texcoords,
|
|
452
|
+
const TextureInfo* texinfo,
|
|
453
|
+
const Shader* shader)
|
|
454
|
+
{
|
|
455
|
+
if (!points)
|
|
456
|
+
argument_error(__FILE__, __LINE__);
|
|
457
|
+
if (npoints <= 0)
|
|
458
|
+
argument_error(__FILE__, __LINE__);
|
|
459
|
+
|
|
460
|
+
PainterData* self = get_data(painter);
|
|
461
|
+
|
|
462
|
+
if (!self->painting)
|
|
463
|
+
invalid_state_error(__FILE__, __LINE__, "'painting' should be true.");
|
|
464
|
+
|
|
465
|
+
std::unique_ptr<TextureInfo> ptexinfo;
|
|
466
|
+
texinfo = setup_texinfo(self, texinfo, ptexinfo);
|
|
467
|
+
shader = setup_shader(self, shader, texinfo);
|
|
468
|
+
|
|
469
|
+
const ShaderProgram* program = Shader_get_program(*shader);
|
|
470
|
+
if (!program || !*program) return;
|
|
471
|
+
|
|
472
|
+
ShaderProgram_activate(*program);
|
|
473
|
+
|
|
474
|
+
const auto& names = Shader_get_builtin_variable_names(*shader);
|
|
475
|
+
apply_builtin_uniforms(
|
|
476
|
+
*program, names, self->position_matrix, self->state, texinfo);
|
|
477
|
+
apply_attributes(
|
|
478
|
+
self, *program, names, points, npoints, texcoords, color, colors);
|
|
479
|
+
draw_indices(self, (GLenum) mode, indices, nindices, npoints);
|
|
480
|
+
self->cleanup();
|
|
481
|
+
|
|
482
|
+
ShaderProgram_deactivate();
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
static inline void
|
|
486
|
+
debug_draw_text_line (
|
|
487
|
+
Painter* painter, const Font& font,
|
|
488
|
+
coord x, coord y, coord str_width, coord str_height)
|
|
489
|
+
{
|
|
490
|
+
#if 0
|
|
491
|
+
painter->self->text_image.save("/tmp/font.png");
|
|
492
|
+
|
|
493
|
+
painter->push_state();
|
|
494
|
+
{
|
|
495
|
+
coord asc, desc, lead;
|
|
496
|
+
font.get_height(&asc, &desc, &lead);
|
|
497
|
+
//printf("%f %f %f %f \n", str_height, asc, desc, lead);
|
|
498
|
+
|
|
499
|
+
painter->set_stroke(0.5, 0.5, 1);
|
|
500
|
+
painter->no_fill();
|
|
501
|
+
painter->rect(x - 1, y - 1, str_width + 2, str_height + 2);
|
|
502
|
+
|
|
503
|
+
coord yy = y;
|
|
504
|
+
painter->set_stroke(1, 0.5, 0.5, 0.4);
|
|
505
|
+
painter->rect(x, yy, str_width, asc);//str_height);
|
|
506
|
+
|
|
507
|
+
yy += asc;
|
|
508
|
+
painter->set_stroke(1, 1, 0.5, 0.4);
|
|
509
|
+
painter->rect(x, yy, str_width, desc);
|
|
510
|
+
|
|
511
|
+
yy += desc;
|
|
512
|
+
painter->set_stroke(1, 0.5, 1, 0.4);
|
|
513
|
+
painter->rect(x, yy, str_width, lead);
|
|
514
|
+
}
|
|
515
|
+
painter->pop_state();
|
|
516
|
+
#endif
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
void
|
|
520
|
+
Painter_draw_text_line (
|
|
521
|
+
Painter* painter, const Font& font,
|
|
522
|
+
const char* line, coord x, coord y,
|
|
523
|
+
coord width, coord height)
|
|
524
|
+
{
|
|
525
|
+
assert(painter && font && line && *line != '\0');
|
|
526
|
+
|
|
527
|
+
Painter::Data* self = painter->self.get();
|
|
528
|
+
|
|
529
|
+
float density = self->pixel_density;
|
|
530
|
+
const RawFont& rawfont = Font_get_raw(font, density);
|
|
531
|
+
coord str_w = rawfont.get_width(line);
|
|
532
|
+
coord str_h = rawfont.get_height();
|
|
533
|
+
int tex_w = ceil(str_w);
|
|
534
|
+
int tex_h = ceil(str_h);
|
|
535
|
+
const Texture& texture = Image_get_texture(self->text_image);
|
|
536
|
+
if (
|
|
537
|
+
texture.width() < tex_w ||
|
|
538
|
+
texture.height() < tex_h ||
|
|
539
|
+
self->text_image.pixel_density() != density)
|
|
540
|
+
{
|
|
541
|
+
int bmp_w = std::max(texture.width(), tex_w);
|
|
542
|
+
int bmp_h = std::max(texture.height(), tex_h);
|
|
543
|
+
self->text_image = Image(Bitmap(bmp_w, bmp_h), density);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
if (!self->text_image)
|
|
547
|
+
invalid_state_error(__FILE__, __LINE__);
|
|
548
|
+
|
|
549
|
+
assert(self->text_image.pixel_density() == density);
|
|
550
|
+
|
|
551
|
+
Bitmap_draw_string(
|
|
552
|
+
&self->text_image.bitmap(), rawfont, line, 0, 0, font.smooth());
|
|
553
|
+
|
|
554
|
+
str_w /= density;
|
|
555
|
+
str_h /= density;
|
|
556
|
+
if (width == 0) width = str_w;
|
|
557
|
+
if (height == 0) height = str_h;
|
|
558
|
+
|
|
559
|
+
Painter_draw_image(
|
|
560
|
+
painter, self->text_image,
|
|
561
|
+
0, 0, str_w, str_h,
|
|
562
|
+
x, y, str_w, str_h,
|
|
563
|
+
false, true, &Shader_get_shader_for_text());
|
|
564
|
+
|
|
565
|
+
debug_draw_text_line(painter, font, x, y, str_w / density, str_h / density);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
Painter::Painter ()
|
|
570
|
+
: self(new PainterData())
|
|
571
|
+
{
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
void
|
|
575
|
+
Painter::bind (const Image& image)
|
|
576
|
+
{
|
|
577
|
+
if (!image)
|
|
578
|
+
argument_error(__FILE__, __LINE__, "invalid image.");
|
|
579
|
+
|
|
580
|
+
if (self->painting)
|
|
581
|
+
invalid_state_error(__FILE__, __LINE__, "painting flag should be false.");
|
|
582
|
+
|
|
583
|
+
FrameBuffer fb(Image_get_texture(image));
|
|
584
|
+
if (!fb)
|
|
585
|
+
rays_error(__FILE__, __LINE__, "invalid frame buffer.");
|
|
586
|
+
|
|
587
|
+
unbind();
|
|
588
|
+
|
|
589
|
+
get_data(this)->frame_buffer = fb;
|
|
590
|
+
canvas(0, 0, image.width(), image.height(), image.pixel_density());
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
void
|
|
594
|
+
Painter::unbind ()
|
|
595
|
+
{
|
|
596
|
+
if (self->painting)
|
|
597
|
+
invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
|
|
598
|
+
|
|
599
|
+
get_data(this)->frame_buffer = FrameBuffer();
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
void
|
|
603
|
+
Painter::begin ()
|
|
604
|
+
{
|
|
605
|
+
PainterData* self = get_data(this);
|
|
606
|
+
|
|
607
|
+
if (self->painting)
|
|
608
|
+
invalid_state_error(__FILE__, __LINE__, "painting flag should be false.");
|
|
609
|
+
|
|
610
|
+
self->opengl_state.push();
|
|
611
|
+
|
|
612
|
+
//glEnable(GL_CULL_FACE);
|
|
613
|
+
|
|
614
|
+
glEnable(GL_DEPTH_TEST);
|
|
615
|
+
glDepthFunc(GL_LEQUAL);
|
|
616
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
617
|
+
|
|
618
|
+
glEnable(GL_BLEND);
|
|
619
|
+
set_blend_mode(self->state.blend_mode);
|
|
620
|
+
|
|
621
|
+
FrameBuffer& fb = self->frame_buffer;
|
|
622
|
+
if (fb)
|
|
623
|
+
{
|
|
624
|
+
FrameBuffer_bind(fb.id());
|
|
625
|
+
|
|
626
|
+
Texture& tex = fb.texture();
|
|
627
|
+
if (tex) tex.set_modified();
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
const Bounds& vp = self->viewport;
|
|
631
|
+
float density = self->pixel_density;
|
|
632
|
+
glViewport(
|
|
633
|
+
(int) (vp.x * density), (int) (vp.y * density),
|
|
634
|
+
(int) (vp.width * density), (int) (vp.height * density));
|
|
635
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
636
|
+
|
|
637
|
+
coord x1 = vp.x, x2 = vp.x + vp.width;
|
|
638
|
+
coord y1 = vp.y, y2 = vp.y + vp.height;
|
|
639
|
+
coord z1 = vp.z, z2 = vp.z + vp.depth;
|
|
640
|
+
if (z1 == 0 && z2 == 0) {z1 = -1000; z2 = 1000;}
|
|
641
|
+
if (!fb) std::swap(y1, y2);
|
|
642
|
+
|
|
643
|
+
self->position_matrix.reset(1);
|
|
644
|
+
self->position_matrix *= to_rays(glm::ortho(x1, x2, y1, y2));
|
|
645
|
+
|
|
646
|
+
// map z to 0.0-1.0
|
|
647
|
+
self->position_matrix.scale(1, 1, 1.0 / (z2 - z1));
|
|
648
|
+
self->position_matrix.translate(0, 0, -z2);
|
|
649
|
+
|
|
650
|
+
//self->position_matrix.translate(0.375f, 0.375f);
|
|
651
|
+
|
|
652
|
+
Painter_update_clip(this);
|
|
653
|
+
|
|
654
|
+
self->painting = true;
|
|
655
|
+
|
|
656
|
+
glClear(GL_DEPTH_BUFFER_BIT);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
void
|
|
660
|
+
Painter::end ()
|
|
661
|
+
{
|
|
662
|
+
PainterData* self = get_data(this);
|
|
663
|
+
|
|
664
|
+
if (!self->painting)
|
|
665
|
+
invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
|
|
666
|
+
|
|
667
|
+
if (!self->state_stack.empty())
|
|
668
|
+
invalid_state_error(__FILE__, __LINE__, "state stack is not empty.");
|
|
669
|
+
|
|
670
|
+
if (!self->position_matrix_stack.empty())
|
|
671
|
+
invalid_state_error(__FILE__, __LINE__, "position matrix stack is not empty.");
|
|
672
|
+
|
|
673
|
+
self->painting = false;
|
|
674
|
+
self->opengl_state.pop();
|
|
675
|
+
self->default_indices.clear();
|
|
676
|
+
|
|
677
|
+
glFinish();
|
|
678
|
+
|
|
679
|
+
if (self->frame_buffer)
|
|
680
|
+
FrameBuffer_unbind();
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
void
|
|
684
|
+
Painter::clear ()
|
|
685
|
+
{
|
|
686
|
+
if (!self->painting)
|
|
687
|
+
invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
|
|
688
|
+
|
|
689
|
+
const Color& c = self->state.background;
|
|
690
|
+
glClearColor(c.red, c.green, c.blue, c.alpha);
|
|
691
|
+
glClear(GL_COLOR_BUFFER_BIT);
|
|
692
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
void
|
|
696
|
+
Painter::set_blend_mode (BlendMode mode)
|
|
697
|
+
{
|
|
698
|
+
self->state.blend_mode = mode;
|
|
699
|
+
switch (mode)
|
|
700
|
+
{
|
|
701
|
+
case BLEND_NORMAL:
|
|
702
|
+
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
|
|
703
|
+
glBlendFuncSeparate(
|
|
704
|
+
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
|
|
705
|
+
break;
|
|
706
|
+
|
|
707
|
+
case BLEND_ADD:
|
|
708
|
+
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
|
|
709
|
+
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE);
|
|
710
|
+
break;
|
|
711
|
+
|
|
712
|
+
case BLEND_SUBTRACT:
|
|
713
|
+
glBlendEquationSeparate(GL_FUNC_REVERSE_SUBTRACT, GL_FUNC_ADD);
|
|
714
|
+
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE);
|
|
715
|
+
break;
|
|
716
|
+
|
|
717
|
+
case BLEND_LIGHTEST:
|
|
718
|
+
glBlendEquationSeparate(GL_MAX, GL_FUNC_ADD);
|
|
719
|
+
glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ONE);
|
|
720
|
+
break;
|
|
721
|
+
|
|
722
|
+
case BLEND_DARKEST:
|
|
723
|
+
glBlendEquationSeparate(GL_MIN, GL_FUNC_ADD);
|
|
724
|
+
glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ONE);
|
|
725
|
+
break;
|
|
726
|
+
|
|
727
|
+
case BLEND_EXCLUSION:
|
|
728
|
+
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
|
|
729
|
+
glBlendFuncSeparate(
|
|
730
|
+
GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_ONE, GL_ONE);
|
|
731
|
+
break;
|
|
732
|
+
|
|
733
|
+
case BLEND_MULTIPLY:
|
|
734
|
+
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
|
|
735
|
+
glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ONE, GL_ONE);
|
|
736
|
+
break;
|
|
737
|
+
|
|
738
|
+
case BLEND_SCREEN:
|
|
739
|
+
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
|
|
740
|
+
glBlendFuncSeparate(GL_ONE_MINUS_DST_COLOR, GL_ONE, GL_ONE, GL_ONE);
|
|
741
|
+
break;
|
|
742
|
+
|
|
743
|
+
case BLEND_REPLACE:
|
|
744
|
+
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
|
|
745
|
+
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO);
|
|
746
|
+
break;
|
|
747
|
+
|
|
748
|
+
default:
|
|
749
|
+
argument_error(__FILE__, __LINE__, "unknown blend mode");
|
|
750
|
+
break;
|
|
751
|
+
}
|
|
752
|
+
OpenGL_check_error(__FILE__, __LINE__);
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
}// Rays
|