static void set_clip_plane (GLint plane_num, const float *vertex_a, const float *vertex_b) { #if defined (HAVE_COGL_GLES2) || defined (HAVE_COGL_GLES) GLfloat plane[4]; #else GLdouble plane[4]; #endif GLfloat angle; CoglHandle framebuffer = _cogl_get_framebuffer (); CoglMatrixStack *modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); CoglMatrixStack *projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); CoglMatrix inverse_projection; _COGL_GET_CONTEXT (ctx, NO_RETVAL); _cogl_matrix_stack_get_inverse (projection_stack, &inverse_projection); /* Calculate the angle between the axes and the line crossing the two points */ angle = atan2f (vertex_b[1] - vertex_a[1], vertex_b[0] - vertex_a[0]) * (180.0/G_PI); _cogl_matrix_stack_push (modelview_stack); /* Load the inverse of the projection matrix so we can specify the plane * in screen coordinates */ _cogl_matrix_stack_set (modelview_stack, &inverse_projection); /* Rotate about point a */ _cogl_matrix_stack_translate (modelview_stack, vertex_a[0], vertex_a[1], vertex_a[2]); /* Rotate the plane by the calculated angle so that it will connect the two points */ _cogl_matrix_stack_rotate (modelview_stack, angle, 0.0f, 0.0f, 1.0f); _cogl_matrix_stack_translate (modelview_stack, -vertex_a[0], -vertex_a[1], -vertex_a[2]); _cogl_matrix_stack_flush_to_gl (modelview_stack, COGL_MATRIX_MODELVIEW); plane[0] = 0; plane[1] = -1.0; plane[2] = 0; plane[3] = vertex_a[1]; #if defined (HAVE_COGL_GLES2) || defined (HAVE_COGL_GLES) GE( glClipPlanef (plane_num, plane) ); #else GE( glClipPlane (plane_num, plane) ); #endif _cogl_matrix_stack_pop (modelview_stack); }
void _cogl_flush_clip_state (CoglClipStackState *clip_state) { CoglClipStack *stack; int has_clip_planes; gboolean using_clip_planes = FALSE; gboolean using_stencil_buffer = FALSE; GList *node; int scissor_x0 = 0; int scissor_y0 = 0; int scissor_x1 = G_MAXINT; int scissor_y1 = G_MAXINT; CoglMatrixStack *modelview_stack = _cogl_framebuffer_get_modelview_stack (_cogl_get_framebuffer ()); if (!clip_state->stack_dirty) return; /* The current primitive journal does not support tracking changes to the * clip stack... */ _cogl_journal_flush (); /* XXX: the handling of clipping is quite complex. It may involve use of * the Cogl Journal or other Cogl APIs which may end up recursively * wanting to ensure the clip state is flushed. We need to ensure we * don't recurse infinitely... */ clip_state->stack_dirty = FALSE; has_clip_planes = cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES); stack = clip_state->stacks->data; clip_state->stencil_used = FALSE; disable_clip_planes (); disable_stencil_buffer (); GE (glDisable (GL_SCISSOR_TEST)); /* If the stack is empty then there's nothing else to do */ if (stack->stack_top == NULL) return; /* Find the bottom of the stack */ for (node = stack->stack_top; node->next; node = node->next); /* Re-add every entry from the bottom of the stack up */ for (; node; node = node->prev) { gpointer entry = node->data; CoglClipStackEntryType type = *(CoglClipStackEntryType *) entry; if (type == COGL_CLIP_STACK_PATH) { CoglClipStackEntryPath *path = (CoglClipStackEntryPath *) entry; _cogl_matrix_stack_push (modelview_stack); _cogl_matrix_stack_set (modelview_stack, &path->matrix); _cogl_add_path_to_stencil_buffer (path->path_nodes_min, path->path_nodes_max, path->path_size, path->path, using_stencil_buffer, TRUE); _cogl_matrix_stack_pop (modelview_stack); using_stencil_buffer = TRUE; /* We can't use clip planes any more */ has_clip_planes = FALSE; } else if (type == COGL_CLIP_STACK_RECT) { CoglClipStackEntryRect *rect = (CoglClipStackEntryRect *) entry; _cogl_matrix_stack_push (modelview_stack); _cogl_matrix_stack_set (modelview_stack, &rect->matrix); /* If this is the first entry and we support clip planes then use that instead */ if (has_clip_planes) { set_clip_planes (rect->x0, rect->y0, rect->x1, rect->y1); using_clip_planes = TRUE; /* We can't use clip planes a second time */ has_clip_planes = FALSE; } else { add_stencil_clip_rectangle (rect->x0, rect->y0, rect->x1, rect->y1, !using_stencil_buffer); using_stencil_buffer = TRUE; } _cogl_matrix_stack_pop (modelview_stack); } else { /* Get the intersection of all window space rectangles in the clip * stack */ CoglClipStackEntryWindowRect *window_rect = entry; scissor_x0 = MAX (scissor_x0, window_rect->x0); scissor_y0 = MAX (scissor_y0, window_rect->y0); scissor_x1 = MIN (scissor_x1, window_rect->x1); scissor_y1 = MIN (scissor_y1, window_rect->y1); } } /* Enabling clip planes is delayed to now so that they won't affect setting up the stencil buffer */ if (using_clip_planes) enable_clip_planes (); if (scissor_x0 >= scissor_x1 || scissor_y0 >= scissor_y1) scissor_x0 = scissor_y0 = scissor_x1 = scissor_y1 = 0; if (!(scissor_x0 == 0 && scissor_y0 == 0 && scissor_x1 == G_MAXINT && scissor_y1 == G_MAXINT)) { GE (glEnable (GL_SCISSOR_TEST)); GE (glScissor (scissor_x0, scissor_y0, scissor_x1 - scissor_x0, scissor_y1 - scissor_y0)); } clip_state->stencil_used = using_stencil_buffer; }
void add_stencil_clip_rectangle (float x_1, float y_1, float x_2, float y_2, gboolean first) { CoglHandle current_source; CoglHandle framebuffer = _cogl_get_framebuffer (); _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* We don't log changes to the stencil buffer so need to flush any * batched geometry before we start... */ _cogl_journal_flush (); _cogl_framebuffer_flush_state (framebuffer, 0); /* temporarily swap in our special stenciling material */ current_source = cogl_handle_ref (ctx->source_material); cogl_set_source (ctx->stencil_material); if (first) { GE( glEnable (GL_STENCIL_TEST) ); /* Initially disallow everything */ GE( glClearStencil (0) ); GE( glClear (GL_STENCIL_BUFFER_BIT) ); /* Punch out a hole to allow the rectangle */ GE( glStencilFunc (GL_NEVER, 0x1, 0x1) ); GE( glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE) ); cogl_rectangle (x_1, y_1, x_2, y_2); } else { CoglMatrixStack *modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); CoglMatrixStack *projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); /* Add one to every pixel of the stencil buffer in the rectangle */ GE( glStencilFunc (GL_NEVER, 0x1, 0x3) ); GE( glStencilOp (GL_INCR, GL_INCR, GL_INCR) ); cogl_rectangle (x_1, y_1, x_2, y_2); /* make sure our rectangle hits the stencil buffer before we * change the stencil operation */ _cogl_journal_flush (); /* Subtract one from all pixels in the stencil buffer so that only pixels where both the original stencil buffer and the rectangle are set will be valid */ GE( glStencilOp (GL_DECR, GL_DECR, GL_DECR) ); _cogl_matrix_stack_push (projection_stack); _cogl_matrix_stack_load_identity (projection_stack); _cogl_matrix_stack_push (modelview_stack); _cogl_matrix_stack_load_identity (modelview_stack); cogl_rectangle (-1.0, -1.0, 1.0, 1.0); _cogl_matrix_stack_pop (modelview_stack); _cogl_matrix_stack_pop (projection_stack); } /* make sure our rectangles hit the stencil buffer before we restore * the stencil function / operation */ _cogl_journal_flush (); /* Restore the stencil mode */ GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) ); GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) ); /* restore the original source material */ cogl_set_source (current_source); cogl_handle_unref (current_source); }
static void set_clip_plane (CoglFramebuffer *framebuffer, GLint plane_num, const float *vertex_a, const float *vertex_b) { GLfloat planef[4]; double planed[4]; GLfloat angle; CoglMatrixStack *modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); CoglMatrixStack *projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); CoglMatrix inverse_projection; _COGL_GET_CONTEXT (ctx, NO_RETVAL); _cogl_matrix_stack_get_inverse (projection_stack, &inverse_projection); /* Calculate the angle between the axes and the line crossing the two points */ angle = atan2f (vertex_b[1] - vertex_a[1], vertex_b[0] - vertex_a[0]) * (180.0/G_PI); _cogl_matrix_stack_push (modelview_stack); /* Load the inverse of the projection matrix so we can specify the plane * in screen coordinates */ _cogl_matrix_stack_set (modelview_stack, &inverse_projection); /* Rotate about point a */ _cogl_matrix_stack_translate (modelview_stack, vertex_a[0], vertex_a[1], vertex_a[2]); /* Rotate the plane by the calculated angle so that it will connect the two points */ _cogl_matrix_stack_rotate (modelview_stack, angle, 0.0f, 0.0f, 1.0f); _cogl_matrix_stack_translate (modelview_stack, -vertex_a[0], -vertex_a[1], -vertex_a[2]); /* Clip planes can only be used when a fixed function backend is in use so we know we can directly push this matrix to the builtin state */ _cogl_matrix_entry_flush_to_gl_builtins (ctx, modelview_stack->last_entry, COGL_MATRIX_MODELVIEW, framebuffer, FALSE /* don't disable flip */); planef[0] = 0; planef[1] = -1.0; planef[2] = 0; planef[3] = vertex_a[1]; switch (ctx->driver) { default: g_assert_not_reached (); break; case COGL_DRIVER_GLES1: GE( ctx, glClipPlanef (plane_num, planef) ); break; case COGL_DRIVER_GL: planed[0] = planef[0]; planed[1] = planef[1]; planed[2] = planef[2]; planed[3] = planef[3]; GE( ctx, glClipPlane (plane_num, planed) ); break; } _cogl_matrix_stack_pop (modelview_stack); }
/* Reads back the contents of a texture by rendering it to the framebuffer * and reading back the resulting pixels. * * NB: Normally this approach isn't normally used since we can just use * glGetTexImage, but may be used as a fallback in some circumstances. */ gboolean _cogl_texture_draw_and_read (CoglHandle handle, CoglBitmap *target_bmp, GLuint target_gl_format, GLuint target_gl_type) { int bpp; CoglFramebuffer *framebuffer; int viewport[4]; CoglBitmap *alpha_bmp; CoglMatrixStack *projection_stack; CoglMatrixStack *modelview_stack; int target_width = _cogl_bitmap_get_width (target_bmp); int target_height = _cogl_bitmap_get_height (target_bmp); int target_rowstride = _cogl_bitmap_get_rowstride (target_bmp); _COGL_GET_CONTEXT (ctx, FALSE); bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888); framebuffer = _cogl_get_draw_buffer (); /* Viewport needs to have some size and be inside the window for this */ _cogl_framebuffer_get_viewport4fv (framebuffer, viewport); if (viewport[0] < 0 || viewport[1] < 0 || viewport[2] <= 0 || viewport[3] <= 0) return FALSE; /* Setup orthographic projection into current viewport (0,0 in top-left * corner to draw the texture upside-down so we match the way cogl_read_pixels * works) */ projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); _cogl_matrix_stack_push (projection_stack); _cogl_matrix_stack_load_identity (projection_stack); _cogl_matrix_stack_ortho (projection_stack, 0, (float)(viewport[2]), (float)(viewport[3]), 0, (float)(0), (float)(100)); modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); _cogl_matrix_stack_push (modelview_stack); _cogl_matrix_stack_load_identity (modelview_stack); /* Direct copy operation */ if (ctx->texture_download_pipeline == COGL_INVALID_HANDLE) { ctx->texture_download_pipeline = cogl_pipeline_new (); cogl_pipeline_set_blend (ctx->texture_download_pipeline, "RGBA = ADD (SRC_COLOR, 0)", NULL); } cogl_push_source (ctx->texture_download_pipeline); cogl_pipeline_set_layer_texture (ctx->texture_download_pipeline, 0, handle); cogl_pipeline_set_layer_combine (ctx->texture_download_pipeline, 0, /* layer */ "RGBA = REPLACE (TEXTURE)", NULL); cogl_pipeline_set_layer_filters (ctx->texture_download_pipeline, 0, COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); do_texture_draw_and_read (handle, target_bmp, viewport); /* Check whether texture has alpha and framebuffer not */ /* FIXME: For some reason even if ALPHA_BITS is 8, the framebuffer still doesn't seem to have an alpha buffer. This might be just a PowerVR issue. GLint r_bits, g_bits, b_bits, a_bits; GE( glGetIntegerv (GL_ALPHA_BITS, &a_bits) ); GE( glGetIntegerv (GL_RED_BITS, &r_bits) ); GE( glGetIntegerv (GL_GREEN_BITS, &g_bits) ); GE( glGetIntegerv (GL_BLUE_BITS, &b_bits) ); printf ("R bits: %d\n", r_bits); printf ("G bits: %d\n", g_bits); printf ("B bits: %d\n", b_bits); printf ("A bits: %d\n", a_bits); */ if ((cogl_texture_get_format (handle) & COGL_A_BIT)/* && a_bits == 0*/) { guint8 *srcdata; guint8 *dstdata; guint8 *srcpixel; guint8 *dstpixel; int x,y; int alpha_rowstride = bpp * target_width; if ((dstdata = _cogl_bitmap_map (target_bmp, COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_MAP_HINT_DISCARD)) == NULL) return FALSE; srcdata = g_malloc (alpha_rowstride * target_height); /* Create temp bitmap for alpha values */ alpha_bmp = _cogl_bitmap_new_from_data (srcdata, COGL_PIXEL_FORMAT_RGBA_8888, target_width, target_height, alpha_rowstride, (CoglBitmapDestroyNotify) g_free, NULL); /* Draw alpha values into RGB channels */ cogl_pipeline_set_layer_combine (ctx->texture_download_pipeline, 0, /* layer */ "RGBA = REPLACE (TEXTURE[A])", NULL); do_texture_draw_and_read (handle, alpha_bmp, viewport); /* Copy temp R to target A */ for (y=0; y<target_height; ++y) { for (x=0; x<target_width; ++x) { srcpixel = srcdata + x*bpp; dstpixel = dstdata + x*bpp; dstpixel[3] = srcpixel[0]; } srcdata += alpha_rowstride; dstdata += target_rowstride; } _cogl_bitmap_unmap (target_bmp); cogl_object_unref (alpha_bmp); } /* Restore old state */ _cogl_matrix_stack_pop (modelview_stack); _cogl_matrix_stack_pop (projection_stack); /* restore the original pipeline */ cogl_pop_source (); return TRUE; }