From 559495caf71ba38b38950750e0a3c094b61b8ed3 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 29 May 2008 13:29:04 +0000 Subject: [PATCH] * clutter/cogl/gles/cogl-gles2-wrapper.h (CoglGles2Wrapper): Added uniforms for alpha testing. * clutter/cogl/gles/cogl-gles2-wrapper.c (cogl_gles2_wrapper_init): Get the uniforms for alpha testing settings. (cogl_wrap_glEnable, cogl_wrap_glDisable): Enable/disable alpha testing. (cogl_wrap_glAlphaFunc): Filled in the wrapper. * clutter/cogl/gles/cogl-fixed-fragment-shader.glsl: Added alpha testing. * clutter/cogl/gles/cogl-gles2-wrapper.h: * clutter/cogl/gles/cogl-gles2-wrapper.c (cogl_wrap_glGetIntegerv): Added a wrapper for glGetIntegerv so that it can report zero clip planes. * clutter/cogl/gles/cogl.c: * clutter/cogl/gles/cogl-texture.c: Use the wrapped version of glGetIntegerv * clutter/cogl/gles/cogl-primitives.c (_cogl_path_fill_nodes): Use _cogl_features_available to check for the stencil buffer instead of an #ifdef. The stencil buffer is available in the default profile for the GLES 2 simulator. --- gles/cogl-fixed-fragment-shader.glsl | 51 +++++ gles/cogl-gles2-wrapper.c | 46 +++- gles/cogl-gles2-wrapper.h | 6 + gles/cogl-primitives.c | 322 ++++++++++++++------------- gles/cogl-texture.c | 10 +- gles/cogl.c | 12 +- 6 files changed, 275 insertions(+), 172 deletions(-) diff --git a/gles/cogl-fixed-fragment-shader.glsl b/gles/cogl-fixed-fragment-shader.glsl index f32135399..bb4ee4dcb 100644 --- a/gles/cogl-fixed-fragment-shader.glsl +++ b/gles/cogl-fixed-fragment-shader.glsl @@ -12,6 +12,20 @@ uniform bool alpha_only; uniform bool fog_enabled; uniform vec4 fog_color; +/* Alpha test options */ +uniform bool alpha_test_enabled; +uniform int alpha_test_func; +uniform float alpha_test_ref; + +/* Alpha test functions */ +const int GL_NEVER = 0x0200; +const int GL_LESS = 0x0201; +const int GL_EQUAL = 0x0202; +const int GL_LEQUAL = 0x0203; +const int GL_GREATER = 0x0204; +const int GL_NOTEQUAL = 0x0205; +const int GL_GEQUAL = 0x0206; + void main (void) { @@ -35,4 +49,41 @@ main (void) if (fog_enabled) /* Mix the calculated color with the fog color */ gl_FragColor.rgb = mix (fog_color.rgb, gl_FragColor.rgb, fog_amount); + + /* Alpha testing */ + if (alpha_test_enabled) + { + if (alpha_test_func == GL_NEVER) + discard; + else if (alpha_test_func == GL_LESS) + { + if (gl_FragColor.a >= alpha_test_ref) + discard; + } + else if (alpha_test_func == GL_EQUAL) + { + if (gl_FragColor.a != alpha_test_ref) + discard; + } + else if (alpha_test_func == GL_LEQUAL) + { + if (gl_FragColor.a > alpha_test_ref) + discard; + } + else if (alpha_test_func == GL_GREATER) + { + if (gl_FragColor.a <= alpha_test_ref) + discard; + } + else if (alpha_test_func == GL_NOTEQUAL) + { + if (gl_FragColor.a == alpha_test_ref) + discard; + } + else if (alpha_test_func == GL_GEQUAL) + { + if (gl_FragColor.a < alpha_test_ref) + discard; + } + } } diff --git a/gles/cogl-gles2-wrapper.c b/gles/cogl-gles2-wrapper.c index 6a09898ca..47d11ffc5 100644 --- a/gles/cogl-gles2-wrapper.c +++ b/gles/cogl-gles2-wrapper.c @@ -164,6 +164,13 @@ cogl_gles2_wrapper_init (CoglGles2Wrapper *wrapper) wrapper->fog_color_uniform = glGetUniformLocation (wrapper->program, "fog_color"); + wrapper->alpha_test_enabled_uniform + = glGetUniformLocation (wrapper->program, "alpha_test_enabled"); + wrapper->alpha_test_func_uniform + = glGetUniformLocation (wrapper->program, "alpha_test_func"); + wrapper->alpha_test_ref_uniform + = glGetUniformLocation (wrapper->program, "alpha_test_ref"); + /* Always use the first texture unit */ glUniform1i (wrapper->bound_texture_uniform, 0); @@ -184,6 +191,10 @@ cogl_gles2_wrapper_init (CoglGles2Wrapper *wrapper) cogl_wrap_glFogx (GL_FOG_START, 0); cogl_wrap_glFogx (GL_FOG_END, 1); cogl_wrap_glFogxv (GL_FOG_COLOR, default_fog_color); + + /* Initialize alpha testing */ + cogl_wrap_glDisable (GL_ALPHA_TEST); + cogl_wrap_glAlphaFunc (GL_ALWAYS, 0.0f); } void @@ -567,6 +578,10 @@ cogl_wrap_glEnable (GLenum cap) glUniform1i (w->fog_enabled_uniform, GL_TRUE); break; + case GL_ALPHA_TEST: + glUniform1i (w->alpha_test_enabled_uniform, GL_TRUE); + break; + default: glEnable (cap); } @@ -587,6 +602,10 @@ cogl_wrap_glDisable (GLenum cap) glUniform1i (w->fog_enabled_uniform, GL_FALSE); break; + case GL_ALPHA_TEST: + glUniform1i (w->alpha_test_enabled_uniform, GL_FALSE); + break; + default: glDisable (cap); } @@ -629,7 +648,15 @@ cogl_wrap_glDisableClientState (GLenum array) void cogl_wrap_glAlphaFunc (GLenum func, GLclampf ref) { - /* FIXME */ + _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL); + + if (ref < 0.0f) + ref = 0.0f; + else if (ref > 1.0f) + ref = 1.0f; + + glUniform1i (w->alpha_test_func_uniform, func); + glUniform1f (w->alpha_test_ref_uniform, ref); } void @@ -656,6 +683,23 @@ cogl_gles2_float_array_to_fixed (int size, const GLfloat *floats, *(fixeds++) = CLUTTER_FLOAT_TO_FIXED (*(floats++)); } +void +cogl_wrap_glGetIntegerv (GLenum pname, GLint *params) +{ + _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL); + + switch (pname) + { + case GL_MAX_CLIP_PLANES: + *params = 0; + break; + + default: + glGetIntegerv (pname, params); + break; + } +} + void cogl_wrap_glGetFixedv (GLenum pname, GLfixed *params) { diff --git a/gles/cogl-gles2-wrapper.h b/gles/cogl-gles2-wrapper.h index b1adf8ca7..b2c477e2c 100644 --- a/gles/cogl-gles2-wrapper.h +++ b/gles/cogl-gles2-wrapper.h @@ -57,6 +57,10 @@ struct _CoglGles2Wrapper GLint fog_end_uniform; GLint fog_color_uniform; + GLint alpha_test_enabled_uniform; + GLint alpha_test_func_uniform; + GLint alpha_test_ref_uniform; + GLuint matrix_mode; GLfloat modelview_stack[COGL_GLES2_MODELVIEW_STACK_SIZE * 16]; GLuint modelview_stack_pos; @@ -149,6 +153,7 @@ void cogl_wrap_glColor4x (GLclampx r, GLclampx g, GLclampx b, GLclampx a); void cogl_wrap_glClipPlanex (GLenum plane, GLfixed *equation); +void cogl_wrap_glGetIntegerv (GLenum pname, GLint *params); void cogl_wrap_glGetFixedv (GLenum pname, GLfixed *params); void cogl_wrap_glFogx (GLenum pname, GLfixed param); @@ -191,6 +196,7 @@ void cogl_gles2_wrapper_bind_texture (GLenum target, GLuint texture, #define cogl_wrap_glAlphaFunc glAlphaFunc #define cogl_wrap_glColor4x glColor4x #define cogl_wrap_glClipPlanex glClipPlanex +#define cogl_wrap_glGetIntegerv glGetIntegerv #define cogl_wrap_glGetFixedv glGetFixedv #define cogl_wrap_glFogx glFogx #define cogl_wrap_glFogxv glFogxv diff --git a/gles/cogl-primitives.c b/gles/cogl-primitives.c index bc7414670..1fe6407a8 100644 --- a/gles/cogl-primitives.c +++ b/gles/cogl-primitives.c @@ -172,186 +172,188 @@ _cogl_path_fill_nodes () bounds_w = CLUTTER_FIXED_CEIL (ctx->path_nodes_max.x - ctx->path_nodes_min.x); bounds_h = CLUTTER_FIXED_CEIL (ctx->path_nodes_max.y - ctx->path_nodes_min.y); -#if GOT_WORKING_STENCIL_BUFFER - - GE( glClear (GL_STENCIL_BUFFER_BIT) ); + if (cogl_features_available (COGL_FEATURE_STENCIL_BUFFER)) + { + GE( glClear (GL_STENCIL_BUFFER_BIT) ); - GE( cogl_wrap_glEnable (GL_STENCIL_TEST) ); - GE( glStencilFunc (GL_ALWAYS, 0x0, 0x0) ); - GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) ); - GE( glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE) ); + GE( cogl_wrap_glEnable (GL_STENCIL_TEST) ); + GE( glStencilFunc (GL_ALWAYS, 0x0, 0x0) ); + GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) ); + GE( glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE) ); - cogl_enable (COGL_ENABLE_VERTEX_ARRAY - | (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0)); + cogl_enable (COGL_ENABLE_VERTEX_ARRAY + | (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0)); - GE( cogl_wrap_glVertexPointer (2, GL_FIXED, 0, ctx->path_nodes) ); - GE( cogl_wrap_glDrawArrays (GL_TRIANGLE_FAN, 0, ctx->path_nodes_size) ); + GE( cogl_wrap_glVertexPointer (2, GL_FIXED, 0, ctx->path_nodes) ); + GE( cogl_wrap_glDrawArrays (GL_TRIANGLE_FAN, 0, ctx->path_nodes_size) ); - GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) ); - GE( glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) ); - GE( glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) ); + GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) ); + GE( glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) ); + GE( glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) ); + cogl_rectangle (bounds_x, bounds_y, bounds_w, bounds_h); - cogl_rectangle (bounds_x, bounds_y, bounds_w, bounds_h); - - GE( cogl_wrap_glDisable (GL_STENCIL_TEST) ); -#else - { - /* This is our edge list it stores intersections between our curve and - * scanlines, it should probably be implemented with a data structure - * that has smaller overhead for inserting the curve/scanline intersections. - */ - GSList *scanlines[bounds_h]; + GE( cogl_wrap_glDisable (GL_STENCIL_TEST) ); + } + else + { + /* This is our edge list it stores intersections between our + * curve and scanlines, it should probably be implemented with a + * data structure that has smaller overhead for inserting the + * curve/scanline intersections. + */ + GSList *scanlines[bounds_h]; - gint i; - gint prev_x; - gint prev_y; - gint first_x; - gint first_y; - gint lastdir=-2; /* last direction we vere moving */ - gint lastline=-1; /* the previous scanline we added to */ + gint i; + gint prev_x; + gint prev_y; + gint first_x; + gint first_y; + gint lastdir=-2; /* last direction we vere moving */ + gint lastline=-1; /* the previous scanline we added to */ - /* clear scanline intersection lists */ - for (i=0; i < bounds_h; i++) - scanlines[i]=NULL; + /* clear scanline intersection lists */ + for (i=0; i < bounds_h; i++) + scanlines[i]=NULL; - first_x = prev_x = CLUTTER_FIXED_TO_INT (ctx->path_nodes[0].x); - first_y = prev_y = CLUTTER_FIXED_TO_INT (ctx->path_nodes[0].y); + first_x = prev_x = CLUTTER_FIXED_TO_INT (ctx->path_nodes[0].x); + first_y = prev_y = CLUTTER_FIXED_TO_INT (ctx->path_nodes[0].y); + + /* create scanline intersection list */ + for (i=1; ipath_nodes_size; i++) + { + gint dest_x = CLUTTER_FIXED_TO_INT (ctx->path_nodes[i].x); + gint dest_y = CLUTTER_FIXED_TO_INT (ctx->path_nodes[i].y); + gint ydir; + gint dx; + gint dy; + gint y; + + fill_close: + dx = dest_x - prev_x; + dy = dest_y - prev_y; + + if (dy < 0) + ydir = -1; + else if (dy > 0) + ydir = 1; + else + ydir = 0; + + /* do linear interpolation between vertexes */ + for (y=prev_y; y!= dest_y; y += ydir) + { + + /* only add a point if the scanline has changed and we're + * within bounds. + */ + if (y-bounds_y >= 0 && + y-bounds_y < bounds_h && + lastline != y) + { + gint x = prev_x + (dx * (y-prev_y)) / dy; + + scanlines[ y - bounds_y ]= + g_slist_insert_sorted (scanlines[ y - bounds_y], + GINT_TO_POINTER(x), + compare_ints); + + if (ydir != lastdir && /* add a double entry when changing */ + lastdir!=-2) /* vertical direction */ + scanlines[ y - bounds_y ]= + g_slist_insert_sorted (scanlines[ y - bounds_y], + GINT_TO_POINTER(x), + compare_ints); + lastdir = ydir; + lastline = y; + } + } + + prev_x = dest_x; + prev_y = dest_y; + + /* if we're on the last knot, fake the first vertex being a + next one */ + if (ctx->path_nodes_size == i+1) + { + dest_x = first_x; + dest_y = first_y; + i++; /* to make the loop finally end */ + goto fill_close; + } + } - /* create scanline intersection list */ - for (i=1; ipath_nodes_size; i++) { - gint dest_x = CLUTTER_FIXED_TO_INT (ctx->path_nodes[i].x); - gint dest_y = CLUTTER_FIXED_TO_INT (ctx->path_nodes[i].y); - gint ydir; - gint dx; - gint dy; - gint y; + gint spans = 0; + gint span_no; + GLfixed *coords; -fill_close: - dx = dest_x - prev_x; - dy = dest_y - prev_y; + /* count number of spans */ + for (i=0; i < bounds_h; i++) + { + GSList *iter = scanlines[i]; + while (iter) + { + GSList *next = iter->next; + if (!next) + { + break; + } + /* draw the segments that should be visible */ + spans ++; + iter = next->next; + } + } + coords = g_malloc0 (spans * sizeof (GLfixed) * 3 * 2 * 2); - if (dy < 0) - ydir = -1; - else if (dy > 0) - ydir = 1; - else - ydir = 0; + span_no = 0; + /* build list of triangles */ + for (i=0; i < bounds_h; i++) + { + GSList *iter = scanlines[i]; + while (iter) + { + GSList *next = iter->next; + GLfixed x0, x1; + GLfixed y0, y1; + if (!next) + break; - /* do linear interpolation between vertexes */ - for (y=prev_y; y!= dest_y; y += ydir) - { + x0 = CLUTTER_INT_TO_FIXED (GPOINTER_TO_INT (iter->data)); + x1 = CLUTTER_INT_TO_FIXED (GPOINTER_TO_INT (next->data)); + y0 = CLUTTER_INT_TO_FIXED (bounds_y + i); + y1 = CLUTTER_INT_TO_FIXED (bounds_y + i + 1) + 2048; + /* render scanlines 1.0625 high to avoid gaps when + transformed */ - /* only add a point if the scanline has changed and we're - * within bounds. - */ - if (y-bounds_y >= 0 && - y-bounds_y < bounds_h && - lastline != y) - { - gint x = prev_x + (dx * (y-prev_y)) / dy; - - scanlines[ y - bounds_y ]= - g_slist_insert_sorted (scanlines[ y - bounds_y], - GINT_TO_POINTER(x), - compare_ints); - - if (ydir != lastdir && /* add a double entry when changing */ - lastdir!=-2) /* vertical direction */ - scanlines[ y - bounds_y ]= - g_slist_insert_sorted (scanlines[ y - bounds_y], - GINT_TO_POINTER(x), - compare_ints); - lastdir = ydir; - lastline = y; - } - } - - prev_x = dest_x; - prev_y = dest_y; - - /* if we're on the last knot, fake the first vertex being a next one */ - if (ctx->path_nodes_size == i+1) - { - dest_x = first_x; - dest_y = first_y; - i++; /* to make the loop finally end */ - goto fill_close; - } - } - - { - gint spans = 0; - gint span_no; - GLfixed *coords; - - /* count number of spans */ - for (i=0; i < bounds_h; i++) - { - GSList *iter = scanlines[i]; - while (iter) - { - GSList *next = iter->next; - if (!next) - { - break; - } - /* draw the segments that should be visible */ - spans ++; - iter = next->next; - } - } - coords = g_malloc0 (spans * sizeof (GLfixed) * 3 * 2 * 2); - - span_no = 0; - /* build list of triangles */ - for (i=0; i < bounds_h; i++) - { - GSList *iter = scanlines[i]; - while (iter) - { - GSList *next = iter->next; - GLfixed x0, x1; - GLfixed y0, y1; - if (!next) - break; - - x0 = CLUTTER_INT_TO_FIXED (GPOINTER_TO_INT (iter->data)); - x1 = CLUTTER_INT_TO_FIXED (GPOINTER_TO_INT (next->data)); - y0 = CLUTTER_INT_TO_FIXED (bounds_y + i); - y1 = CLUTTER_INT_TO_FIXED (bounds_y + i + 1) + 2048; - /* render scanlines 1.0625 high to avoid gaps when transformed */ - - coords[span_no * 12 + 0] = x0; - coords[span_no * 12 + 1] = y0; - coords[span_no * 12 + 2] = x1; - coords[span_no * 12 + 3] = y0; - coords[span_no * 12 + 4] = x1; - coords[span_no * 12 + 5] = y1; - coords[span_no * 12 + 6] = x0; - coords[span_no * 12 + 7] = y0; - coords[span_no * 12 + 8] = x0; - coords[span_no * 12 + 9] = y1; - coords[span_no * 12 + 10] = x1; - coords[span_no * 12 + 11] = y1; - span_no ++; - iter = next->next; - } - } - for (i=0; i < bounds_h; i++) - { - g_slist_free (scanlines[i]); - } + coords[span_no * 12 + 0] = x0; + coords[span_no * 12 + 1] = y0; + coords[span_no * 12 + 2] = x1; + coords[span_no * 12 + 3] = y0; + coords[span_no * 12 + 4] = x1; + coords[span_no * 12 + 5] = y1; + coords[span_no * 12 + 6] = x0; + coords[span_no * 12 + 7] = y0; + coords[span_no * 12 + 8] = x0; + coords[span_no * 12 + 9] = y1; + coords[span_no * 12 + 10] = x1; + coords[span_no * 12 + 11] = y1; + span_no ++; + iter = next->next; + } + } + for (i=0; i < bounds_h; i++) + { + g_slist_free (scanlines[i]); + } /* render triangles */ cogl_enable (COGL_ENABLE_VERTEX_ARRAY - | (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0)); + | (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0)); GE ( cogl_wrap_glVertexPointer (2, GL_FIXED, 0, coords ) ); GE ( cogl_wrap_glDrawArrays (GL_TRIANGLES, 0, spans * 2 * 3)); g_free (coords); - } - } -#endif + } + } } diff --git a/gles/cogl-texture.c b/gles/cogl-texture.c index 70362239e..97021592f 100644 --- a/gles/cogl-texture.c +++ b/gles/cogl-texture.c @@ -381,7 +381,7 @@ _cogl_texture_download_from_gl (CoglTexture *tex, bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888); /* Viewport needs to have some size and be inside the window for this */ - GE( glGetIntegerv (GL_VIEWPORT, viewport) ); + GE( cogl_wrap_glGetIntegerv (GL_VIEWPORT, viewport) ); if (viewport[0] < 0 || viewport[1] < 0 || viewport[2] <= 0 || viewport[3] <= 0) @@ -422,10 +422,10 @@ _cogl_texture_download_from_gl (CoglTexture *tex, 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) ); + GE( cogl_wrap_glGetIntegerv (GL_ALPHA_BITS, &a_bits) ); + GE( cogl_wrap_glGetIntegerv (GL_RED_BITS, &r_bits) ); + GE( cogl_wrap_glGetIntegerv (GL_GREEN_BITS, &g_bits) ); + GE( cogl_wrap_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); diff --git a/gles/cogl.c b/gles/cogl.c index 303d49f9d..5e5cf76f6 100644 --- a/gles/cogl.c +++ b/gles/cogl.c @@ -482,11 +482,11 @@ _cogl_features_init () _COGL_GET_CONTEXT (ctx, NO_RETVAL); - GE( glGetIntegerv (GL_STENCIL_BITS, &stencil_bits) ); + GE( cogl_wrap_glGetIntegerv (GL_STENCIL_BITS, &stencil_bits) ); if (stencil_bits > 0) flags |= COGL_FEATURE_STENCIL_BUFFER; - GE( glGetIntegerv (GL_MAX_CLIP_PLANES, &max_clip_planes) ); + GE( cogl_wrap_glGetIntegerv (GL_MAX_CLIP_PLANES, &max_clip_planes) ); if (max_clip_planes >= 4) flags |= COGL_FEATURE_FOUR_CLIP_PLANES; @@ -538,13 +538,13 @@ void cogl_get_bitmasks (gint *red, gint *green, gint *blue, gint *alpha) { if (red) - GE( glGetIntegerv(GL_RED_BITS, red) ); + GE( cogl_wrap_glGetIntegerv(GL_RED_BITS, red) ); if (green) - GE( glGetIntegerv(GL_GREEN_BITS, green) ); + GE( cogl_wrap_glGetIntegerv(GL_GREEN_BITS, green) ); if (blue) - GE( glGetIntegerv(GL_BLUE_BITS, blue) ); + GE( cogl_wrap_glGetIntegerv(GL_BLUE_BITS, blue) ); if (alpha) - GE( glGetIntegerv(GL_ALPHA_BITS, alpha ) ); + GE( cogl_wrap_glGetIntegerv(GL_ALPHA_BITS, alpha ) ); } void