48
48
#include "cogl-offscreen.h"
49
49
#include "cogl-matrix-stack.h"
51
#ifndef GL_CLIP_PLANE0
52
#define GL_CLIP_PLANE0 0x3000
53
#define GL_CLIP_PLANE1 0x3001
54
#define GL_CLIP_PLANE2 0x3002
55
#define GL_CLIP_PLANE3 0x3003
56
#define GL_CLIP_PLANE4 0x3004
57
#define GL_CLIP_PLANE5 0x3005
61
project_vertex (const CoglMatrix *modelview_projection,
66
cogl_matrix_transform_point (modelview_projection,
67
&vertex[0], &vertex[1],
68
&vertex[2], &vertex[3]);
70
/* Convert from homogenized coordinates */
71
for (i = 0; i < 4; i++)
72
vertex[i] /= vertex[3];
76
set_clip_plane (CoglFramebuffer *framebuffer,
78
const float *vertex_a,
79
const float *vertex_b)
84
CoglMatrixStack *modelview_stack =
85
_cogl_framebuffer_get_modelview_stack (framebuffer);
86
CoglMatrixStack *projection_stack =
87
_cogl_framebuffer_get_projection_stack (framebuffer);
88
CoglMatrix inverse_projection;
90
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
92
_cogl_matrix_stack_get_inverse (projection_stack, &inverse_projection);
94
/* Calculate the angle between the axes and the line crossing the
96
angle = atan2f (vertex_b[1] - vertex_a[1],
97
vertex_b[0] - vertex_a[0]) * (180.0/G_PI);
99
_cogl_matrix_stack_push (modelview_stack);
101
/* Load the inverse of the projection matrix so we can specify the plane
102
* in screen coordinates */
103
_cogl_matrix_stack_set (modelview_stack, &inverse_projection);
105
/* Rotate about point a */
106
_cogl_matrix_stack_translate (modelview_stack,
107
vertex_a[0], vertex_a[1], vertex_a[2]);
108
/* Rotate the plane by the calculated angle so that it will connect
110
_cogl_matrix_stack_rotate (modelview_stack, angle, 0.0f, 0.0f, 1.0f);
111
_cogl_matrix_stack_translate (modelview_stack,
112
-vertex_a[0], -vertex_a[1], -vertex_a[2]);
114
/* Clip planes can only be used when a fixed function backend is in
115
use so we know we can directly push this matrix to the builtin
117
_cogl_matrix_entry_flush_to_gl_builtins (ctx,
118
modelview_stack->last_entry,
119
COGL_MATRIX_MODELVIEW,
121
FALSE /* don't disable flip */);
126
planef[3] = vertex_a[1];
131
g_assert_not_reached ();
134
case COGL_DRIVER_GLES1:
135
GE( ctx, glClipPlanef (plane_num, planef) );
139
planed[0] = planef[0];
140
planed[1] = planef[1];
141
planed[2] = planef[2];
142
planed[3] = planef[3];
143
GE( ctx, glClipPlane (plane_num, planed) );
147
_cogl_matrix_stack_pop (modelview_stack);
151
set_clip_planes (CoglFramebuffer *framebuffer,
152
CoglMatrixEntry *modelview_entry,
158
CoglMatrix modelview_matrix;
159
CoglMatrixStack *projection_stack =
160
_cogl_framebuffer_get_projection_stack (framebuffer);
161
CoglMatrix projection_matrix;
162
CoglMatrix modelview_projection;
165
float vertex_tl[4] = { x_1, y_1, 0, 1.0 };
166
float vertex_tr[4] = { x_2, y_1, 0, 1.0 };
167
float vertex_bl[4] = { x_1, y_2, 0, 1.0 };
168
float vertex_br[4] = { x_2, y_2, 0, 1.0 };
170
_cogl_matrix_stack_get (projection_stack, &projection_matrix);
171
_cogl_matrix_entry_get (modelview_entry, &modelview_matrix);
173
cogl_matrix_multiply (&modelview_projection,
177
project_vertex (&modelview_projection, vertex_tl);
178
project_vertex (&modelview_projection, vertex_tr);
179
project_vertex (&modelview_projection, vertex_bl);
180
project_vertex (&modelview_projection, vertex_br);
182
/* Calculate the signed area of the polygon formed by the four
183
vertices so that we can know its orientation */
184
signed_area = (vertex_tl[0] * (vertex_tr[1] - vertex_bl[1])
185
+ vertex_tr[0] * (vertex_br[1] - vertex_tl[1])
186
+ vertex_br[0] * (vertex_bl[1] - vertex_tr[1])
187
+ vertex_bl[0] * (vertex_tl[1] - vertex_br[1]));
189
/* Set the clip planes to form lines between all of the vertices
190
using the same orientation as we calculated */
191
if (signed_area > 0.0f)
193
/* counter-clockwise */
194
set_clip_plane (framebuffer, GL_CLIP_PLANE0, vertex_tl, vertex_bl);
195
set_clip_plane (framebuffer, GL_CLIP_PLANE1, vertex_bl, vertex_br);
196
set_clip_plane (framebuffer, GL_CLIP_PLANE2, vertex_br, vertex_tr);
197
set_clip_plane (framebuffer, GL_CLIP_PLANE3, vertex_tr, vertex_tl);
202
set_clip_plane (framebuffer, GL_CLIP_PLANE0, vertex_tl, vertex_tr);
203
set_clip_plane (framebuffer, GL_CLIP_PLANE1, vertex_tr, vertex_br);
204
set_clip_plane (framebuffer, GL_CLIP_PLANE2, vertex_br, vertex_bl);
205
set_clip_plane (framebuffer, GL_CLIP_PLANE3, vertex_bl, vertex_tl);
210
add_stencil_clip_rectangle (CoglFramebuffer *framebuffer,
211
CoglMatrixEntry *modelview_entry,
218
CoglMatrixStack *projection_stack =
219
_cogl_framebuffer_get_projection_stack (framebuffer);
220
CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
222
/* NB: This can be called while flushing the journal so we need
223
* to be very conservative with what state we change.
226
_cogl_context_set_current_projection_entry (ctx,
227
projection_stack->last_entry);
228
_cogl_context_set_current_modelview_entry (ctx, modelview_entry);
232
GE( ctx, glEnable (GL_STENCIL_TEST) );
234
/* Initially disallow everything */
235
GE( ctx, glClearStencil (0) );
236
GE( ctx, glClear (GL_STENCIL_BUFFER_BIT) );
238
/* Punch out a hole to allow the rectangle */
239
GE( ctx, glStencilFunc (GL_NEVER, 0x1, 0x1) );
240
GE( ctx, glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE) );
242
_cogl_rectangle_immediate (framebuffer,
243
ctx->stencil_pipeline,
248
/* Add one to every pixel of the stencil buffer in the
250
GE( ctx, glStencilFunc (GL_NEVER, 0x1, 0x3) );
251
GE( ctx, glStencilOp (GL_INCR, GL_INCR, GL_INCR) );
252
_cogl_rectangle_immediate (framebuffer,
253
ctx->stencil_pipeline,
256
/* Subtract one from all pixels in the stencil buffer so that
257
only pixels where both the original stencil buffer and the
258
rectangle are set will be valid */
259
GE( ctx, glStencilOp (GL_DECR, GL_DECR, GL_DECR) );
261
_cogl_context_set_current_projection_entry (ctx, &ctx->identity_entry);
262
_cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry);
264
_cogl_rectangle_immediate (framebuffer,
265
ctx->stencil_pipeline,
266
-1.0, -1.0, 1.0, 1.0);
269
/* Restore the stencil mode */
270
GE( ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1) );
271
GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
274
typedef void (*SilhouettePaintCallback) (CoglFramebuffer *framebuffer,
275
CoglPipeline *pipeline,
279
add_stencil_clip_silhouette (CoglFramebuffer *framebuffer,
280
SilhouettePaintCallback silhouette_callback,
281
CoglMatrixEntry *modelview_entry,
290
CoglMatrixStack *projection_stack =
291
_cogl_framebuffer_get_projection_stack (framebuffer);
292
CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
294
/* NB: This can be called while flushing the journal so we need
295
* to be very conservative with what state we change.
298
_cogl_context_set_current_projection_entry (ctx,
299
projection_stack->last_entry);
300
_cogl_context_set_current_modelview_entry (ctx, modelview_entry);
302
_cogl_pipeline_flush_gl_state (ctx->stencil_pipeline, framebuffer, FALSE, 0);
304
GE( ctx, glEnable (GL_STENCIL_TEST) );
306
GE( ctx, glColorMask (FALSE, FALSE, FALSE, FALSE) );
307
GE( ctx, glDepthMask (FALSE) );
311
GE (ctx, glStencilMask (2));
312
GE (ctx, glStencilFunc (GL_LEQUAL, 0x2, 0x6));
316
/* If we're not using the stencil buffer for clipping then we
317
don't need to clear the whole stencil buffer, just the area
318
that will be drawn */
320
/* If this is being called from the clip stack code then it
321
will have set up a scissor for the minimum bounding box of
322
all of the clips. That box will likely mean that this
323
_cogl_clear won't need to clear the entire
324
buffer. _cogl_framebuffer_clear_without_flush4f is used instead
325
of cogl_clear because it won't try to flush the journal */
326
_cogl_framebuffer_clear_without_flush4f (framebuffer,
327
COGL_BUFFER_BIT_STENCIL,
331
/* Just clear the bounding box */
332
GE( ctx, glStencilMask (~(GLuint) 0) );
333
GE( ctx, glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) );
334
_cogl_rectangle_immediate (framebuffer,
335
ctx->stencil_pipeline,
336
bounds_x1, bounds_y1,
337
bounds_x2, bounds_y2);
339
GE (ctx, glStencilMask (1));
340
GE (ctx, glStencilFunc (GL_LEQUAL, 0x1, 0x3));
343
GE (ctx, glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT));
345
silhouette_callback (framebuffer, ctx->stencil_pipeline, user_data);
349
/* Now we have the new stencil buffer in bit 1 and the old
350
stencil buffer in bit 0 so we need to intersect them */
351
GE (ctx, glStencilMask (3));
352
GE (ctx, glStencilFunc (GL_NEVER, 0x2, 0x3));
353
GE (ctx, glStencilOp (GL_DECR, GL_DECR, GL_DECR));
354
/* Decrement all of the bits twice so that only pixels where the
355
value is 3 will remain */
357
_cogl_context_set_current_projection_entry (ctx, &ctx->identity_entry);
358
_cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry);
360
_cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline,
361
-1.0, -1.0, 1.0, 1.0);
362
_cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline,
363
-1.0, -1.0, 1.0, 1.0);
366
GE (ctx, glStencilMask (~(GLuint) 0));
367
GE (ctx, glDepthMask (TRUE));
368
GE (ctx, glColorMask (TRUE, TRUE, TRUE, TRUE));
370
GE (ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1));
371
GE (ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP));
375
paint_path_silhouette (CoglFramebuffer *framebuffer,
376
CoglPipeline *pipeline,
379
CoglPath *path = user_data;
380
if (path->data->path_nodes->len >= 3)
381
_cogl_path_fill_nodes (path,
384
COGL_DRAW_SKIP_JOURNAL_FLUSH |
385
COGL_DRAW_SKIP_PIPELINE_VALIDATION |
386
COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH);
390
add_stencil_clip_path (CoglFramebuffer *framebuffer,
391
CoglMatrixEntry *modelview_entry,
396
CoglPathData *data = path->data;
397
add_stencil_clip_silhouette (framebuffer,
398
paint_path_silhouette,
400
data->path_nodes_min.x,
401
data->path_nodes_min.y,
402
data->path_nodes_max.x,
403
data->path_nodes_max.y,
410
paint_primitive_silhouette (CoglFramebuffer *framebuffer,
411
CoglPipeline *pipeline,
414
_cogl_framebuffer_draw_primitive (framebuffer,
417
COGL_DRAW_SKIP_JOURNAL_FLUSH |
418
COGL_DRAW_SKIP_PIPELINE_VALIDATION |
419
COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH |
420
COGL_DRAW_SKIP_LEGACY_STATE);
424
add_stencil_clip_primitive (CoglFramebuffer *framebuffer,
425
CoglMatrixEntry *modelview_entry,
426
CoglPrimitive *primitive,
434
add_stencil_clip_silhouette (framebuffer,
435
paint_primitive_silhouette,
447
disable_stencil_buffer (void)
449
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
451
GE( ctx, glDisable (GL_STENCIL_TEST) );
455
enable_clip_planes (void)
457
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
459
GE( ctx, glEnable (GL_CLIP_PLANE0) );
460
GE( ctx, glEnable (GL_CLIP_PLANE1) );
461
GE( ctx, glEnable (GL_CLIP_PLANE2) );
462
GE( ctx, glEnable (GL_CLIP_PLANE3) );
466
disable_clip_planes (void)
468
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
470
GE( ctx, glDisable (GL_CLIP_PLANE3) );
471
GE( ctx, glDisable (GL_CLIP_PLANE2) );
472
GE( ctx, glDisable (GL_CLIP_PLANE1) );
473
GE( ctx, glDisable (GL_CLIP_PLANE0) );
477
54
_cogl_clip_stack_push_entry (CoglClipStack *clip_stack,
881
462
CoglFramebuffer *framebuffer)
883
464
CoglContext *ctx = framebuffer->context;
885
CoglBool using_clip_planes = FALSE;
886
CoglBool using_stencil_buffer = FALSE;
891
CoglClipStack *entry;
894
/* If we have already flushed this state then we don't need to do
896
if (ctx->current_clip_stack_valid)
898
if (ctx->current_clip_stack == stack)
901
_cogl_clip_stack_unref (ctx->current_clip_stack);
904
ctx->current_clip_stack_valid = TRUE;
905
ctx->current_clip_stack = _cogl_clip_stack_ref (stack);
908
ctx->private_feature_flags & COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES;
911
disable_clip_planes ();
912
disable_stencil_buffer ();
914
/* If the stack is empty then there's nothing else to do */
917
COGL_NOTE (CLIPPING, "Flushed empty clip stack");
919
ctx->current_clip_stack_uses_stencil = FALSE;
920
GE (ctx, glDisable (GL_SCISSOR_TEST));
924
/* Calculate the scissor rect first so that if we eventually have to
925
clear the stencil buffer then the clear will be clipped to the
926
intersection of all of the bounding boxes. This saves having to
927
clear the whole stencil buffer */
928
_cogl_clip_stack_get_bounds (stack,
929
&scissor_x0, &scissor_y0,
930
&scissor_x1, &scissor_y1);
932
/* Enable scissoring as soon as possible */
933
if (scissor_x0 >= scissor_x1 || scissor_y0 >= scissor_y1)
934
scissor_x0 = scissor_y0 = scissor_x1 = scissor_y1 = scissor_y_start = 0;
937
/* We store the entry coordinates in Cogl coordinate space
938
* but OpenGL requires the window origin to be the bottom
939
* left so we may need to convert the incoming coordinates.
941
* NB: Cogl forces all offscreen rendering to be done upside
942
* down so in this case no conversion is needed.
945
if (cogl_is_offscreen (framebuffer))
946
scissor_y_start = scissor_y0;
949
int framebuffer_height =
950
cogl_framebuffer_get_height (framebuffer);
952
scissor_y_start = framebuffer_height - scissor_y1;
956
COGL_NOTE (CLIPPING, "Flushing scissor to (%i, %i, %i, %i)",
957
scissor_x0, scissor_y0,
958
scissor_x1, scissor_y1);
960
GE (ctx, glEnable (GL_SCISSOR_TEST));
961
GE (ctx, glScissor (scissor_x0, scissor_y_start,
962
scissor_x1 - scissor_x0,
963
scissor_y1 - scissor_y0));
965
/* Add all of the entries. This will end up adding them in the
966
reverse order that they were specified but as all of the clips
967
are intersecting it should work out the same regardless of the
969
for (entry = stack; entry; entry = entry->parent)
973
case COGL_CLIP_STACK_PATH:
975
CoglClipStackPath *path_entry = (CoglClipStackPath *) entry;
977
COGL_NOTE (CLIPPING, "Adding stencil clip for path");
979
add_stencil_clip_path (framebuffer,
980
path_entry->matrix_entry,
982
using_stencil_buffer,
985
using_stencil_buffer = TRUE;
988
case COGL_CLIP_STACK_PRIMITIVE:
990
CoglClipStackPrimitive *primitive_entry =
991
(CoglClipStackPrimitive *) entry;
993
COGL_NOTE (CLIPPING, "Adding stencil clip for primitive");
995
add_stencil_clip_primitive (framebuffer,
996
primitive_entry->matrix_entry,
997
primitive_entry->primitive,
998
primitive_entry->bounds_x1,
999
primitive_entry->bounds_y1,
1000
primitive_entry->bounds_x2,
1001
primitive_entry->bounds_y2,
1002
using_stencil_buffer,
1005
using_stencil_buffer = TRUE;
1008
case COGL_CLIP_STACK_RECT:
1010
CoglClipStackRect *rect = (CoglClipStackRect *) entry;
1012
/* We don't need to do anything extra if the clip for this
1013
rectangle was entirely described by its scissor bounds */
1014
if (!rect->can_be_scissor)
1016
/* If we support clip planes and we haven't already used
1017
them then use that instead */
1018
if (has_clip_planes)
1020
COGL_NOTE (CLIPPING,
1021
"Adding clip planes clip for rectangle");
1023
set_clip_planes (framebuffer,
1029
using_clip_planes = TRUE;
1030
/* We can't use clip planes a second time */
1031
has_clip_planes = FALSE;
1035
COGL_NOTE (CLIPPING, "Adding stencil clip for rectangle");
1037
add_stencil_clip_rectangle (framebuffer,
1043
!using_stencil_buffer);
1044
using_stencil_buffer = TRUE;
1049
case COGL_CLIP_STACK_WINDOW_RECT:
1051
/* We don't need to do anything for window space rectangles because
1052
* their functionality is entirely implemented by the entry bounding
1057
/* Enabling clip planes is delayed to now so that they won't affect
1058
setting up the stencil buffer */
1059
if (using_clip_planes)
1060
enable_clip_planes ();
1062
ctx->current_clip_stack_uses_stencil = using_stencil_buffer;
466
ctx->driver_vtable->clip_stack_flush (stack, framebuffer);