mirror of
https://github.com/brl/mutter.git
synced 2024-12-03 13:20:41 -05:00
3607a470aa
* clutter/Makefile.am: * clutter/eglx/Makefile.am: * clutter/eglx/clutter-backend-egl.c: * clutter/eglx/clutter-backend-egl.h: * clutter/eglx/clutter-eglx.h: * clutter/eglx/clutter-event-egl.c: * clutter/eglx/clutter-stage-egl.c: * clutter/eglx/clutter-stage-egl.h: * clutter/glx/Makefile.am: * clutter/glx/clutter-backend-glx.c: * clutter/glx/clutter-backend-glx.h: * clutter/glx/clutter-event-glx.c: * clutter/glx/clutter-glx.h: * clutter/glx/clutter-stage-glx.c: * clutter/glx/clutter-stage-glx.h: * clutter/x11/Makefile.am: * clutter/x11/clutter-backend-x11-private.h: * clutter/x11/clutter-backend-x11.c: * clutter/x11/clutter-backend-x11.h: * clutter/x11/clutter-event-x11.c: * clutter/x11/clutter-stage-x11.c: * clutter/x11/clutter-stage-x11.h: * clutter/x11/clutter-x11.h: Create a new X11 backend class of which EGL and GLX 'real' backends then subclass. Effectively shares all X11 code between both backends avoids code duplication and brings many missing features to EGL X backend. Requires some cleanup and testing. (#518) * clutter/cogl/gles/cogl.c: (cogl_color): Add define to use color4ub only if configure finds it. If not fall back to old code. * configure.ac: Drop support for vincent checks. Drop sdles backend. Specifically check for color4ub call.
605 lines
13 KiB
C
605 lines
13 KiB
C
/*
|
|
* Clutter COGL
|
|
*
|
|
* A basic GL/GLES Abstraction/Utility Layer
|
|
*
|
|
* Authored By Matthew Allum <mallum@openedhand.com>
|
|
*
|
|
* Copyright (C) 2007 OpenedHand
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "cogl.h"
|
|
|
|
#include <GLES/gl.h>
|
|
#include <string.h>
|
|
|
|
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
|
#define PIXEL_TYPE GL_UNSIGNED_BYTE
|
|
#else
|
|
#define PIXEL_TYPE GL_UNSIGNED_INT_8_8_8_8_REV
|
|
#endif
|
|
|
|
static gulong __enable_flags = 0;
|
|
|
|
#define COGL_DEBUG 0
|
|
|
|
#if COGL_DEBUG
|
|
struct token_string
|
|
{
|
|
GLuint Token;
|
|
const char *String;
|
|
};
|
|
|
|
static const struct token_string Errors[] = {
|
|
{ GL_NO_ERROR, "no error" },
|
|
{ GL_INVALID_ENUM, "invalid enumerant" },
|
|
{ GL_INVALID_VALUE, "invalid value" },
|
|
{ GL_INVALID_OPERATION, "invalid operation" },
|
|
{ GL_STACK_OVERFLOW, "stack overflow" },
|
|
{ GL_STACK_UNDERFLOW, "stack underflow" },
|
|
{ GL_OUT_OF_MEMORY, "out of memory" },
|
|
#ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT
|
|
{ GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "invalid framebuffer operation" },
|
|
#endif
|
|
{ ~0, NULL }
|
|
};
|
|
|
|
static const char*
|
|
error_string(GLenum errorCode)
|
|
{
|
|
int i;
|
|
for (i = 0; Errors[i].String; i++) {
|
|
if (Errors[i].Token == errorCode)
|
|
return Errors[i].String;
|
|
}
|
|
return "unknown";
|
|
}
|
|
#endif
|
|
|
|
#if COGL_DEBUG
|
|
#define GE(x...) { \
|
|
GLenum err; \
|
|
(x); \
|
|
fprintf(stderr, "%s\n", #x); \
|
|
while ((err = glGetError()) != GL_NO_ERROR) { \
|
|
fprintf(stderr, "glError: %s caught at %s:%u\n", \
|
|
(char *)error_string(err), \
|
|
__FILE__, __LINE__); \
|
|
} \
|
|
}
|
|
#else
|
|
#define GE(x) (x);
|
|
#endif
|
|
|
|
CoglFuncPtr
|
|
cogl_get_proc_address (const gchar* name)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
gboolean
|
|
cogl_check_extension (const gchar *name, const gchar *ext)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
cogl_paint_init (const ClutterColor *color)
|
|
{
|
|
#if COGL_DEBUG
|
|
fprintf(stderr, "\n ============== Paint Start ================ \n");
|
|
#endif
|
|
|
|
glClearColorx ((color->red << 16) / 0xff,
|
|
(color->green << 16) / 0xff,
|
|
(color->blue << 16) / 0xff,
|
|
0xff);
|
|
|
|
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
|
glDisable (GL_LIGHTING);
|
|
glDisable (GL_DEPTH_TEST);
|
|
|
|
cogl_enable (CGL_ENABLE_BLEND);
|
|
|
|
glTexEnvx (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
}
|
|
|
|
/* FIXME: inline most of these */
|
|
void
|
|
cogl_push_matrix (void)
|
|
{
|
|
GE( glPushMatrix() );
|
|
}
|
|
|
|
void
|
|
cogl_pop_matrix (void)
|
|
{
|
|
GE( glPopMatrix() );
|
|
}
|
|
|
|
void
|
|
cogl_scale (ClutterFixed x, ClutterFixed y)
|
|
{
|
|
GE( glScalex (x, y, CFX_ONE) );
|
|
}
|
|
|
|
void
|
|
cogl_translatex (ClutterFixed x, ClutterFixed y, ClutterFixed z)
|
|
{
|
|
GE( glTranslatex (x, y, z) );
|
|
}
|
|
|
|
void
|
|
cogl_translate (gint x, gint y, gint z)
|
|
{
|
|
GE( glTranslatex (CLUTTER_INT_TO_FIXED(x),
|
|
CLUTTER_INT_TO_FIXED(y),
|
|
CLUTTER_INT_TO_FIXED(z)) );
|
|
}
|
|
|
|
void
|
|
cogl_rotatex (ClutterFixed angle,
|
|
ClutterFixed x,
|
|
ClutterFixed y,
|
|
ClutterFixed z)
|
|
{
|
|
GE( glRotatex (angle,x,y,z) );
|
|
}
|
|
|
|
void
|
|
cogl_rotate (gint angle, gint x, gint y, gint z)
|
|
{
|
|
GE( glRotatex (CLUTTER_INT_TO_FIXED(angle),
|
|
CLUTTER_INT_TO_FIXED(x),
|
|
CLUTTER_INT_TO_FIXED(y),
|
|
CLUTTER_INT_TO_FIXED(z)) );
|
|
}
|
|
|
|
void
|
|
cogl_enable (gulong flags)
|
|
{
|
|
/* This function essentially caches glEnable state() in the
|
|
* hope of lessening number GL traffic.
|
|
*/
|
|
if (flags & CGL_ENABLE_BLEND)
|
|
{
|
|
if (!(__enable_flags & CGL_ENABLE_BLEND))
|
|
{
|
|
GE( glEnable (GL_BLEND) );
|
|
GE( glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) );
|
|
}
|
|
__enable_flags |= CGL_ENABLE_BLEND;
|
|
}
|
|
else if (__enable_flags & CGL_ENABLE_BLEND)
|
|
{
|
|
GE( glDisable (GL_BLEND) );
|
|
__enable_flags &= ~CGL_ENABLE_BLEND;
|
|
}
|
|
|
|
if (flags & CGL_ENABLE_TEXTURE_2D)
|
|
{
|
|
if (!(__enable_flags & CGL_ENABLE_TEXTURE_2D))
|
|
GE( glEnable (GL_TEXTURE_2D) );
|
|
__enable_flags |= CGL_ENABLE_TEXTURE_2D;
|
|
}
|
|
else if (__enable_flags & CGL_ENABLE_TEXTURE_2D)
|
|
{
|
|
GE( glDisable (GL_TEXTURE_2D) );
|
|
__enable_flags &= ~CGL_ENABLE_TEXTURE_2D;
|
|
}
|
|
|
|
#if 0
|
|
if (flags & CGL_ENABLE_TEXTURE_RECT)
|
|
{
|
|
if (!(__enable_flags & CGL_ENABLE_TEXTURE_RECT))
|
|
glEnable (GL_TEXTURE_RECTANGLE_ARB);
|
|
|
|
__enable_flags |= CGL_ENABLE_TEXTURE_RECT;
|
|
}
|
|
else if (__enable_flags & CGL_ENABLE_TEXTURE_RECT)
|
|
{
|
|
glDisable (GL_TEXTURE_RECTANGLE_ARB);
|
|
__enable_flags &= ~CGL_ENABLE_TEXTURE_RECT;
|
|
}
|
|
#endif
|
|
|
|
if (flags & CGL_ENABLE_ALPHA_TEST)
|
|
{
|
|
if (!(__enable_flags & CGL_ENABLE_ALPHA_TEST))
|
|
glEnable (GL_ALPHA_TEST);
|
|
|
|
__enable_flags |= CGL_ENABLE_ALPHA_TEST;
|
|
}
|
|
else if (__enable_flags & CGL_ENABLE_ALPHA_TEST)
|
|
{
|
|
glDisable (GL_ALPHA_TEST);
|
|
__enable_flags &= ~CGL_ENABLE_ALPHA_TEST;
|
|
}
|
|
}
|
|
|
|
void
|
|
cogl_color (const ClutterColor *color)
|
|
{
|
|
#if HAVE_GLES_COLOR4UB
|
|
/*
|
|
* GLES 1.1 does actually have this function, it's in the header file but
|
|
* missing in the reference manual (and SDK):
|
|
*
|
|
* http://www.khronos.org/egl/headers/1_1/gl.h
|
|
*/
|
|
GE( glColor4ub (color->red,
|
|
color->green,
|
|
color->blue,
|
|
color->alpha) );
|
|
#else
|
|
/* conversion can cause issues with picking on some gles implementations */
|
|
GE( glColor4x ((color->red << 16) / 0xff,
|
|
(color->green << 16) / 0xff,
|
|
(color->blue << 16) / 0xff,
|
|
(color->alpha << 16) / 0xff));
|
|
#endif
|
|
}
|
|
|
|
void
|
|
cogl_clip_set (const ClutterGeometry *clip)
|
|
{
|
|
GE( glEnable (GL_STENCIL_TEST) );
|
|
|
|
GE( glClearStencil (0) );
|
|
GE( glClear (GL_STENCIL_BUFFER_BIT) );
|
|
|
|
GE( glStencilFunc (GL_NEVER, 0x1, 0x1) );
|
|
GE( glStencilOp (GL_INCR, GL_INCR, GL_INCR) );
|
|
|
|
GE( glColor4x (CFX_ONE, CFX_ONE, CFX_ONE, CFX_ONE ) );
|
|
|
|
cogl_rectangle (clip->x, clip->y, clip->width, clip->height);
|
|
|
|
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
|
|
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
|
|
}
|
|
|
|
void
|
|
cogl_clip_unset (void)
|
|
{
|
|
GE( glDisable (GL_STENCIL_TEST) );
|
|
}
|
|
|
|
gboolean
|
|
cogl_texture_can_size (COGLenum target,
|
|
COGLenum pixel_format,
|
|
COGLenum pixel_type,
|
|
int width,
|
|
int height)
|
|
{
|
|
/* FIXME: How we get this is likely GLES implementation dependant. */
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
cogl_texture_quad (gint x1,
|
|
gint x2,
|
|
gint y1,
|
|
gint y2,
|
|
ClutterFixed tx1,
|
|
ClutterFixed ty1,
|
|
ClutterFixed tx2,
|
|
ClutterFixed ty2)
|
|
{
|
|
#define FIX CLUTTER_INT_TO_FIXED
|
|
|
|
GLfixed quadVerts[] = {
|
|
FIX(x1), FIX(y1), 0,
|
|
FIX(x2), FIX(y1), 0,
|
|
FIX(x2), FIX(y2), 0,
|
|
FIX(x2), FIX(y2), 0,
|
|
FIX(x1), FIX(y2), 0,
|
|
FIX(x1), FIX(y1), 0
|
|
};
|
|
|
|
GLfixed quadTex[] = {
|
|
tx1, ty1,
|
|
tx2, ty1,
|
|
tx2, ty2,
|
|
tx2, ty2,
|
|
tx1, ty2,
|
|
tx1, ty1
|
|
};
|
|
|
|
#undef FIX
|
|
|
|
GE( glEnableClientState(GL_VERTEX_ARRAY) );
|
|
GE( glEnableClientState(GL_TEXTURE_COORD_ARRAY) );
|
|
GE( glVertexPointer(3, GL_FIXED, 0, quadVerts) );
|
|
GE( glTexCoordPointer(2, GL_FIXED, 0, quadTex) );
|
|
GE( glDrawArrays(GL_TRIANGLES, 0, 6) );
|
|
GE( glDisableClientState(GL_TEXTURE_COORD_ARRAY) );
|
|
GE( glDisableClientState(GL_VERTEX_ARRAY) );
|
|
}
|
|
|
|
void
|
|
cogl_textures_create (guint num, COGLuint *textures)
|
|
{
|
|
GE( glGenTextures (num, textures) );
|
|
}
|
|
|
|
void
|
|
cogl_textures_destroy (guint num, const COGLuint *textures)
|
|
{
|
|
GE( glDeleteTextures (num, textures) );
|
|
}
|
|
|
|
void
|
|
cogl_texture_bind (COGLenum target, COGLuint texture)
|
|
{
|
|
GE( glBindTexture (target, texture) );
|
|
}
|
|
|
|
void
|
|
cogl_texture_set_alignment (COGLenum target,
|
|
guint alignment,
|
|
guint row_length)
|
|
{
|
|
/* GE( glPixelStorei (GL_UNPACK_ROW_LENGTH, row_length) ); */
|
|
GE( glPixelStorei (GL_UNPACK_ALIGNMENT, alignment) );
|
|
}
|
|
|
|
void
|
|
cogl_texture_set_filters (COGLenum target,
|
|
COGLenum min_filter,
|
|
COGLenum max_filter)
|
|
{
|
|
GE( glTexParameteri(target, GL_TEXTURE_MAG_FILTER, max_filter) );
|
|
GE( glTexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filter) );
|
|
}
|
|
|
|
void
|
|
cogl_texture_set_wrap (COGLenum target,
|
|
COGLenum wrap_s,
|
|
COGLenum wrap_t)
|
|
{
|
|
GE( glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap_s) );
|
|
GE( glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap_s) );
|
|
}
|
|
|
|
void
|
|
cogl_texture_image_2d (COGLenum target,
|
|
COGLint internal_format,
|
|
gint width,
|
|
gint height,
|
|
COGLenum format,
|
|
COGLenum type,
|
|
const guchar* pixels)
|
|
{
|
|
GE( glTexImage2D (target,
|
|
0,
|
|
format, /* HACK: For gles we set the internal_format equal
|
|
* to the pixel format. This is for RGB data (i.e
|
|
* jpgs) which seem to need a matching internal
|
|
* format rather than RGBA (which is used by GL)
|
|
*.
|
|
* This fix isn't ideal..
|
|
*/
|
|
width,
|
|
height,
|
|
0,
|
|
format,
|
|
type,
|
|
pixels) );
|
|
}
|
|
|
|
void
|
|
cogl_texture_sub_image_2d (COGLenum target,
|
|
gint xoff,
|
|
gint yoff,
|
|
gint width,
|
|
gint height,
|
|
COGLenum format,
|
|
COGLenum type,
|
|
const guchar* pixels)
|
|
{
|
|
GE( glTexSubImage2D (target,
|
|
0,
|
|
xoff,
|
|
yoff,
|
|
width,
|
|
height,
|
|
format,
|
|
type,
|
|
pixels));
|
|
}
|
|
|
|
void
|
|
cogl_rectangle (gint x, gint y, guint width, guint height)
|
|
{
|
|
#define FIX CLUTTER_INT_TO_FIXED
|
|
|
|
GLfixed rect_verts[] = {
|
|
FIX(x), FIX(y),
|
|
FIX((x + width)), FIX(y),
|
|
FIX(x), FIX((y + height)),
|
|
FIX((x + width)), FIX((y + height)),
|
|
};
|
|
|
|
#undef FIX
|
|
|
|
GE( glEnableClientState(GL_VERTEX_ARRAY) );
|
|
GE( glVertexPointer(2, GL_FIXED, 0, rect_verts) );
|
|
GE( glDrawArrays(GL_TRIANGLE_STRIP, 0, 4) );
|
|
GE( glDisableClientState(GL_VERTEX_ARRAY) );
|
|
}
|
|
|
|
/* FIXME: Should use ClutterReal or Fixed */
|
|
void
|
|
cogl_trapezoid (gint y1,
|
|
gint x11,
|
|
gint x21,
|
|
gint y2,
|
|
gint x12,
|
|
gint x22)
|
|
{
|
|
/* FIXME */
|
|
}
|
|
|
|
|
|
void
|
|
cogl_alpha_func (COGLenum func,
|
|
ClutterFixed ref)
|
|
{
|
|
GE( glAlphaFunc (func, CLUTTER_FIXED_TO_FLOAT(ref)) );
|
|
}
|
|
|
|
/*
|
|
* Fixed point implementation of the perspective function
|
|
*/
|
|
void
|
|
cogl_perspective (ClutterFixed fovy,
|
|
ClutterFixed aspect,
|
|
ClutterFixed zNear,
|
|
ClutterFixed zFar)
|
|
{
|
|
ClutterFixed xmax, ymax;
|
|
ClutterFixed x, y, c, d;
|
|
ClutterFixed fovy_rad_half = CFX_MUL (fovy, CFX_PI) / 360;
|
|
|
|
GLfixed m[16];
|
|
|
|
memset (&m[0], 0, sizeof (m));
|
|
|
|
/*
|
|
* Based on the original algorithm in perspective():
|
|
*
|
|
* 1) xmin = -xmax => xmax + xmin == 0 && xmax - xmin == 2 * xmax
|
|
* same true for y, hence: a == 0 && b == 0;
|
|
*
|
|
* 2) When working with small numbers, we can are loosing significant
|
|
* precision, hence we use clutter_qmulx() here, not the fast macro.
|
|
*/
|
|
ymax = clutter_qmulx (zNear, CFX_DIV (clutter_sinx (fovy_rad_half),
|
|
clutter_cosx (fovy_rad_half)));
|
|
xmax = clutter_qmulx (ymax, aspect);
|
|
|
|
x = CFX_DIV (zNear, xmax);
|
|
y = CFX_DIV (zNear, ymax);
|
|
c = CFX_DIV (-(zFar + zNear), ( zFar - zNear));
|
|
d = CFX_DIV (-(clutter_qmulx (2*zFar, zNear)), (zFar - zNear));
|
|
|
|
#define M(row,col) m[col*4+row]
|
|
M(0,0) = x;
|
|
M(1,1) = y;
|
|
M(2,2) = c;
|
|
M(2,3) = d;
|
|
M(3,2) = 1 + ~CFX_ONE;
|
|
|
|
GE( glMultMatrixx (m) );
|
|
#undef M
|
|
}
|
|
|
|
void
|
|
cogl_setup_viewport (guint w,
|
|
guint h,
|
|
ClutterFixed fovy,
|
|
ClutterFixed aspect,
|
|
ClutterFixed z_near,
|
|
ClutterFixed z_far)
|
|
{
|
|
gint width = (gint) w;
|
|
gint height = (gint) h;
|
|
ClutterFixed z_camera;
|
|
|
|
GE( glViewport (0, 0, width, height) );
|
|
GE( glMatrixMode (GL_PROJECTION) );
|
|
GE( glLoadIdentity () );
|
|
|
|
/* For Ortho projection.
|
|
* glOrthox (0, width << 16, 0, height << 16, -1 << 16, 1 << 16);
|
|
*/
|
|
|
|
cogl_perspective (fovy, aspect, z_near, z_far);
|
|
|
|
GE( glMatrixMode (GL_MODELVIEW) );
|
|
GE( glLoadIdentity () );
|
|
|
|
/*
|
|
* camera distance from screen, 0.5 * tan (FOV)
|
|
*
|
|
* See comments in ../gl/cogl.c
|
|
*/
|
|
#define DEFAULT_Z_CAMERA 0.869f
|
|
z_camera = CLUTTER_FLOAT_TO_FIXED (DEFAULT_Z_CAMERA);
|
|
|
|
if (fovy != CFX_60)
|
|
{
|
|
ClutterFixed fovy_rad = CFX_MUL (fovy, CFX_PI) / 180;
|
|
|
|
z_camera = CFX_DIV (clutter_sinx (fovy_rad),
|
|
clutter_cosx (fovy_rad)) >> 1;
|
|
}
|
|
|
|
|
|
GE( glTranslatex (-1 << 15, -1 << 15, -z_camera));
|
|
|
|
GE( glScalex ( CFX_ONE / width,
|
|
-CFX_ONE / height,
|
|
CFX_ONE / width));
|
|
|
|
GE( glTranslatex (0, -CFX_ONE * height, 0) );
|
|
}
|
|
|
|
ClutterFeatureFlags
|
|
cogl_get_features ()
|
|
{
|
|
/* Suck */
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
cogl_get_modelview_matrix (ClutterFixed m[16])
|
|
{
|
|
glGetFixedv(GL_MODELVIEW_MATRIX, &m[0]);
|
|
}
|
|
|
|
void
|
|
cogl_get_projection_matrix (ClutterFixed m[16])
|
|
{
|
|
glGetFixedv(GL_PROJECTION_MATRIX, &m[0]);
|
|
}
|
|
|
|
void
|
|
cogl_get_viewport (ClutterFixed v[4])
|
|
{
|
|
glGetFixedv(GL_VIEWPORT, &v[0]);
|
|
}
|
|
|
|
void
|
|
cogl_get_bitmasks (gint *red, gint *green, gint *blue, gint *alpha)
|
|
{
|
|
if (red)
|
|
GE( glGetIntegerv(GL_RED_BITS, red) );
|
|
if (green)
|
|
GE( glGetIntegerv(GL_GREEN_BITS, green) );
|
|
if (blue)
|
|
GE( glGetIntegerv(GL_BLUE_BITS, blue) );
|
|
if (alpha)
|
|
GE( glGetIntegerv(GL_ALPHA_BITS, alpha ) );
|
|
}
|