rays 0.1.11 → 0.1.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (168) hide show
  1. checksums.yaml +5 -5
  2. data/.doc/ext/rays/bitmap.cpp +22 -76
  3. data/.doc/ext/rays/bounds.cpp +95 -125
  4. data/.doc/ext/rays/camera.cpp +88 -0
  5. data/.doc/ext/rays/color.cpp +223 -45
  6. data/.doc/ext/rays/color_space.cpp +146 -46
  7. data/.doc/ext/rays/defs.cpp +183 -0
  8. data/.doc/ext/rays/font.cpp +69 -21
  9. data/.doc/ext/rays/image.cpp +26 -37
  10. data/.doc/ext/rays/matrix.cpp +186 -29
  11. data/.doc/ext/rays/native.cpp +14 -8
  12. data/.doc/ext/rays/noise.cpp +53 -0
  13. data/.doc/ext/rays/painter.cpp +187 -292
  14. data/.doc/ext/rays/point.cpp +96 -77
  15. data/.doc/ext/rays/polygon.cpp +313 -0
  16. data/.doc/ext/rays/polygon_line.cpp +96 -0
  17. data/.doc/ext/rays/polyline.cpp +167 -0
  18. data/.doc/ext/rays/rays.cpp +103 -12
  19. data/.doc/ext/rays/shader.cpp +83 -9
  20. data/LICENSE +21 -0
  21. data/README.md +1 -1
  22. data/Rakefile +24 -9
  23. data/VERSION +1 -1
  24. data/ext/rays/bitmap.cpp +22 -80
  25. data/ext/rays/bounds.cpp +100 -128
  26. data/ext/rays/camera.cpp +94 -0
  27. data/ext/rays/color.cpp +231 -51
  28. data/ext/rays/color_space.cpp +149 -47
  29. data/ext/rays/defs.cpp +183 -0
  30. data/ext/rays/defs.h +26 -2
  31. data/ext/rays/extconf.rb +2 -3
  32. data/ext/rays/font.cpp +74 -24
  33. data/ext/rays/image.cpp +28 -40
  34. data/ext/rays/matrix.cpp +198 -30
  35. data/ext/rays/native.cpp +14 -8
  36. data/ext/rays/noise.cpp +55 -0
  37. data/ext/rays/painter.cpp +203 -298
  38. data/ext/rays/point.cpp +105 -81
  39. data/ext/rays/polygon.cpp +329 -0
  40. data/ext/rays/polygon_line.cpp +99 -0
  41. data/ext/rays/polyline.cpp +176 -0
  42. data/ext/rays/rays.cpp +103 -13
  43. data/ext/rays/shader.cpp +84 -9
  44. data/include/rays.h +10 -2
  45. data/include/rays/bitmap.h +14 -26
  46. data/include/rays/bounds.h +21 -4
  47. data/include/rays/camera.h +49 -0
  48. data/include/rays/color.h +25 -14
  49. data/include/rays/color_space.h +15 -10
  50. data/include/rays/coord.h +114 -0
  51. data/include/rays/debug.h +22 -0
  52. data/include/rays/defs.h +36 -0
  53. data/include/rays/exception.h +6 -2
  54. data/include/rays/font.h +4 -4
  55. data/include/rays/image.h +12 -18
  56. data/include/rays/matrix.h +50 -24
  57. data/include/rays/noise.h +42 -0
  58. data/include/rays/opengl.h +2 -50
  59. data/include/rays/painter.h +89 -93
  60. data/include/rays/point.h +44 -51
  61. data/include/rays/polygon.h +198 -0
  62. data/include/rays/polyline.h +71 -0
  63. data/include/rays/rays.h +3 -0
  64. data/include/rays/ruby.h +7 -1
  65. data/include/rays/ruby/bounds.h +1 -1
  66. data/include/rays/ruby/camera.h +41 -0
  67. data/include/rays/ruby/color.h +1 -1
  68. data/include/rays/ruby/color_space.h +1 -1
  69. data/include/rays/ruby/font.h +1 -1
  70. data/include/rays/ruby/matrix.h +1 -1
  71. data/include/rays/ruby/point.h +1 -1
  72. data/include/rays/ruby/polygon.h +52 -0
  73. data/include/rays/ruby/polyline.h +41 -0
  74. data/include/rays/ruby/rays.h +8 -0
  75. data/include/rays/ruby/shader.h +1 -1
  76. data/include/rays/shader.h +36 -8
  77. data/lib/rays.rb +7 -2
  78. data/lib/rays/bitmap.rb +0 -15
  79. data/lib/rays/bounds.rb +17 -23
  80. data/lib/rays/camera.rb +21 -0
  81. data/lib/rays/color.rb +20 -47
  82. data/lib/rays/color_space.rb +13 -13
  83. data/lib/rays/image.rb +3 -7
  84. data/lib/rays/matrix.rb +28 -0
  85. data/lib/rays/module.rb +4 -19
  86. data/lib/rays/painter.rb +78 -93
  87. data/lib/rays/point.rb +13 -21
  88. data/lib/rays/polygon.rb +58 -0
  89. data/lib/rays/polygon_line.rb +36 -0
  90. data/lib/rays/polyline.rb +32 -0
  91. data/lib/rays/shader.rb +20 -1
  92. data/rays.gemspec +5 -7
  93. data/src/bitmap.h +36 -0
  94. data/src/bounds.cpp +74 -11
  95. data/src/color.cpp +58 -23
  96. data/src/color_space.cpp +52 -34
  97. data/src/color_space.h +22 -0
  98. data/src/coord.cpp +170 -0
  99. data/src/coord.h +35 -0
  100. data/src/font.cpp +118 -0
  101. data/src/font.h +64 -0
  102. data/src/frame_buffer.cpp +37 -71
  103. data/src/frame_buffer.h +4 -4
  104. data/src/image.cpp +172 -98
  105. data/src/image.h +25 -0
  106. data/src/ios/bitmap.h +21 -0
  107. data/src/ios/bitmap.mm +129 -110
  108. data/src/ios/camera.mm +236 -0
  109. data/src/ios/font.mm +50 -62
  110. data/src/ios/helper.h +2 -2
  111. data/src/ios/opengl.mm +19 -4
  112. data/src/ios/rays.mm +3 -0
  113. data/src/matrix.cpp +111 -26
  114. data/src/matrix.h +30 -0
  115. data/src/noise.cpp +74 -0
  116. data/src/opengl.cpp +9 -27
  117. data/src/opengl.h +37 -0
  118. data/src/osx/bitmap.h +21 -0
  119. data/src/osx/bitmap.mm +129 -110
  120. data/src/osx/camera.mm +236 -0
  121. data/src/osx/font.mm +49 -62
  122. data/src/osx/helper.h +2 -2
  123. data/src/osx/opengl.mm +19 -83
  124. data/src/osx/rays.mm +3 -0
  125. data/src/painter.cpp +845 -671
  126. data/src/painter.h +24 -0
  127. data/src/point.cpp +140 -119
  128. data/src/polygon.cpp +1266 -0
  129. data/src/polygon.h +32 -0
  130. data/src/polyline.cpp +160 -0
  131. data/src/polyline.h +69 -0
  132. data/src/render_buffer.cpp +11 -4
  133. data/src/render_buffer.h +2 -2
  134. data/src/shader.cpp +163 -106
  135. data/src/shader.h +38 -0
  136. data/src/shader_program.cpp +533 -0
  137. data/src/{program.h → shader_program.h} +28 -16
  138. data/src/shader_source.cpp +140 -0
  139. data/src/shader_source.h +52 -0
  140. data/src/texture.cpp +136 -160
  141. data/src/texture.h +65 -0
  142. data/src/win32/bitmap.cpp +62 -52
  143. data/src/win32/font.cpp +11 -13
  144. data/src/win32/font.h +24 -0
  145. data/src/win32/gdi.h +6 -6
  146. data/test/helper.rb +0 -3
  147. data/test/test_bitmap.rb +31 -7
  148. data/test/test_bounds.rb +36 -0
  149. data/test/test_color.rb +59 -19
  150. data/test/test_color_space.rb +95 -0
  151. data/test/test_font.rb +5 -0
  152. data/test/test_image.rb +24 -20
  153. data/test/test_matrix.rb +106 -0
  154. data/test/test_painter.rb +157 -51
  155. data/test/test_painter_shape.rb +102 -0
  156. data/test/test_point.rb +29 -0
  157. data/test/test_polygon.rb +234 -0
  158. data/test/test_polygon_line.rb +167 -0
  159. data/test/test_polyline.rb +171 -0
  160. data/test/test_shader.rb +9 -9
  161. metadata +102 -70
  162. data/.doc/ext/rays/texture.cpp +0 -138
  163. data/ext/rays/texture.cpp +0 -149
  164. data/include/rays/ruby/texture.h +0 -41
  165. data/include/rays/texture.h +0 -71
  166. data/lib/rays/texture.rb +0 -24
  167. data/src/program.cpp +0 -648
  168. data/test/test_texture.rb +0 -27
@@ -4,6 +4,7 @@
4
4
 
5
5
  #import <Foundation/Foundation.h>
6
6
  #include "rays/exception.h"
7
+ #include "../opengl.h"
7
8
 
8
9
 
9
10
  namespace Rays
@@ -27,6 +28,8 @@ namespace Rays
27
28
  rays_error(__FILE__, __LINE__, "Rays::init(): already initialized.");
28
29
 
29
30
  global::pool = [[NSAutoreleasePool alloc] init];
31
+
32
+ OpenGL_set_context(get_offscreen_context());
30
33
  }
31
34
 
32
35
  void
@@ -1,22 +1,28 @@
1
- #include "rays/painter.h"
1
+ #include "painter.h"
2
2
 
3
3
 
4
4
  #include <math.h>
5
- #include <list>
5
+ #include <assert.h>
6
+ #include <memory>
7
+ #include <vector>
6
8
  #include <algorithm>
7
- #include <boost/scoped_array.hpp>
9
+ #include <glm/gtc/matrix_transform.hpp>
8
10
  #include "rays/exception.h"
9
11
  #include "rays/point.h"
10
12
  #include "rays/bounds.h"
11
13
  #include "rays/color.h"
12
- #include "rays/matrix.h"
13
- #include "rays/font.h"
14
- #include "rays/bitmap.h"
15
- #include "rays/texture.h"
16
- #include "rays/image.h"
17
- #include "rays/shader.h"
14
+ #include "rays/debug.h"
15
+ #include "opengl.h"
16
+ #include "matrix.h"
17
+ #include "polygon.h"
18
+ #include "bitmap.h"
19
+ #include "texture.h"
20
+ #include "image.h"
21
+ #include "font.h"
18
22
  #include "frame_buffer.h"
19
- #include "program.h"
23
+ #include "shader.h"
24
+ #include "shader_program.h"
25
+ #include "shader_source.h"
20
26
 
21
27
 
22
28
  namespace Rays
@@ -35,152 +41,528 @@ namespace Rays
35
41
  };// ColorType
36
42
 
37
43
 
38
- static const float PI = M_PI;
44
+ struct State
45
+ {
39
46
 
40
- static const float PI_2 = PI * 2;
47
+ Color background, colors[2];
41
48
 
49
+ coord stroke_width;
42
50
 
43
- struct Attributes
44
- {
51
+ CapType stroke_cap;
45
52
 
46
- Bounds clip;
53
+ JoinType stroke_join;
47
54
 
48
- Color background, colors[2];
55
+ coord miter_limit;
56
+
57
+ uint nsegment;
58
+
59
+ Bounds clip;
49
60
 
50
61
  Font font;
51
62
 
63
+ Shader shader;
64
+
52
65
  void init ()
53
66
  {
54
- clip .reset(-1);
55
67
  background .reset(0, 0);
56
68
  colors[FILL] .reset(1, 1);
57
69
  colors[STROKE] .reset(1, 0);
70
+ stroke_width = 0;
71
+ stroke_cap = CAP_DEFAULT;
72
+ stroke_join = JOIN_DEFAULT;
73
+ miter_limit = JOIN_DEFAULT_MITER_LIMIT;
74
+ nsegment = 0;
75
+ clip .reset(-1);
58
76
  font = default_font();
77
+ shader = Shader();
78
+ }
79
+
80
+ bool has_color ()
81
+ {
82
+ return colors[FILL] || colors[STROKE];
59
83
  }
60
84
 
61
- };// Attributes
85
+ };// State
62
86
 
63
87
 
64
- struct Painter::Data
88
+ struct TextureInfo
65
89
  {
66
90
 
67
- Bounds viewport;
91
+ const Texture& texture;
68
92
 
69
- Attributes attrs;
93
+ Coord2 texcoord_min, texcoord_max;
70
94
 
71
- Program program;
95
+ TextureInfo (
96
+ const Texture& texture,
97
+ coord x_min, coord y_min,
98
+ coord x_max, coord y_max)
99
+ : texture(texture)
100
+ {
101
+ texcoord_min.reset(x_min, y_min);
102
+ texcoord_max.reset(x_max, y_max);
103
+ }
72
104
 
73
- std::list<Attributes> attrs_stack;
105
+ operator bool () const
106
+ {
107
+ return
108
+ texture &&
109
+ texcoord_min.x < texcoord_max.x &&
110
+ texcoord_min.x < texcoord_max.y;
111
+ }
74
112
 
75
- bool painting;
113
+ bool operator ! () const
114
+ {
115
+ return !operator bool();
116
+ }
76
117
 
77
- GLenum prev_matrix_mode;
118
+ };// TextureInfo
78
119
 
79
- GLuint current_texture;
80
120
 
81
- Image text_image;
121
+ struct OpenGLState
122
+ {
123
+
124
+ GLint viewport[4];
125
+
126
+ GLclampf color_clear[4];
127
+
128
+ GLboolean scissor_test;
129
+ GLint scissor_box[4];
130
+
131
+ GLboolean blend;
132
+ GLint blend_src_factor, blend_dst_factor;
133
+
134
+ GLint framebuffer_binding;
135
+
136
+ void push ()
137
+ {
138
+ glGetIntegerv(GL_VIEWPORT, viewport);
139
+
140
+ glGetFloatv(GL_COLOR_CLEAR_VALUE, color_clear);
141
+
142
+ glGetBooleanv(GL_SCISSOR_TEST, &scissor_test);
143
+ glGetIntegerv(GL_SCISSOR_BOX, scissor_box);
144
+
145
+ glGetBooleanv(GL_BLEND, &blend);
146
+ glGetIntegerv(GL_BLEND_SRC_ALPHA, &blend_src_factor);
147
+ glGetIntegerv(GL_BLEND_DST_ALPHA, &blend_dst_factor);
148
+
149
+ glGetIntegerv(GL_FRAMEBUFFER_BINDING, &framebuffer_binding);
150
+ }
151
+
152
+ void pop ()
153
+ {
154
+ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
155
+
156
+ glClearColor(
157
+ color_clear[0], color_clear[1], color_clear[2], color_clear[3]);
158
+
159
+ enable(GL_SCISSOR_TEST, scissor_test);
160
+ glScissor(scissor_box[0], scissor_box[1], scissor_box[2], scissor_box[3]);
161
+
162
+ enable(GL_BLEND, blend);
163
+ glBlendFunc(blend_src_factor, blend_dst_factor);
164
+
165
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_binding);
166
+ }
167
+
168
+ private:
169
+
170
+ void enable(GLenum type, GLboolean value)
171
+ {
172
+ if (value)
173
+ glEnable(type);
174
+ else
175
+ glDisable(type);
176
+ }
177
+
178
+ };// OpenGLState
179
+
180
+
181
+ class DefaultIndices
182
+ {
183
+
184
+ public:
185
+
186
+ void resize (size_t size)
187
+ {
188
+ indices.reserve(size);
189
+ while (indices.size() < size)
190
+ indices.emplace_back(indices.size());
191
+ }
192
+
193
+ void clear ()
194
+ {
195
+ decltype(indices)().swap(indices);
196
+ }
197
+
198
+ const uint* get () const
199
+ {
200
+ return &indices[0];
201
+ }
202
+
203
+ private:
204
+
205
+ std::vector<uint> indices;
206
+
207
+ };// DefaultIndices
208
+
209
+
210
+ template <typename COORD>
211
+ static GLenum get_gl_type ();
212
+
213
+ template <>
214
+ GLenum
215
+ get_gl_type<float> ()
216
+ {
217
+ return GL_FLOAT;
218
+ }
219
+
220
+ static const Shader&
221
+ get_default_shader_for_shape ()
222
+ {
223
+ static const Shader SHADER(
224
+ "varying vec4 " VARYING_COLOR ";"
225
+ "void main ()"
226
+ "{"
227
+ " gl_FragColor = v_Color;"
228
+ "}");
229
+ return SHADER;
230
+ }
231
+
232
+ static const Shader&
233
+ get_default_shader_for_color_texture ()
234
+ {
235
+ static const Shader SHADER(
236
+ "varying vec4 " VARYING_TEXCOORD ";"
237
+ "varying vec4 " VARYING_COLOR ";"
238
+ "vec4 sampleTexture(vec2);"
239
+ "void main ()"
240
+ "{"
241
+ " vec4 color = sampleTexture(" VARYING_TEXCOORD ".xy);"
242
+ " gl_FragColor = v_Color * color;"
243
+ "}");
244
+ return SHADER;
245
+ }
246
+
247
+ static const Shader&
248
+ get_default_shader_for_alpha_texture ()
249
+ {
250
+ static const Shader SHADER(
251
+ "varying vec4 " VARYING_TEXCOORD ";"
252
+ "varying vec4 " VARYING_COLOR ";"
253
+ "vec4 sampleTexture(vec2);"
254
+ "void main ()"
255
+ "{"
256
+ " vec4 color = sampleTexture(" VARYING_TEXCOORD ".xy);"
257
+ " gl_FragColor = vec4(v_Color.rgb, color.a);"
258
+ "}");
259
+ return SHADER;
260
+ }
261
+
262
+
263
+ struct Painter::Data
264
+ {
265
+
266
+ bool painting = false;
267
+
268
+ float pixel_density = 1;
269
+
270
+ Bounds viewport;
271
+
272
+ State state;
273
+
274
+ std::vector<State> state_stack;
275
+
276
+ Matrix position_matrix;
277
+
278
+ std::vector<Matrix> position_matrix_stack;
82
279
 
83
280
  FrameBuffer frame_buffer;
84
281
 
85
- float scale_factor;
282
+ Image text_image;
283
+
284
+ OpenGLState opengl_state;
86
285
 
87
- mutable Matrix matrix_tmp;
286
+ DefaultIndices default_indices;
88
287
 
89
288
  Data ()
90
- : painting(false), prev_matrix_mode(0), current_texture(0),
91
- text_image(1, 1, GRAY, true), scale_factor(1)
92
289
  {
93
- attrs.init();
290
+ state.init();
291
+ }
292
+
293
+ void set_pixel_density (float density)
294
+ {
295
+ if (density <= 0)
296
+ argument_error(__FILE__, __LINE__, "invalid pixel_density.");
297
+
298
+ this->pixel_density = density;
299
+ text_image = Image();
94
300
  }
95
301
 
96
302
  void update_clip ()
97
303
  {
98
- if (attrs.clip)
304
+ const Bounds& clip = state.clip;
305
+ if (clip)
99
306
  {
307
+ coord y = frame_buffer ? clip.y : viewport.h - (clip.y + clip.h);
100
308
  glEnable(GL_SCISSOR_TEST);
101
309
  glScissor(
102
- attrs.clip.x,
103
- viewport.height - attrs.clip.height - attrs.clip.y,
104
- attrs.clip.width,
105
- attrs.clip.height);
310
+ pixel_density * clip.x,
311
+ pixel_density * y,
312
+ pixel_density * clip.width,
313
+ pixel_density * clip.height);
106
314
  }
107
315
  else
108
316
  {
109
317
  glDisable(GL_SCISSOR_TEST);
110
318
  }
111
319
 
112
- check_error(__FILE__, __LINE__);
320
+ OpenGL_check_error(__FILE__, __LINE__);
113
321
  }
114
322
 
115
- bool use_color (ColorType type)
323
+ bool get_color (Color* color, ColorType type)
116
324
  {
117
- const Color& c = attrs.colors[type];
118
- if (c.alpha <= 0) return false;
325
+ const Color& c = state.colors[type];
326
+ if (!c) return false;
119
327
 
120
- glColor4f(c.red, c.green, c.blue, c.alpha);
328
+ *color = c;
121
329
  return true;
122
330
  }
123
331
 
124
- void draw_shape (
125
- GLenum mode,
126
- int nindices, const uint* indices,
127
- int vertex_size, const coord* vertices,
128
- const coord* tex_coords = NULL, const Texture* texture = NULL)
332
+ void draw_polygon (
333
+ GLenum mode, const Color& color,
334
+ const Coord3* points, size_t npoints,
335
+ const uint* indices = NULL, size_t nindices = 0,
336
+ const Coord3* texcoords = NULL,
337
+ const Shader& default_shader = get_default_shader_for_shape(),
338
+ const TextureInfo* texinfo = NULL)
129
339
  {
130
- if (nindices <= 0 || !indices || !vertices)
340
+ if (!points || npoints <= 0)
131
341
  argument_error(__FILE__, __LINE__);
132
342
 
133
343
  if (!painting)
134
344
  invalid_state_error(__FILE__, __LINE__, "'painting' should be true.");
135
345
 
136
- bool use_texture = texture && tex_coords;
346
+ if (!indices || nindices <= 0)
347
+ {
348
+ default_indices.resize(npoints);
349
+ indices = default_indices.get();
350
+ nindices = npoints;
351
+ }
137
352
 
138
- if (use_texture)
353
+ if (!texcoords)
354
+ texcoords = points;
355
+
356
+ const ShaderProgram* program = Shader_get_program(state.shader);
357
+ if (!program || !*program)
139
358
  {
359
+ program = Shader_get_program(default_shader);
360
+ if (!program || !*program) return;
361
+ }
362
+
363
+ ShaderProgram_activate(*program);
364
+ apply_builtin_uniforms(*program, texinfo);
365
+
366
+ GLint a_position = glGetAttribLocation(program->id(), ATTRIB_POSITION);
367
+ GLint a_texcoord = glGetAttribLocation(program->id(), ATTRIB_TEXCOORD);
368
+ GLint a_color = glGetAttribLocation(program->id(), ATTRIB_COLOR);
369
+ if (a_position < 0 || a_texcoord < 0 || a_color < 0)
370
+ opengl_error(__FILE__, __LINE__);
371
+
372
+ setup_vertices(
373
+ points, npoints, texcoords, color, a_position, a_texcoord, a_color);
374
+ //activate_texture(texture);
375
+
376
+ glDrawElements(mode, (GLsizei) nindices, GL_UNSIGNED_INT, indices);
377
+ OpenGL_check_error(__FILE__, __LINE__);
378
+
379
+ //deactivate_texture(texture);
380
+ cleanup_vertices(a_position, a_texcoord);
381
+
382
+ ShaderProgram_deactivate();
383
+ }
384
+
385
+ private:
386
+
387
+ void apply_builtin_uniforms (
388
+ const ShaderProgram& program, const TextureInfo* texinfo)
389
+ {
390
+ GLint pos_matrix_loc =
391
+ glGetUniformLocation(program.id(), UNIFORM_POSITION_MATRIX);
392
+ if (pos_matrix_loc >= 0)
393
+ {
394
+ glUniformMatrix4fv(
395
+ pos_matrix_loc, 1, GL_FALSE, position_matrix.array);
396
+ OpenGL_check_error(__FILE__, __LINE__);
397
+ }
398
+
399
+ GLint texcoord_matrix_loc =
400
+ glGetUniformLocation(program.id(), UNIFORM_TEXCOORD_MATRIX);
401
+ if (texcoord_matrix_loc >= 0)
402
+ {
403
+ static const Matrix TEXCOORD_MATRIX(1);
404
+ glUniformMatrix4fv(
405
+ texcoord_matrix_loc, 1, GL_FALSE, TEXCOORD_MATRIX.array);
406
+ OpenGL_check_error(__FILE__, __LINE__);
407
+ }
408
+
409
+ apply_texture_uniforms(program, texinfo);
410
+ }
411
+
412
+ void apply_texture_uniforms (
413
+ const ShaderProgram& program, const TextureInfo* texinfo)
414
+ {
415
+ if (!texinfo || !*texinfo) return;
416
+
417
+ const Texture& texture = texinfo->texture;
418
+
419
+ GLint texture_loc =
420
+ glGetUniformLocation(program.id(), UNIFORM_TEXTURE);
421
+ if (texture_loc >= 0)
422
+ {
423
+ glActiveTexture(GL_TEXTURE0);
424
+ glBindTexture(GL_TEXTURE_2D, texture.id());
425
+
426
+ glUniform1i(texture_loc, 0);
427
+ OpenGL_check_error(__FILE__, __LINE__);
428
+ }
429
+
430
+ GLint size_loc =
431
+ glGetUniformLocation(program.id(), UNIFORM_TEXTURE_SIZE);
432
+ if (size_loc >= 0)
433
+ {
434
+ glUniform2f(
435
+ size_loc, texture.reserved_width(), texture.reserved_height());
436
+ OpenGL_check_error(__FILE__, __LINE__);
437
+ }
438
+
439
+ GLint min_loc =
440
+ glGetUniformLocation(program.id(), UNIFORM_TEXCOORD_MIN);
441
+ if (min_loc >= 0)
442
+ {
443
+ glUniform2fv(min_loc, 1, texinfo->texcoord_min.array);
444
+ OpenGL_check_error(__FILE__, __LINE__);
445
+ }
446
+
447
+ GLint max_loc =
448
+ glGetUniformLocation(program.id(), UNIFORM_TEXCOORD_MAX);
449
+ if (max_loc >= 0)
450
+ {
451
+ glUniform2fv(max_loc, 1, texinfo->texcoord_max.array);
452
+ OpenGL_check_error(__FILE__, __LINE__);
453
+ }
454
+ }
455
+
456
+ void setup_vertices (
457
+ const Coord3* points, size_t npoints,
458
+ const Coord3* texcoords, const Color& color,
459
+ GLuint a_position, GLuint a_texcoord, GLuint a_color)
460
+ {
461
+ assert(points && npoints >= 0 && texcoords);
462
+
463
+ glEnableVertexAttribArray(a_position);
464
+ glVertexAttribPointer(
465
+ a_position, Coord3::SIZE, get_gl_type<coord>(),
466
+ GL_FALSE, sizeof(Coord3), points);
467
+ OpenGL_check_error(__FILE__, __LINE__);
468
+
469
+ glEnableVertexAttribArray(a_texcoord);
470
+ glVertexAttribPointer(
471
+ a_texcoord, Coord3::SIZE, get_gl_type<coord>(),
472
+ GL_FALSE, sizeof(Coord3), texcoords);
473
+ OpenGL_check_error(__FILE__, __LINE__);
474
+
475
+ glVertexAttrib4fv(a_color, color.array);
476
+ }
477
+
478
+ void cleanup_vertices (GLint a_position, GLint a_texcoord)
479
+ {
480
+ glDisableVertexAttribArray(a_position);
481
+ glDisableVertexAttribArray(a_texcoord);
482
+ OpenGL_check_error(__FILE__, __LINE__);
483
+ }
484
+
485
+ void activate_texture (const Texture* texture)
486
+ {
487
+ if (!texture)
488
+ {
489
+ glDisable(GL_TEXTURE_2D);
490
+ return;
491
+ }
492
+
140
493
  if (!*texture)
141
494
  argument_error(__FILE__, __LINE__, "invalid texture.");
142
495
 
143
496
  GLuint id = texture->id();
144
- if (id != current_texture)
145
- {
497
+ if (id != get_current_texture_id())
146
498
  glBindTexture(GL_TEXTURE_2D, id);
147
- current_texture = id;
148
- }
149
499
 
150
500
  glEnable(GL_TEXTURE_2D);
501
+ }
151
502
 
152
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
153
- glTexCoordPointer(2, GL_FLOAT, 0, tex_coords);
503
+ GLuint get_current_texture_id ()
504
+ {
505
+ GLint id = 0;
506
+ glGetIntegerv(GL_TEXTURE_BINDING_2D, &id);
507
+ return (GLuint) id;
154
508
  }
155
- else
509
+
510
+ void deactivate_texture (const Texture* texture)
156
511
  {
512
+ if (!texture) return;
513
+
157
514
  glDisable(GL_TEXTURE_2D);
158
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
159
515
  }
160
516
 
161
- glEnableClientState(GL_VERTEX_ARRAY);
162
- glVertexPointer(vertex_size, GL_FLOAT, 0, vertices);
517
+ };// Painter::Data
163
518
 
164
- glDrawElements(mode, nindices, GL_UNSIGNED_INT, indices);
165
519
 
166
- glDisableClientState(GL_VERTEX_ARRAY);
167
- if (use_texture)
168
- {
169
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
170
- glDisable(GL_TEXTURE_2D);
171
- }
520
+ static void
521
+ draw_polygon (
522
+ Painter* painter,
523
+ const GLenum* modes,
524
+ coord offset_x, coord offset_y,
525
+ bool nofill, bool nostroke,
526
+ const Coord3* points, size_t npoints,
527
+ const uint* indices = NULL, size_t nindices = 0,
528
+ const Coord3* texcoords = NULL,
529
+ const Shader& default_shader = get_default_shader_for_shape(),
530
+ const TextureInfo* texinfo = NULL)
531
+ {
532
+ assert(painter);
533
+
534
+ bool offset = offset_x != 0 || offset_y != 0;
535
+ if (offset)
536
+ {
537
+ painter->push_matrix();
538
+ painter->translate(offset_x, offset_y);
172
539
  }
173
540
 
174
- };// Painter::Data
541
+ Color color;
542
+ for (int type = COLOR_TYPE_BEGIN; type < COLOR_TYPE_END; ++type)
543
+ {
544
+ if ((nofill && type == FILL) || (nostroke && type == STROKE))
545
+ continue;
546
+
547
+ if (!painter->self->get_color(&color, (ColorType) type))
548
+ continue;
549
+
550
+ painter->self->draw_polygon(
551
+ modes[type], color, points, npoints, indices, nindices, texcoords,
552
+ default_shader, texinfo);
553
+ }
175
554
 
555
+ if (offset)
556
+ painter->pop_matrix();
557
+ }
176
558
 
177
559
  void
178
- set_painter_scale_factor (Painter* painter, float factor)
560
+ Painter_draw_polygon (
561
+ Painter* painter, GLenum mode, const Color& color,
562
+ const Coord3* points, size_t npoints,
563
+ const uint* indices, size_t nindices)
179
564
  {
180
- if (!painter)
181
- argument_error(__FILE__, __LINE__, "invalid texture.");
182
-
183
- painter->self->scale_factor = factor;
565
+ painter->self->draw_polygon(mode, color, points, npoints, indices, nindices);
184
566
  }
185
567
 
186
568
 
@@ -193,53 +575,57 @@ namespace Rays
193
575
  }
194
576
 
195
577
  void
196
- Painter::canvas (coord x, coord y, coord width, coord height)
578
+ Painter::canvas (
579
+ coord x, coord y, coord width, coord height, float pixel_density)
197
580
  {
198
- canvas(Bounds(x, y, -100, width, height, 200));
581
+ canvas(Bounds(x, y, -100, width, height, 200), pixel_density);
199
582
  }
200
583
 
201
584
  void
202
- Painter::canvas (coord x, coord y, coord z, coord width, coord height, coord depth)
585
+ Painter::canvas (
586
+ coord x, coord y, coord z, coord width, coord height, coord depth,
587
+ float pixel_density)
203
588
  {
204
- canvas(Bounds(x, y, z, width, height, depth));
589
+ canvas(Bounds(x, y, z, width, height, depth), pixel_density);
205
590
  }
206
591
 
207
592
  void
208
- Painter::canvas (const Bounds& bounds)
593
+ Painter::canvas (const Bounds& viewport, float pixel_density)
209
594
  {
210
- if (!bounds)
595
+ if (!viewport)
211
596
  argument_error(__FILE__, __LINE__);
212
597
 
213
598
  if (self->painting)
214
- invalid_state_error(__FILE__, __LINE__, "self->painting should be false.");
599
+ invalid_state_error(__FILE__, __LINE__, "painting flag should be false.");
215
600
 
216
- self->viewport = bounds;
601
+ self->viewport = viewport;
602
+ self->set_pixel_density(pixel_density);
217
603
  }
218
604
 
219
605
  void
220
- Painter::bind (const Texture& texture)
606
+ Painter::bind (const Image& image)
221
607
  {
222
- if (!texture)
223
- argument_error(__FILE__, __LINE__, "invalid texture.");
608
+ if (!image)
609
+ argument_error(__FILE__, __LINE__, "invalid image.");
224
610
 
225
611
  if (self->painting)
226
- invalid_state_error(__FILE__, __LINE__, "self->painting should be false.");
612
+ invalid_state_error(__FILE__, __LINE__, "painting flag should be false.");
227
613
 
228
- FrameBuffer fb(texture);
614
+ FrameBuffer fb(Image_get_texture(image));
229
615
  if (!fb)
230
616
  rays_error(__FILE__, __LINE__, "invalid frame buffer.");
231
617
 
232
618
  unbind();
233
619
 
234
620
  self->frame_buffer = fb;
235
- canvas(0, 0, fb.width(), fb.height());
621
+ canvas(0, 0, image.width(), image.height(), image.pixel_density());
236
622
  }
237
623
 
238
624
  void
239
625
  Painter::unbind ()
240
626
  {
241
627
  if (self->painting)
242
- invalid_state_error(__FILE__, __LINE__, "self->painting should be true.");
628
+ invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
243
629
 
244
630
  self->frame_buffer = FrameBuffer();
245
631
  }
@@ -250,104 +636,74 @@ namespace Rays
250
636
  return self->viewport;
251
637
  }
252
638
 
639
+ float
640
+ Painter::pixel_density () const
641
+ {
642
+ return self->pixel_density;
643
+ }
253
644
 
254
645
  void
255
646
  Painter::begin ()
256
647
  {
257
648
  if (self->painting)
258
- invalid_state_error(__FILE__, __LINE__, "self->painting should be false.");
649
+ invalid_state_error(__FILE__, __LINE__, "painting flag should be false.");
259
650
 
260
- FrameBuffer& fb = self->frame_buffer;
261
- if (fb) bind_frame_buffer(fb.id());
651
+ self->opengl_state.push();
262
652
 
263
- push_attr();
264
- push_shader();
653
+ //glEnable(GL_CULL_FACE);
654
+ glEnable(GL_BLEND);
655
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
656
+ OpenGL_check_error(__FILE__, __LINE__);
657
+
658
+ FrameBuffer& fb = self->frame_buffer;
659
+ if (fb) FrameBuffer_bind(fb.id());
265
660
 
266
661
  const Bounds& vp = self->viewport;
267
- float scale = self->scale_factor;
662
+ float density = self->pixel_density;
268
663
  glViewport(
269
- (int) vp.x, (int) vp.y,
270
- (int) vp.width * scale, (int) vp.height * scale);
664
+ (int) (vp.x * density), (int) (vp.y * density),
665
+ (int) (vp.width * density), (int) (vp.height * density));
666
+ OpenGL_check_error(__FILE__, __LINE__);
271
667
 
272
668
  coord x1 = vp.x, x2 = vp.x + vp.width;
273
669
  coord y1 = vp.y, y2 = vp.y + vp.height;
274
670
  coord z1 = vp.z, z2 = vp.z + vp.depth;
275
671
  if (z1 == 0 && z2 == 0) {z1 = -100; z2 = 200;}
276
- if (!fb) std::swap(y1, y2);
277
-
278
- glGetIntegerv(GL_MATRIX_MODE, (GLint*) &self->prev_matrix_mode);
279
-
280
- glMatrixMode(GL_PROJECTION);
281
- glPushMatrix();
282
- glLoadIdentity();
283
- glOrtho(x1, x2, y1, y2, z1, z2);
672
+ if (!fb) std::swap(y1, y2);
284
673
 
285
- glMatrixMode(GL_MODELVIEW);
286
- glPushMatrix();
287
- glLoadIdentity();
288
- glTranslatef(0.375f, 0.375f, 0);
674
+ self->position_matrix.reset(1);
675
+ self->position_matrix *= to_rays(glm::ortho(x1, x2, y1, y2));
676
+ //self->position_matrix.translate(0.375f, 0.375f);
289
677
 
290
- glMatrixMode(GL_TEXTURE);
291
- glPushMatrix();
292
- glLoadIdentity();
293
-
294
- #ifndef IOS
295
- glMatrixMode(GL_COLOR);
296
- glPushMatrix();
297
- glLoadIdentity();
298
- #endif
299
-
300
- glMatrixMode(GL_MODELVIEW);
301
-
302
- //glEnable(GL_CULL_FACE);
303
- glEnable(GL_BLEND);
304
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
305
-
306
- check_error(__FILE__, __LINE__);
678
+ self->update_clip();
307
679
 
308
680
  self->painting = true;
309
-
310
- no_clip();
311
681
  }
312
682
 
313
683
  void
314
684
  Painter::end ()
315
685
  {
316
686
  if (!self->painting)
317
- invalid_state_error(__FILE__, __LINE__, "self->painting should be true.");
318
-
319
- self->painting = false;
320
-
321
- glDisable(GL_BLEND);
322
- glDisable(GL_CULL_FACE);
323
-
324
- glMatrixMode(GL_PROJECTION);
325
- glPopMatrix();
326
-
327
- glMatrixMode(GL_MODELVIEW);
328
- glPopMatrix();
687
+ invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
329
688
 
330
- glMatrixMode(GL_TEXTURE);
331
- glPopMatrix();
689
+ if (!self->state_stack.empty())
690
+ invalid_state_error(__FILE__, __LINE__, "state stack is not empty.");
332
691
 
333
- #ifndef IOS
334
- glMatrixMode(GL_COLOR);
335
- glPopMatrix();
336
- #endif
692
+ if (!self->position_matrix_stack.empty())
693
+ invalid_state_error(__FILE__, __LINE__, "position matrix stack is not empty.");
337
694
 
338
- glMatrixMode(self->prev_matrix_mode);
339
-
340
- pop_shader();
341
- pop_attr();
695
+ self->painting = false;
696
+ self->opengl_state.pop();
697
+ self->default_indices.clear();
342
698
 
343
- //glFinish();
699
+ glFinish();
344
700
 
345
701
  if (self->frame_buffer)
346
702
  {
347
- unbind_frame_buffer();
703
+ FrameBuffer_unbind();
348
704
 
349
705
  Texture& tex = self->frame_buffer.texture();
350
- if (tex) tex.set_dirty(true);
706
+ if (tex) tex.set_modified();
351
707
  }
352
708
  }
353
709
 
@@ -355,388 +711,243 @@ namespace Rays
355
711
  Painter::clear ()
356
712
  {
357
713
  if (!self->painting)
358
- invalid_state_error(__FILE__, __LINE__, "self->painting should be true.");
714
+ invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
359
715
 
360
- const Color& c = self->attrs.background;
716
+ const Color& c = self->state.background;
361
717
  glClearColor(c.red, c.green, c.blue, c.alpha);
362
718
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
363
-
364
- check_error(__FILE__, __LINE__);
719
+ OpenGL_check_error(__FILE__, __LINE__);
365
720
  }
366
721
 
367
- void
368
- Painter::line (coord x1, coord y1, coord x2, coord y2)
722
+ static inline void
723
+ debug_draw_triangulation (
724
+ Painter* painter, const Polygon& polygon, const Color& color)
369
725
  {
370
- static const uint INDICES[] =
371
- {
372
- 0, 1
373
- };
726
+ #ifdef _DEBUG
727
+ assert(painter);
374
728
 
375
- Data* pself = self.get();
729
+ Color invert_color(
730
+ 1.f - color.red,
731
+ 1.f - color.green,
732
+ 1.f - color.blue);
376
733
 
377
- if (!pself->painting)
378
- invalid_state_error(__FILE__, __LINE__, "self->painting should be true.");
379
-
380
- if (!pself->use_color(STROKE))
381
- return;
382
-
383
- coord vertices[] =
734
+ Polygon::TrianglePointList triangles;
735
+ if (Polygon_triangulate(&triangles, polygon))
384
736
  {
385
- x1, y1,
386
- x2, y2
387
- };
388
-
389
- pself->draw_shape(GL_LINES, 2, INDICES, 2, vertices);
390
- }
391
-
392
- void
393
- Painter::line (const Point& p1, const Point& p2)
394
- {
395
- line(p1.x, p1.y, p2.x, p2.y);
737
+ for (size_t i = 0; i < triangles.size(); i += 3)
738
+ {
739
+ painter->self->draw_polygon(
740
+ GL_LINE_LOOP, invert_color, &triangles[i], 3);
741
+ }
742
+ }
743
+ #endif
396
744
  }
397
745
 
398
746
  void
399
- Painter::lines (const Coord2* points, size_t size)
747
+ Painter::polygon (const Polygon& polygon)
400
748
  {
401
- Data* pself = self.get();
402
-
403
- if (!pself->painting)
404
- invalid_state_error(__FILE__, __LINE__, "self->painting should be true.");
749
+ if (!self->painting)
750
+ invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
405
751
 
406
- if (!pself->use_color(STROKE))
752
+ if (!self->state.has_color())
407
753
  return;
408
754
 
409
- boost::scoped_array<uint> indices(new uint[size]);
410
- for (size_t i = 0; i < size; ++i)
411
- indices[i] = (uint) i;
412
-
413
- pself->draw_shape(GL_LINES, (int) size, indices.get(), 2, (coord*) points);
414
- }
415
-
416
- void
417
- Painter::lines (const Coord3* points, size_t size)
418
- {
419
- Data* pself = self.get();
420
-
421
- if (!pself->painting)
422
- invalid_state_error(__FILE__, __LINE__, "self->painting should be true.");
423
-
424
- if (!pself->use_color(STROKE))
425
- return;
755
+ Color color;
426
756
 
427
- boost::scoped_array<uint> indices(new uint[size]);
428
- boost::scoped_array<Coord2> vertices(new Coord2[size]);
429
- for (size_t i = 0; i < size; ++i)
757
+ if (self->get_color(&color, FILL))
430
758
  {
431
- indices[i] = (uint) i;
432
- vertices[i].reset(points[i].x, points[i].y);
759
+ Polygon_fill(polygon, this, color);
760
+ debug_draw_triangulation(this, polygon, color);
433
761
  }
434
762
 
435
- pself->draw_shape(
436
- GL_LINES, (int) size, indices.get(), 2, (coord*) vertices.get());
763
+ if (self->get_color(&color, STROKE))
764
+ Polygon_stroke(polygon, this, color);
437
765
  }
438
766
 
439
767
  void
440
- Painter::polygon (const Coord2* points, size_t size)
768
+ Painter::line (coord x1, coord y1, coord x2, coord y2)
441
769
  {
442
- Data* pself = self.get();
443
-
444
- if (!pself->painting)
445
- invalid_state_error(__FILE__, __LINE__, "self->painting should be true.");
446
-
447
- GLenum modes[] = {GL_TRIANGLE_FAN, GL_LINE_LOOP};
448
- boost::scoped_array<uint> indices;
449
-
450
- for (int type = COLOR_TYPE_BEGIN; type < COLOR_TYPE_END; ++type)
451
- {
452
- if (!pself->use_color((ColorType) type)) continue;
453
-
454
- if (!indices.get())
455
- {
456
- indices.reset(new uint[size]);
457
- for (size_t i = 0; i < size; ++i)
458
- indices[i] = (uint) i;
459
- }
460
-
461
- pself->draw_shape(
462
- modes[type], (int) size, indices.get(), 2, (coord*) points);
463
- }
770
+ polygon(create_line(x1, y1, x2, y2));
464
771
  }
465
772
 
466
773
  void
467
- Painter::polygon (const Coord3* points, size_t size)
774
+ Painter::line (const Point& p1, const Point& p2)
468
775
  {
469
- Data* pself = self.get();
470
-
471
- if (!pself->painting)
472
- invalid_state_error(__FILE__, __LINE__, "self->painting should be true.");
473
-
474
- GLenum modes[] = {GL_TRIANGLE_FAN, GL_LINE_LOOP};
475
- boost::scoped_array<uint> indices;
476
- boost::scoped_array<Coord2> vertices;
477
-
478
- for (int type = COLOR_TYPE_BEGIN; type < COLOR_TYPE_END; ++type)
479
- {
480
- if (!pself->use_color((ColorType) type)) continue;
481
-
482
- if (!indices.get())
483
- {
484
- indices.reset(new uint[size]);
485
- for (size_t i = 0; i < size; ++i)
486
- indices[i] = (uint) i;
487
- }
776
+ polygon(create_line(p1, p2));
777
+ }
488
778
 
489
- if (!vertices.get())
490
- {
491
- vertices.reset(new Coord2[size]);
492
- for (size_t i = 0; i < size; ++i)
493
- vertices[i].reset(points[i].x, points[i].y);
494
- }
779
+ void
780
+ Painter::line (const Point* points, size_t size, bool loop)
781
+ {
782
+ polygon(create_line(points, size, loop));
783
+ }
495
784
 
496
- pself->draw_shape(
497
- modes[type], (int) size, indices.get(), 2, (coord*) vertices.get());
498
- }
785
+ void
786
+ Painter::line (const Polyline& polyline)
787
+ {
788
+ polygon(create_line(polyline));
499
789
  }
500
790
 
501
791
  void
502
792
  Painter::rect (coord x, coord y, coord width, coord height, coord round)
503
793
  {
504
- rect(x, y, width, height, round, round);
794
+ polygon(create_rect(x, y, width, height, round, nsegment()));
505
795
  }
506
796
 
507
797
  void
508
798
  Painter::rect (
509
799
  coord x, coord y, coord width, coord height,
510
- coord round_width, coord round_height)
800
+ coord round_left_top, coord round_right_top,
801
+ coord round_left_bottom, coord round_right_bottom)
511
802
  {
512
- static const GLenum MODES[] = {GL_TRIANGLE_FAN, GL_LINE_LOOP};
513
- static const uint INDICES[] =
514
- {
515
- 0, 1, 2, 3
516
- };
517
-
518
- Data* pself = self.get();
519
-
520
- if (!pself->painting)
521
- invalid_state_error(__FILE__, __LINE__, "self->painting should be true.");
522
-
523
- if (width <= 0 || height <= 0) return;
524
-
525
- coord x2 = x + width - 1;
526
- coord y2 = y + height - 1;
527
-
528
- for (int type = COLOR_TYPE_BEGIN; type < COLOR_TYPE_END; ++type)
529
- {
530
- if (!pself->use_color((ColorType) type)) continue;
531
-
532
- coord xx = x2 + 1 - type;
533
- coord yy = y2 + 1 - type;
534
- coord vertices[] =
535
- {
536
- x, y,
537
- x, yy,
538
- xx, yy,
539
- xx, y
540
- };
541
-
542
- pself->draw_shape(MODES[type], 4, INDICES, 2, vertices);
543
- }
803
+ polygon(create_rect(
804
+ x, y, width, height,
805
+ round_left_top, round_right_top,
806
+ round_left_bottom, round_right_bottom,
807
+ nsegment()));
544
808
  }
545
809
 
546
810
  void
547
811
  Painter::rect (const Bounds& bounds, coord round)
548
812
  {
549
- rect(
550
- bounds.x, bounds.y, bounds.width, bounds.height,
551
- round);
813
+ polygon(create_rect(bounds, round, nsegment()));
552
814
  }
553
815
 
554
816
  void
555
- Painter::rect (const Bounds& bounds, coord round_width, coord round_height)
817
+ Painter::rect (
818
+ const Bounds& bounds,
819
+ coord round_left_top, coord round_right_top,
820
+ coord round_left_bottom, coord round_right_bottom)
556
821
  {
557
- rect(
558
- bounds.x, bounds.y, bounds.width, bounds.height,
559
- round_width, round_height);
822
+ polygon(create_rect(
823
+ bounds,
824
+ round_left_top, round_right_top,
825
+ round_left_bottom, round_right_bottom,
826
+ nsegment()));
560
827
  }
561
828
 
562
- static void
563
- draw_ellipse (
564
- Painter* painter,
829
+ void
830
+ Painter::ellipse (
565
831
  coord x, coord y, coord width, coord height,
566
- float angle_from, float angle_to, coord radius_min,
567
- uint nsegment)
832
+ const Point& hole_size,
833
+ float angle_from, float angle_to)
568
834
  {
569
- if (!painter)
570
- argument_error(__FILE__, __LINE__);
571
-
572
- Painter::Data* pself = painter->self.get();
573
-
574
- if (!pself->painting)
575
- invalid_state_error(__FILE__, __LINE__, "self->painting should be true.");
576
-
577
- if (height == 0) height = width;
578
- if (nsegment <= 0) nsegment = Painter::ELLIPSE_NSEGMENT;
579
-
580
- coord radius_x = width / 2;
581
- coord radius_y = height / 2;
582
- coord radius_x_min = radius_x * radius_min;
583
- coord radius_y_min = radius_y * radius_min;
584
- float from = angle_from / 360.f;
585
- float to = angle_to / 360.f;
586
- bool hole = radius_min != 0;
587
- int nvertices = hole ? nsegment * 2 : nsegment;
588
- GLenum modes[] =
589
- {
590
- (GLenum) (hole ? GL_TRIANGLE_STRIP : GL_TRIANGLE_FAN),
591
- GL_LINE_LOOP
592
- };
593
- boost::scoped_array<uint> indices;
594
- boost::scoped_array<Coord2> vertices;
595
-
596
- x += radius_x;
597
- y += radius_y;
598
-
599
- for (int type = COLOR_TYPE_BEGIN; type < COLOR_TYPE_END; ++type)
600
- {
601
- if (!pself->use_color((ColorType) type)) continue;
602
-
603
- if (!indices.get())
604
- {
605
- indices.reset(new uint[nvertices]);
606
- for (int i = 0; i < nvertices; ++i)
607
- indices[i] = i;
608
- }
609
-
610
- if (!vertices.get())
611
- vertices.reset(new Coord2[nvertices]);
612
-
613
- Coord2* vertex = vertices.get();
614
- assert(vertex);
615
-
616
- for (uint seg = 0; seg < nsegment; ++seg, ++vertex)
617
- {
618
- float pos = (float) seg / (float) nsegment;
619
- float radian = (from + (to - from) * pos) * PI_2;
620
- float xx = cos(radian);
621
- float yy = -sin(radian);
622
-
623
- if (hole)
624
- vertex->reset(x + xx * radius_x_min, y + yy * radius_y_min);
625
- vertex ->reset(x + xx * radius_x, y + yy * radius_y);
626
- }
835
+ polygon(create_ellipse(
836
+ x, y, width, height, hole_size, angle_from, angle_to, nsegment()));
837
+ }
627
838
 
628
- pself->draw_shape(modes[type], nvertices, indices.get(), 2, (coord*) vertices.get());
629
- }
839
+ void
840
+ Painter::ellipse (
841
+ const Bounds& bounds,
842
+ const Point& hole_size,
843
+ float angle_from, float angle_to)
844
+ {
845
+ polygon(create_ellipse(
846
+ bounds, hole_size, angle_from, angle_to, nsegment()));
630
847
  }
631
848
 
632
849
  void
633
850
  Painter::ellipse (
634
- coord x, coord y, coord width, coord height,
635
- coord radius_min, uint nsegment)
851
+ const Point& center, const Point& radius, const Point& hole_radius,
852
+ float angle_from, float angle_to)
636
853
  {
637
- draw_ellipse(this, x, y, width, height, 0, 360, radius_min, nsegment);
854
+ polygon(create_ellipse(
855
+ center, radius, hole_radius, angle_from, angle_to, nsegment()));
638
856
  }
639
857
 
640
858
  void
641
- Painter::ellipse (const Bounds& bounds, coord radius_min, uint nsegment)
859
+ Painter::curve (
860
+ coord x1, coord y1, coord x2, coord y2,
861
+ coord x3, coord y3, coord x4, coord y4,
862
+ bool loop)
642
863
  {
643
- ellipse(
644
- bounds.x, bounds.y, bounds.width, bounds.height, radius_min, nsegment);
864
+ polygon(create_curve(x1, y1, x2, y2, x3, y3, x4, y4, loop));
645
865
  }
646
866
 
647
867
  void
648
- Painter::ellipse (
649
- const Point& center, coord radius, coord radius_min, uint nsegment)
868
+ Painter::curve (
869
+ const Point& p1, const Point& p2, const Point& p3, const Point& p4,
870
+ bool loop)
650
871
  {
651
- ellipse(
652
- center.x - radius, center.y - radius, radius * 2, radius * 2,
653
- radius_min, nsegment);
872
+ polygon(create_curve(p1, p2, p3, p4, loop));
654
873
  }
655
874
 
656
875
  void
657
- Painter::arc (
658
- coord x, coord y, coord width, coord height,
659
- float angle_from, float angle_to, coord radius_min, uint nsegment)
876
+ Painter::curve (const Point* points, size_t size, bool loop)
660
877
  {
661
- draw_ellipse(
662
- this, x, y, width, height, angle_from, angle_to, radius_min, nsegment);
878
+ polygon(create_curve(points, size, loop));
663
879
  }
664
880
 
665
881
  void
666
- Painter::arc (
667
- const Bounds& bounds,
668
- float angle_from, float angle_to, coord radius_min, uint nsegment)
882
+ Painter::bezier (
883
+ coord x1, coord y1, coord x2, coord y2,
884
+ coord x3, coord y3, coord x4, coord y4,
885
+ bool loop)
886
+ {
887
+ polygon(create_bezier(x1, y1, x2, y2, x3, y3, x4, y4, loop));
888
+ }
889
+
890
+ void
891
+ Painter::bezier (
892
+ const Point& p1, const Point& p2, const Point& p3, const Point& p4,
893
+ bool loop)
669
894
  {
670
- arc(
671
- bounds.x, bounds.y, bounds.width, bounds.height,
672
- angle_from, angle_to, radius_min, nsegment);
895
+ polygon(create_bezier(p1, p2, p3, p4, loop));
673
896
  }
674
897
 
675
898
  void
676
- Painter::arc (
677
- const Point& center, coord radius,
678
- float angle_from, float angle_to, coord radius_min, uint nsegment)
899
+ Painter::bezier (const Point* points, size_t size, bool loop)
679
900
  {
680
- arc(
681
- center.x, center.y, radius * 2, radius * 2,
682
- angle_from, angle_to, radius_min, nsegment);
901
+ polygon(create_bezier(points, size, loop));
683
902
  }
684
903
 
685
904
  static void
686
905
  draw_image (
687
- Painter* painter, const Texture& tex,
688
- float s_min, float t_min, float s_max, float t_max,
689
- coord x, coord y, coord width, coord height,
690
- bool nostroke = false)
906
+ Painter* painter, const Image& image,
907
+ coord src_x, coord src_y, coord src_w, coord src_h,
908
+ coord dst_x, coord dst_y, coord dst_w, coord dst_h,
909
+ bool nostroke = false, const Shader* shader = NULL)
691
910
  {
692
911
  static const GLenum MODES[] = {GL_TRIANGLE_FAN, GL_LINE_LOOP};
693
- static const uint INDICES[] =
694
- {
695
- 0, 1, 2, 3
696
- };
697
912
 
698
- assert(tex);
913
+ assert(painter && image);
699
914
 
700
- if (!painter)
701
- argument_error(__FILE__, __LINE__);
915
+ Painter::Data* self = painter->self.get();
702
916
 
703
- Painter::Data* pself = painter->self.get();
917
+ if (!self->painting)
918
+ invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
704
919
 
705
- if (!pself->painting)
706
- invalid_state_error(__FILE__, __LINE__, "self->painting should be true.");
920
+ if (!self->state.has_color())
921
+ return;
707
922
 
708
- coord x2 = x + width - 1;
709
- coord y2 = y + height - 1;
710
- coord vertices[] =
711
- {
712
- x, y,
713
- x, y2,
714
- x2, y2,
715
- x2, y
716
- };
923
+ const Texture& texture = Image_get_texture(image);
924
+ if (!texture)
925
+ invalid_state_error(__FILE__, __LINE__);
717
926
 
718
- for (int type = COLOR_TYPE_BEGIN; type < COLOR_TYPE_END; ++type)
719
- {
720
- if (
721
- (nostroke && type == STROKE) ||
722
- !pself->use_color((ColorType) type))
723
- {
724
- continue;
725
- }
927
+ float density = image.pixel_density();
928
+ src_x *= density;
929
+ src_y *= density;
930
+ src_w *= density;
931
+ src_h *= density;
726
932
 
727
- if (type == FILL)
728
- {
729
- coord tex_coords[] = {
730
- s_min, t_min,
731
- s_min, t_max,
732
- s_max, t_max,
733
- s_max, t_min
734
- };
735
- pself->draw_shape(MODES[type], 4, INDICES, 2, vertices, tex_coords, &tex);
736
- }
737
- else
738
- pself->draw_shape(MODES[type], 4, INDICES, 2, vertices);
739
- }
933
+ Point points[4], texcoords[4];
934
+ points[0] .reset(dst_x, dst_y);
935
+ points[1] .reset(dst_x, dst_y + dst_h);
936
+ points[2] .reset(dst_x + dst_w, dst_y + dst_h);
937
+ points[3] .reset(dst_x + dst_w, dst_y);
938
+ texcoords[0].reset(src_x, src_y);
939
+ texcoords[1].reset(src_x, src_y + src_h);
940
+ texcoords[2].reset(src_x + src_w, src_y + src_h);
941
+ texcoords[3].reset(src_x + src_w, src_y);
942
+
943
+ TextureInfo texinfo(texture, src_x, src_y, src_x + src_w, src_y + src_h);
944
+
945
+ if (!shader)
946
+ shader = &get_default_shader_for_color_texture();
947
+
948
+ draw_polygon(
949
+ painter, MODES, 0, 0, false, nostroke, points, 4, NULL, 0, texcoords,
950
+ *shader, &texinfo);
740
951
  }
741
952
 
742
953
  void
@@ -745,14 +956,10 @@ namespace Rays
745
956
  if (!image_)
746
957
  argument_error(__FILE__, __LINE__);
747
958
 
748
- const Texture& tex = image_.texture();
749
- if (!tex)
750
- argument_error(__FILE__, __LINE__);
751
-
752
959
  draw_image(
753
- this, tex,
754
- 0, 0, tex.s_max(), tex.t_max(),
755
- x, y, tex.width(), tex.height());
960
+ this, image_,
961
+ 0, 0, image_.width(), image_.height(),
962
+ x, y, image_.width(), image_.height());
756
963
  }
757
964
 
758
965
  void
@@ -768,14 +975,10 @@ namespace Rays
768
975
  if (!image_)
769
976
  argument_error(__FILE__, __LINE__);
770
977
 
771
- const Texture& tex = image_.texture();
772
- if (!tex)
773
- argument_error(__FILE__, __LINE__);
774
-
775
978
  draw_image(
776
- this, tex,
777
- 0, 0, tex.s_max(), tex.t_max(),
778
- x, y, width, height);
979
+ this, image_,
980
+ 0, 0, image_.width(), image_.height(),
981
+ x, y, width, height);
779
982
  }
780
983
 
781
984
  void
@@ -788,191 +991,185 @@ namespace Rays
788
991
  void
789
992
  Painter::image (
790
993
  const Image& image_,
791
- coord src_x, coord src_y, coord src_width, coord src_height,
792
- coord dest_x, coord dest_y)
994
+ coord src_x, coord src_y, coord src_width, coord src_height,
995
+ coord dst_x, coord dst_y)
793
996
  {
794
997
  if (!image_)
795
998
  argument_error(__FILE__, __LINE__);
796
999
 
797
- const Texture& tex = image_.texture();
798
- if (!tex)
799
- argument_error(__FILE__, __LINE__);
800
-
801
- coord dest_width = tex.width(), dest_height = tex.height();
802
- float s = tex.s_max() / dest_width, t = tex.t_max() / dest_height;
803
1000
  draw_image(
804
- this, tex,
805
- src_x * s, src_y * t, src_width * s, src_height * t,
806
- dest_x, dest_y, dest_width, dest_height);
1001
+ this, image_,
1002
+ src_x, src_y, src_width, src_height,
1003
+ dst_x, dst_y, image_.width(), image_.height());
807
1004
  }
808
1005
 
809
1006
  void
810
1007
  Painter::image (
811
- const Image& image_, const Bounds& src_bounds, const Point& dest_position)
1008
+ const Image& image_, const Bounds& src_bounds, const Point& dst_position)
812
1009
  {
813
1010
  image(
814
1011
  image_,
815
1012
  src_bounds.x, src_bounds.y, src_bounds.width, src_bounds.height,
816
- dest_position.x, dest_position.y);
1013
+ dst_position.x, dst_position.y);
817
1014
  }
818
1015
 
819
1016
  void
820
1017
  Painter::image (
821
1018
  const Image& image_,
822
- coord src_x, coord src_y, coord src_width, coord src_height,
823
- coord dest_x, coord dest_y, coord dest_width, coord dest_height)
1019
+ coord src_x, coord src_y, coord src_width, coord src_height,
1020
+ coord dst_x, coord dst_y, coord dst_width, coord dst_height)
824
1021
  {
825
1022
  if (!image_)
826
1023
  argument_error(__FILE__, __LINE__);
827
1024
 
828
- const Texture& tex = image_.texture();
829
- if (!tex)
830
- argument_error(__FILE__, __LINE__);
831
-
832
- float s = tex.s_max() / tex.width();
833
- float t = tex.t_max() / tex.height();
834
1025
  draw_image(
835
- this, tex,
836
- src_x * s, src_y * t, src_width * s, src_height * t,
837
- dest_x, dest_y, dest_width, dest_height);
1026
+ this, image_,
1027
+ src_x, src_y, src_width, src_height,
1028
+ dst_x, dst_y, dst_width, dst_height);
838
1029
  }
839
1030
 
840
1031
  void
841
1032
  Painter::image (
842
- const Image& image_, const Bounds& src_bounds, const Bounds& dest_bounds)
1033
+ const Image& image_, const Bounds& src_bounds, const Bounds& dst_bounds)
843
1034
  {
844
1035
  image(
845
1036
  image_,
846
- src_bounds.x, src_bounds.y, src_bounds.width, src_bounds.height,
847
- dest_bounds.x, dest_bounds.y, dest_bounds.width, dest_bounds.height);
1037
+ src_bounds.x, src_bounds.y, src_bounds.width, src_bounds.height,
1038
+ dst_bounds.x, dst_bounds.y, dst_bounds.width, dst_bounds.height);
1039
+ }
1040
+
1041
+ static inline void
1042
+ debug_draw_text (
1043
+ Painter* painter, const Font& font,
1044
+ coord x, coord y, coord str_width, coord str_height)
1045
+ {
1046
+ #if 0
1047
+ save_image(painter->self->text_image, "/tmp/font.png");
1048
+
1049
+ painter->push_state();
1050
+ {
1051
+ coord asc, desc, lead;
1052
+ font.get_height(&asc, &desc, &lead);
1053
+ //printf("%f %f %f %f \n", str_height, asc, desc, lead);
1054
+
1055
+ painter->set_stroke(0.5, 0.5, 1);
1056
+ painter->no_fill();
1057
+ painter->rect(x - 1, y - 1, str_width + 2, str_height + 2);
1058
+
1059
+ coord yy = y;
1060
+ painter->set_stroke(1, 0.5, 0.5, 0.4);
1061
+ painter->rect(x, yy, str_width, asc);//str_height);
1062
+
1063
+ yy += asc;
1064
+ painter->set_stroke(1, 1, 0.5, 0.4);
1065
+ painter->rect(x, yy, str_width, desc);
1066
+
1067
+ yy += desc;
1068
+ painter->set_stroke(1, 0.5, 1, 0.4);
1069
+ painter->rect(x, yy, str_width, lead);
1070
+ }
1071
+ painter->pop_state();
1072
+ #endif
848
1073
  }
849
1074
 
850
1075
  static void
851
1076
  draw_text (
852
- Painter* painter, const char* str, coord str_width, coord str_height,
853
- coord x, coord y, coord width, coord height,
854
- const Font& font)
1077
+ Painter* painter, const Font& font,
1078
+ const char* str, coord x, coord y, coord width = 0, coord height = 0)
855
1079
  {
856
- assert(str && *str != '\0' && font);
1080
+ assert(painter && font && str && *str != '\0');
857
1081
 
858
- if (!painter)
859
- argument_error(__FILE__, __LINE__);
1082
+ Painter::Data* self = painter->self.get();
860
1083
 
861
- if (!painter->self->painting)
862
- invalid_state_error(__FILE__, __LINE__, "self->painting should be true.");
1084
+ if (!self->painting)
1085
+ invalid_state_error(__FILE__, __LINE__, "painting flag should be true.");
863
1086
 
864
- Painter::Data* self = painter->self.get();
865
- int tex_w = ceil(str_width);
866
- int tex_h = ceil(str_height);
1087
+ if (!self->state.has_color())
1088
+ return;
867
1089
 
1090
+ float density = self->pixel_density;
1091
+ coord str_w = Font_get_width(font, density, str);
1092
+ coord str_h = Font_get_height(font, density);
1093
+ int tex_w = ceil(str_w);
1094
+ int tex_h = ceil(str_h);
1095
+ const Texture& texture = Image_get_texture(self->text_image);
868
1096
  if (
869
- self->text_image.width() < tex_w ||
870
- self->text_image.height() < tex_h)
1097
+ texture.width() < tex_w ||
1098
+ texture.height() < tex_h ||
1099
+ self->text_image.pixel_density() != density)
871
1100
  {
872
- self->text_image = Image(
873
- std::max(self->text_image.width(), tex_w),
874
- std::max(self->text_image.height(), tex_h),
875
- self->text_image.color_space(),
876
- self->text_image.alpha_only());
1101
+ int bmp_w = std::max(texture.width(), tex_w);
1102
+ int bmp_h = std::max(texture.height(), tex_h);
1103
+ self->text_image = Image(Bitmap(bmp_w, bmp_h, ALPHA), density);
877
1104
  }
878
1105
 
879
1106
  if (!self->text_image)
880
1107
  invalid_state_error(__FILE__, __LINE__);
881
1108
 
882
- draw_string(&self->text_image.bitmap(), str, 0, 0, font);
1109
+ assert(self->text_image.pixel_density() == density);
883
1110
 
884
- const Texture& tex = self->text_image.texture();
885
- if (!tex)
886
- rays_error(__FILE__, __LINE__, "text_image's texture is invalid.");
1111
+ Bitmap_draw_string(
1112
+ &self->text_image.bitmap(), Font_get_raw(font, density), str, 0, 0);
887
1113
 
888
- #if 0//def DEBUG
889
- save_image(self->text_image, "/Users/snori/font.png");
890
-
891
- painter->push_attr();
892
- {
893
- coord asc, desc, lead;
894
- font.get_height(&asc, &desc, &lead);
895
- //printf("%f %f %f %f \n", str_height, asc, desc, lead);
896
-
897
- painter->set_stroke(0.5, 0.5, 1);
898
- painter->no_fill();
899
- painter->rect(x - 1, y - 1, str_width + 2, str_height + 2);
900
-
901
- coord yy = y;
902
- painter->set_stroke(1, 0.5, 0.5, 0.4);
903
- painter->rect(x, yy, str_width, asc);//str_height);
904
-
905
- yy += asc;
906
- painter->set_stroke(1, 1, 0.5, 0.4);
907
- painter->rect(x, yy, str_width, desc);
908
-
909
- yy += desc;
910
- painter->set_stroke(1, 0.5, 1, 0.4);
911
- painter->rect(x, yy, str_width, lead);
912
- }
913
- painter->pop_attr();
914
- #endif
1114
+ str_w /= density;
1115
+ str_h /= density;
1116
+ if (width == 0) width = str_w;
1117
+ if (height == 0) height = str_h;
915
1118
 
916
1119
  draw_image(
917
- painter, tex,
918
- 0, 0, tex.s(str_width - 1), tex.t(str_height - 1),
919
- x, y, width, height,
920
- true);
1120
+ painter, self->text_image,
1121
+ 0, 0, str_w, str_h,
1122
+ x, y, str_w, str_h,
1123
+ true, &get_default_shader_for_alpha_texture());
1124
+
1125
+ debug_draw_text(painter, font, x, y, str_w / density, str_h / density);
921
1126
  }
922
1127
 
923
1128
  void
924
- Painter::text (const char* str, coord x, coord y, const Font* font)
1129
+ Painter::text (const char* str, coord x, coord y)
925
1130
  {
926
1131
  if (!str)
927
1132
  argument_error(__FILE__, __LINE__);
928
1133
 
929
1134
  if (*str == '\0') return;
930
1135
 
931
- if (!font) font = &self->attrs.font;
932
- if (!*font)
933
- argument_error(__FILE__, __LINE__);
1136
+ const Font& font = self->state.font;
1137
+ if (!font)
1138
+ invalid_state_error(__FILE__, __LINE__);
934
1139
 
935
- coord w = font->get_width(str), h = font->get_height();
936
- w = ceil(w);
937
- h = ceil(h);
938
- draw_text(this, str, w, h, x, y, w, h, *font);
1140
+ draw_text(this, font, str, x, y);
939
1141
  }
940
1142
 
941
1143
  void
942
- Painter::text (const char* str, const Point& position, const Font* font)
1144
+ Painter::text (const char* str, const Point& position)
943
1145
  {
944
- text(str, position.x, position.y, font);
1146
+ text(str, position.x, position.y);
945
1147
  }
946
1148
 
947
1149
  void
948
- Painter::text (
949
- const char* str, coord x, coord y, coord width, coord height,
950
- const Font* font)
1150
+ Painter::text (const char* str, coord x, coord y, coord width, coord height)
951
1151
  {
952
1152
  if (!str)
953
1153
  argument_error(__FILE__, __LINE__);
954
1154
 
955
- if (*str == '\0') return;
1155
+ if (*str == '\0' || width == 0 || height == 0) return;
956
1156
 
957
- if (!font) font = &self->attrs.font;
958
- if (!*font)
959
- argument_error(__FILE__, __LINE__);
1157
+ const Font& font = self->state.font;
1158
+ if (!font)
1159
+ invalid_state_error(__FILE__, __LINE__);
960
1160
 
961
- coord w = font->get_width(str), h = font->get_height();
962
- w = ceil(w);
963
- h = ceil(h);
964
- draw_text(this, str, w, h, x, y, width, height, *font);
1161
+ draw_text(this, font, str, x, y, width, height);
965
1162
  }
966
1163
 
967
1164
  void
968
- Painter::text (const char* str, const Bounds& bounds, const Font* font)
1165
+ Painter::text (const char* str, const Bounds& bounds)
969
1166
  {
970
- text(str, bounds.x, bounds.y, bounds.width, bounds.height, font);
1167
+ text(str, bounds.x, bounds.y, bounds.width, bounds.height);
971
1168
  }
972
1169
 
973
-
974
1170
  void
975
- Painter::set_background (float red, float green, float blue, float alpha, bool clear)
1171
+ Painter::set_background (
1172
+ float red, float green, float blue, float alpha, bool clear)
976
1173
  {
977
1174
  set_background(Color(red, green, blue, alpha), clear);
978
1175
  }
@@ -980,7 +1177,7 @@ namespace Rays
980
1177
  void
981
1178
  Painter::set_background (const Color& color, bool clear)
982
1179
  {
983
- self->attrs.background = color;
1180
+ self->state.background = color;
984
1181
 
985
1182
  if (self->painting && clear) this->clear();
986
1183
  }
@@ -996,7 +1193,7 @@ namespace Rays
996
1193
  const Color&
997
1194
  Painter::background () const
998
1195
  {
999
- return self->attrs.background;
1196
+ return self->state.background;
1000
1197
  }
1001
1198
 
1002
1199
  void
@@ -1008,19 +1205,19 @@ namespace Rays
1008
1205
  void
1009
1206
  Painter::set_fill (const Color& color)
1010
1207
  {
1011
- self->attrs.colors[FILL] = color;
1208
+ self->state.colors[FILL] = color;
1012
1209
  }
1013
1210
 
1014
1211
  void
1015
1212
  Painter::no_fill ()
1016
1213
  {
1017
- self->attrs.colors[FILL].alpha = 0;
1214
+ self->state.colors[FILL].alpha = 0;
1018
1215
  }
1019
1216
 
1020
1217
  const Color&
1021
1218
  Painter::fill () const
1022
1219
  {
1023
- return self->attrs.colors[FILL];
1220
+ return self->state.colors[FILL];
1024
1221
  }
1025
1222
 
1026
1223
  void
@@ -1032,217 +1229,200 @@ namespace Rays
1032
1229
  void
1033
1230
  Painter::set_stroke (const Color& color)
1034
1231
  {
1035
- self->attrs.colors[STROKE] = color;
1232
+ self->state.colors[STROKE] = color;
1036
1233
  }
1037
1234
 
1038
1235
  void
1039
1236
  Painter::no_stroke ()
1040
1237
  {
1041
- self->attrs.colors[STROKE].alpha = 0;
1238
+ self->state.colors[STROKE].alpha = 0;
1042
1239
  }
1043
1240
 
1044
1241
  const Color&
1045
1242
  Painter::stroke () const
1046
1243
  {
1047
- return self->attrs.colors[STROKE];
1244
+ return self->state.colors[STROKE];
1048
1245
  }
1049
1246
 
1050
1247
  void
1051
- Painter::set_clip (coord x, coord y, coord width, coord height)
1248
+ Painter::set_stroke_width (coord width)
1052
1249
  {
1053
- set_clip(Bounds(x, y, width, height));
1250
+ self->state.stroke_width = width;
1054
1251
  }
1055
1252
 
1056
- void
1057
- Painter::set_clip (const Bounds& bounds)
1253
+ coord
1254
+ Painter::stroke_width () const
1058
1255
  {
1059
- self->attrs.clip = bounds;
1060
- self->update_clip();
1256
+ return self->state.stroke_width;
1061
1257
  }
1062
1258
 
1063
1259
  void
1064
- Painter::no_clip ()
1065
- {
1066
- set_clip(0, 0, -1, -1);
1067
- }
1068
-
1069
- const Bounds&
1070
- Painter::clip () const
1260
+ Painter::set_stroke_cap (CapType cap)
1071
1261
  {
1072
- return self->attrs.clip;
1262
+ self->state.stroke_cap = cap;
1073
1263
  }
1074
1264
 
1075
- void
1076
- Painter::set_font (const char* name, coord size)
1265
+ CapType
1266
+ Painter::stroke_cap () const
1077
1267
  {
1078
- set_font(Font(name, size));
1268
+ return self->state.stroke_cap;
1079
1269
  }
1080
1270
 
1081
1271
  void
1082
- Painter::set_font (const Font& font)
1272
+ Painter::set_stroke_join (JoinType join)
1083
1273
  {
1084
- self->attrs.font = font;
1274
+ self->state.stroke_join = join;
1085
1275
  }
1086
1276
 
1087
- const Font&
1088
- Painter::font () const
1277
+ JoinType
1278
+ Painter::stroke_join () const
1089
1279
  {
1090
- return self->attrs.font;
1280
+ return self->state.stroke_join;
1091
1281
  }
1092
1282
 
1093
1283
  void
1094
- Painter::push_attr ()
1284
+ Painter::set_miter_limit (coord limit)
1095
1285
  {
1096
- self->attrs_stack.push_back(self->attrs);
1286
+ self->state.miter_limit = limit;
1097
1287
  }
1098
1288
 
1099
- void
1100
- Painter::pop_attr ()
1289
+ coord
1290
+ Painter::miter_limit () const
1101
1291
  {
1102
- if (self->attrs_stack.empty())
1103
- rays_error(__FILE__, __LINE__, "attrs_stack is empty.");
1104
-
1105
- self->attrs = self->attrs_stack.back();
1106
- self->attrs_stack.pop_back();
1107
- self->update_clip();
1292
+ return self->state.miter_limit;
1108
1293
  }
1109
1294
 
1110
-
1111
1295
  void
1112
- Painter::attach (const Shader& shader)
1296
+ Painter::set_nsegment (int nsegment)
1113
1297
  {
1114
- self->program.attach(shader);
1298
+ if (nsegment < 0) nsegment = 0;
1299
+ self->state.nsegment = nsegment;
1115
1300
  }
1116
1301
 
1117
- void
1118
- Painter::detach (const Shader& shader)
1302
+ uint
1303
+ Painter::nsegment () const
1119
1304
  {
1120
- self->program.detach(shader);
1305
+ return self->state.nsegment;
1121
1306
  }
1122
1307
 
1123
1308
  void
1124
- Painter::set_uniform (const char* name, int arg1)
1309
+ Painter::set_clip (coord x, coord y, coord width, coord height)
1125
1310
  {
1126
- self->program.set_uniform(name, arg1);
1311
+ set_clip(Bounds(x, y, width, height));
1127
1312
  }
1128
1313
 
1129
1314
  void
1130
- Painter::set_uniform (const char* name, int arg1, int arg2)
1315
+ Painter::set_clip (const Bounds& bounds)
1131
1316
  {
1132
- self->program.set_uniform(name, arg1, arg2);
1317
+ self->state.clip = bounds;
1318
+ self->update_clip();
1133
1319
  }
1134
1320
 
1135
1321
  void
1136
- Painter::set_uniform (const char* name, int arg1, int arg2, int arg3)
1322
+ Painter::no_clip ()
1137
1323
  {
1138
- self->program.set_uniform(name, arg1, arg2, arg3);
1324
+ set_clip(0, 0, -1, -1);
1139
1325
  }
1140
1326
 
1141
- void
1142
- Painter::set_uniform (const char* name, int arg1, int arg2, int arg3, int arg4)
1327
+ const Bounds&
1328
+ Painter::clip () const
1143
1329
  {
1144
- self->program.set_uniform(name, arg1, arg2, arg3, arg4);
1330
+ return self->state.clip;
1145
1331
  }
1146
1332
 
1147
1333
  void
1148
- Painter::set_uniform (const char* name, const int* args, size_t size)
1334
+ Painter::set_font (const char* name, coord size)
1149
1335
  {
1150
- self->program.set_uniform(name, args, size);
1336
+ set_font(Font(name, size));
1151
1337
  }
1152
1338
 
1153
1339
  void
1154
- Painter::set_uniform (const char* name, float arg1)
1340
+ Painter::set_font (const Font& font)
1155
1341
  {
1156
- self->program.set_uniform(name, arg1);
1342
+ self->state.font = font;
1157
1343
  }
1158
1344
 
1159
- void
1160
- Painter::set_uniform (const char* name, float arg1, float arg2)
1345
+ const Font&
1346
+ Painter::font () const
1161
1347
  {
1162
- self->program.set_uniform(name, arg1, arg2);
1348
+ return self->state.font;
1163
1349
  }
1164
1350
 
1165
1351
  void
1166
- Painter::set_uniform (const char* name, float arg1, float arg2, float arg3)
1352
+ Painter::set_shader (const Shader& shader)
1167
1353
  {
1168
- self->program.set_uniform(name, arg1, arg2, arg3);
1354
+ self->state.shader = shader;
1169
1355
  }
1170
1356
 
1171
1357
  void
1172
- Painter::set_uniform (const char* name, float arg1, float arg2, float arg3, float arg4)
1358
+ Painter::no_shader ()
1173
1359
  {
1174
- self->program.set_uniform(name, arg1, arg2, arg3, arg4);
1360
+ self->state.shader = Shader();
1175
1361
  }
1176
1362
 
1177
- void
1178
- Painter::set_uniform (const char* name, const float* args, size_t size)
1363
+ const Shader&
1364
+ Painter::shader () const
1179
1365
  {
1180
- self->program.set_uniform(name, args, size);
1366
+ return self->state.shader;
1181
1367
  }
1182
1368
 
1183
1369
  void
1184
- Painter::push_shader ()
1370
+ Painter::push_state ()
1185
1371
  {
1186
- self->program.push();
1372
+ self->state_stack.emplace_back(self->state);
1187
1373
  }
1188
1374
 
1189
1375
  void
1190
- Painter::pop_shader ()
1376
+ Painter::pop_state ()
1191
1377
  {
1192
- self->program.pop();
1193
- }
1378
+ if (self->state_stack.empty())
1379
+ invalid_state_error(__FILE__, __LINE__, "state stack underflow.");
1194
1380
 
1381
+ self->state = self->state_stack.back();
1382
+ self->state_stack.pop_back();
1383
+ self->update_clip();
1384
+ }
1195
1385
 
1196
1386
  void
1197
1387
  Painter::translate (coord x, coord y, coord z)
1198
1388
  {
1199
- glTranslatef(x, y, z);
1389
+ self->position_matrix.translate(x, y, z);
1200
1390
  }
1201
1391
 
1202
1392
  void
1203
1393
  Painter::translate (const Point& value)
1204
1394
  {
1205
- translate(value.x, value.y, value.z);
1395
+ self->position_matrix.translate(value);
1206
1396
  }
1207
1397
 
1208
1398
  void
1209
1399
  Painter::scale (coord x, coord y, coord z)
1210
1400
  {
1211
- glScalef(x, y, z);
1401
+ self->position_matrix.scale(x, y, z);
1212
1402
  }
1213
1403
 
1214
1404
  void
1215
1405
  Painter::scale (const Point& value)
1216
1406
  {
1217
- scale(value.x, value.y, value.z);
1407
+ self->position_matrix.scale(value);
1218
1408
  }
1219
1409
 
1220
1410
  void
1221
- Painter::rotate (float angle, coord x, coord y, coord z)
1411
+ Painter::rotate (float degree, coord x, coord y, coord z)
1222
1412
  {
1223
- glRotatef(angle, x, y, z);
1413
+ self->position_matrix.rotate(degree, x, y, z);
1224
1414
  }
1225
1415
 
1226
1416
  void
1227
- Painter::rotate (float angle, const Point& axis)
1417
+ Painter::rotate (float angle, const Point& normalized_axis)
1228
1418
  {
1229
- rotate(angle, axis.x, axis.y, axis.z);
1419
+ self->position_matrix.rotate(angle, normalized_axis);
1230
1420
  }
1231
1421
 
1232
1422
  void
1233
1423
  Painter::set_matrix (float value)
1234
1424
  {
1235
- if (value == 1)
1236
- {
1237
- glLoadIdentity();
1238
- return;
1239
- }
1240
-
1241
- set_matrix(
1242
- value, 0, 0, 0,
1243
- 0, value, 0, 0,
1244
- 0, 0, value, 0,
1245
- 0, 0, 0, value);
1425
+ self->position_matrix.reset(value);
1246
1426
  }
1247
1427
 
1248
1428
  void
@@ -1252,52 +1432,46 @@ namespace Rays
1252
1432
  float c1, float c2, float c3, float c4,
1253
1433
  float d1, float d2, float d3, float d4)
1254
1434
  {
1255
- float array[] = {
1435
+ self->position_matrix.reset(
1256
1436
  a1, a2, a3, a4,
1257
1437
  b1, b2, b3, b4,
1258
1438
  c1, c2, c3, c4,
1259
- d1, d2, d3, d4
1260
- };
1261
- set_matrix(array);
1439
+ d1, d2, d3, d4);
1262
1440
  }
1263
1441
 
1264
1442
  void
1265
- Painter::set_matrix (const float* elements)
1443
+ Painter::set_matrix (const coord* elements, size_t size)
1266
1444
  {
1267
- if (!elements)
1268
- argument_error(__FILE__, __LINE__);
1269
-
1270
- glLoadMatrixf(elements);
1445
+ self->position_matrix.reset(elements, size);
1271
1446
  }
1272
1447
 
1273
1448
  void
1274
1449
  Painter::set_matrix (const Matrix& matrix)
1275
1450
  {
1276
- set_matrix(matrix.array);
1451
+ self->position_matrix = matrix;
1277
1452
  }
1278
1453
 
1279
1454
  const Matrix&
1280
1455
  Painter::matrix () const
1281
1456
  {
1282
- glGetFloatv(GL_MODELVIEW_MATRIX, self->matrix_tmp.array);
1283
- check_error(__FILE__, __LINE__);
1284
- return self->matrix_tmp;
1457
+ return self->position_matrix;
1285
1458
  }
1286
1459
 
1287
1460
  void
1288
1461
  Painter::push_matrix ()
1289
1462
  {
1290
- glPushMatrix();
1291
- check_error(__FILE__, __LINE__);
1463
+ self->position_matrix_stack.emplace_back(self->position_matrix);
1292
1464
  }
1293
1465
 
1294
1466
  void
1295
1467
  Painter::pop_matrix ()
1296
1468
  {
1297
- glPopMatrix();
1298
- check_error(__FILE__, __LINE__);
1299
- }
1469
+ if (self->position_matrix_stack.empty())
1470
+ invalid_state_error(__FILE__, __LINE__, "matrix stack underflow.");
1300
1471
 
1472
+ self->position_matrix = self->position_matrix_stack.back();
1473
+ self->position_matrix_stack.pop_back();
1474
+ }
1301
1475
 
1302
1476
  Painter::operator bool () const
1303
1477
  {