mutter/clutter/cogl/gles/cogl-gles2-wrapper.c
Robert Bragg ea643ca0f8 [multi-texturing] This adds a new cogl_multi_texture API for GL,GLES1 + GLES2
Multitexturing allows blending multiple layers of texture data when texturing
some geometry. A common use is for pre-baked light maps which can give nice
lighting effects relativly cheaply. Another is for dot-3 bump mapping, and
another is applying alpha channel masks.

The dot-3 bump mapping would be really nice one day, but currently cogl doesn't
support lighting so that's not dealt with in this patch.

notable limitations:
- It can only texture rectangles a.t.m - and like cogl_texture_rectangle there
is no support for rotated texturing.
- Sliced textures are not supported. I think I've figured out how to handle
layers with different slice sizes at least for rectangular geometry, but I'm
not sure how complex it becomes once rotations are possible and texturing
arbitrary cogl_polygons.
- Except for this new API, cogl still doesn't know about more than one texture
unit, and so has no way of caching any enables related to other units. So that
things don't break it's currently necessary to disable anything to do with
additional units as soon as we are done with them which isn't ideal.
- No clutter API yet.
2008-12-22 16:35:51 +00:00

1636 lines
43 KiB
C

/*
* Clutter COGL
*
* A basic GL/GLES Abstraction/Utility Layer
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2008 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 <clutter/clutter-fixed.h>
#include <string.h>
#include <math.h>
#include "cogl.h"
#include "cogl-gles2-wrapper.h"
#include "cogl-fixed-vertex-shader.h"
#include "cogl-fixed-fragment-shader.h"
#include "cogl-context.h"
#include "cogl-shader-private.h"
#include "cogl-program.h"
#include "cogl-internal.h"
#define _COGL_GET_GLES2_WRAPPER(wvar, retval) \
CoglGles2Wrapper *wvar; \
{ \
CoglContext *__ctxvar = _cogl_context_get_default (); \
if (__ctxvar == NULL) return retval; \
wvar = &__ctxvar->gles2; \
}
#define _COGL_GLES2_CHANGE_SETTING(w, var, val) \
do \
if ((w)->settings.var != (val)) \
{ \
(w)->settings.var = (val); \
(w)->settings_dirty = TRUE; \
} \
while (0)
#define _COGL_GLES2_CHANGE_UNIFORM(w, flag, var, val) \
do \
if ((w)->var != (val)) \
{ \
(w)->var = (val); \
(w)->dirty_uniforms |= COGL_GLES2_DIRTY_ ## flag; \
} \
while (0)
#define COGL_GLES2_WRAPPER_VERTEX_ATTRIB 0
#define COGL_GLES2_WRAPPER_COLOR_ATTRIB 1
#define COGL_GLES2_WRAPPER_NORMAL_ATTRIB 2
static GLuint
cogl_gles2_wrapper_create_shader (GLenum type, const char *source)
{
GLuint shader;
GLint source_len = strlen (source);
GLint status;
shader = glCreateShader (type);
glShaderSource (shader, 1, &source, &source_len);
glCompileShader (shader);
glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
if (!status)
{
char log[1024];
GLint len;
glGetShaderInfoLog (shader, sizeof (log) - 1, &len, log);
log[len] = '\0';
g_critical ("%s", log);
glDeleteShader (shader);
return 0;
}
return shader;
}
void
cogl_gles2_wrapper_init (CoglGles2Wrapper *wrapper)
{
GLfixed default_fog_color[4] = { 0, 0, 0, 0 };
memset (wrapper, 0, sizeof (CoglGles2Wrapper));
/* Initialize the stacks */
cogl_wrap_glMatrixMode (GL_PROJECTION);
cogl_wrap_glLoadIdentity ();
cogl_wrap_glMatrixMode (GL_MODELVIEW);
cogl_wrap_glLoadIdentity ();
wrapper->texture_units =
g_array_new (FALSE, FALSE, sizeof (CoglGles2WrapperTextureUnit *));
/* The gl*ActiveTexture wrappers will initialise the texture
* stack for the texture unit when it's first activated */
cogl_wrap_glActiveTexture (GL_TEXTURE0);
cogl_wrap_glClientActiveTexture (GL_TEXTURE0);
/* Initialize the fogging options */
cogl_wrap_glDisable (GL_FOG);
cogl_wrap_glFogx (GL_FOG_MODE, GL_LINEAR);
cogl_wrap_glFogx (GL_FOG_DENSITY, COGL_FIXED_1);
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);
}
static gboolean
cogl_gles2_settings_equal (const CoglGles2WrapperSettings *a,
const CoglGles2WrapperSettings *b,
gboolean vertex_tests,
gboolean fragment_tests)
{
if (fragment_tests)
{
int i;
for (i = 0; i < a->n_texture_units; i++)
{
if (a->texture_units[i].enabled != b->texture_units[i].enabled)
return FALSE;
if (a->texture_units[i].alpha_only != b->texture_units[i].alpha_only)
return FALSE;
}
if (a->alpha_test_enabled != b->alpha_test_enabled)
return FALSE;
if (a->alpha_test_enabled && a->alpha_test_func != b->alpha_test_func)
return FALSE;
}
if (a->fog_enabled != b->fog_enabled)
return FALSE;
if (vertex_tests && a->fog_enabled && a->fog_mode != b->fog_mode)
return FALSE;
return TRUE;
}
static CoglGles2WrapperShader *
cogl_gles2_get_vertex_shader (const CoglGles2WrapperSettings *settings)
{
GString *shader_source;
GLuint shader_obj;
CoglGles2WrapperShader *shader;
GSList *node;
int i;
_COGL_GET_GLES2_WRAPPER (w, NULL);
/* Check if we already have a vertex shader for these settings */
for (node = w->compiled_vertex_shaders; node; node = node->next)
if (cogl_gles2_settings_equal (settings,
&((CoglGles2WrapperShader *)
node->data)->settings,
TRUE, FALSE))
return (CoglGles2WrapperShader *) node->data;
/* Otherwise create a new shader */
shader_source = g_string_new (cogl_fixed_vertex_shader_per_vertex_attribs);
for (i = 0; i < settings->n_texture_units; i++)
{
if (!settings->texture_units[i].enabled)
continue;
g_string_append_printf (shader_source,
"attribute vec4 multi_tex_coord_attrib%d;\n",
i);
}
g_string_append (shader_source, cogl_fixed_vertex_shader_transform_matrices);
g_string_append_printf (shader_source,
"uniform mat4 texture_matrix[%d];\n",
settings->n_texture_units);
g_string_append (shader_source, cogl_fixed_vertex_shader_output_variables);
g_string_append_printf (shader_source,
"varying vec2 tex_coord[%d];",
settings->n_texture_units);
g_string_append (shader_source, cogl_fixed_vertex_shader_fogging_options);
g_string_append (shader_source, cogl_fixed_vertex_shader_main_start);
for (i = 0; i < settings->n_texture_units; i++)
{
if (!settings->texture_units[i].enabled)
continue;
g_string_append_printf (shader_source,
"transformed_tex_coord = "
"texture_matrix[%d] "
" * multi_tex_coord_attrib%d;\n",
i, i);
g_string_append_printf (shader_source,
"tex_coord[%d] = transformed_tex_coord.st "
" / transformed_tex_coord.q;\n",
i);
}
g_string_append (shader_source, cogl_fixed_vertex_shader_frag_color_start);
if (settings->fog_enabled)
{
g_string_append (shader_source, cogl_fixed_vertex_shader_fog_start);
switch (settings->fog_mode)
{
case GL_EXP:
g_string_append (shader_source, cogl_fixed_vertex_shader_fog_exp);
break;
case GL_EXP2:
g_string_append (shader_source, cogl_fixed_vertex_shader_fog_exp2);
break;
default:
g_string_append (shader_source, cogl_fixed_vertex_shader_fog_linear);
break;
}
g_string_append (shader_source, cogl_fixed_vertex_shader_fog_end);
}
g_string_append (shader_source, cogl_fixed_vertex_shader_end);
shader_obj = cogl_gles2_wrapper_create_shader (GL_VERTEX_SHADER,
shader_source->str);
g_string_free (shader_source, TRUE);
if (shader_obj == 0)
return NULL;
shader = g_slice_new (CoglGles2WrapperShader);
shader->shader = shader_obj;
shader->settings = *settings;
w->compiled_vertex_shaders = g_slist_prepend (w->compiled_vertex_shaders,
shader);
return shader;
}
static CoglGles2WrapperShader *
cogl_gles2_get_fragment_shader (const CoglGles2WrapperSettings *settings)
{
GString *shader_source;
GLuint shader_obj;
CoglGles2WrapperShader *shader;
GSList *node;
int i;
_COGL_GET_GLES2_WRAPPER (w, NULL);
/* Check if we already have a fragment shader for these settings */
for (node = w->compiled_fragment_shaders; node; node = node->next)
if (cogl_gles2_settings_equal (settings,
&((CoglGles2WrapperShader *)
node->data)->settings,
FALSE, TRUE))
return (CoglGles2WrapperShader *) node->data;
/* Otherwise create a new shader */
shader_source = g_string_new (cogl_fixed_fragment_shader_variables_start);
g_string_append (shader_source, cogl_fixed_fragment_shader_inputs);
g_string_append_printf (shader_source,
"varying vec2 tex_coord[%d];\n",
settings->n_texture_units);
g_string_append (shader_source, cogl_fixed_fragment_shader_texturing_options);
g_string_append_printf (shader_source,
"uniform sampler2D texture_unit[%d];\n",
settings->n_texture_units);
g_string_append (shader_source, cogl_fixed_fragment_shader_fogging_options);
g_string_append (shader_source, cogl_fixed_fragment_shader_main_declare);
g_string_append (shader_source, cogl_fixed_fragment_shader_main_start);
/* This pointless extra variable is needed to work around an
apparent bug in the PowerVR drivers. Without it the alpha
blending seems to stop working */
/* g_string_append (shader_source, "gl_FragColor = frag_color;\n");
*/
g_string_append (shader_source,
"vec4 frag_color_copy = frag_color;\n");
g_string_append (shader_source, "gl_FragColor = frag_color;\n");
for (i = 0; i < settings->n_texture_units; i++)
{
if (settings->texture_units[i].alpha_only)
{
/* If the texture only has an alpha channel (eg, with the textures
from the pango renderer) then the RGB components will be
black. We want to use the RGB from the current color in that
case */
g_string_append_printf (
shader_source,
"gl_FragColor.a *= "
"texture2D (texture_unit[%d], tex_coord[%d]).a;\n",
i, i);
}
else
{
g_string_append_printf (
shader_source,
"gl_FragColor *= "
"texture2D (texture_unit[%d], tex_coord[%d]);\n",
i, i);
}
}
/* FIXME */
g_string_append (shader_source, "gl_FragColor.r = 1.0;\n");
g_string_append (shader_source, "gl_FragColor.g = 1.0;\n");
if (i == 0)
g_string_append (shader_source, "gl_FragColor = frag_color;\n");
if (settings->fog_enabled)
g_string_append (shader_source, cogl_fixed_fragment_shader_fog);
if (settings->alpha_test_enabled)
switch (settings->alpha_test_func)
{
case GL_NEVER:
g_string_append (shader_source,
cogl_fixed_fragment_shader_alpha_never);
break;
case GL_LESS:
g_string_append (shader_source,
cogl_fixed_fragment_shader_alpha_less);
break;
case GL_EQUAL:
g_string_append (shader_source,
cogl_fixed_fragment_shader_alpha_equal);
break;
case GL_LEQUAL:
g_string_append (shader_source,
cogl_fixed_fragment_shader_alpha_lequal);
break;
case GL_GREATER:
g_string_append (shader_source,
cogl_fixed_fragment_shader_alpha_greater);
break;
case GL_NOTEQUAL:
g_string_append (shader_source,
cogl_fixed_fragment_shader_alpha_notequal);
break;
case GL_GEQUAL:
g_string_append (shader_source,
cogl_fixed_fragment_shader_alpha_gequal);
}
g_string_append (shader_source, cogl_fixed_fragment_shader_end);
shader_obj = cogl_gles2_wrapper_create_shader (GL_FRAGMENT_SHADER,
shader_source->str);
g_string_free (shader_source, TRUE);
if (shader_obj == 0)
return NULL;
shader = g_slice_new (CoglGles2WrapperShader);
shader->shader = shader_obj;
shader->settings = *settings;
w->compiled_fragment_shaders = g_slist_prepend (w->compiled_fragment_shaders,
shader);
return shader;
}
static void
cogl_gles2_wrapper_get_locations (GLuint program,
CoglGles2WrapperSettings *settings,
CoglGles2WrapperUniforms *uniforms,
CoglGles2WrapperAttributes *attribs)
{
int i;
uniforms->mvp_matrix_uniform
= glGetUniformLocation (program, "mvp_matrix");
uniforms->modelview_matrix_uniform
= glGetUniformLocation (program, "modelview_matrix");
uniforms->texture_matrix_uniforms =
g_array_new (FALSE, FALSE, sizeof (GLint));
uniforms->texture_sampler_uniforms =
g_array_new (FALSE, FALSE, sizeof (GLint));
attribs->multi_texture_coords =
g_array_new (FALSE, FALSE, sizeof (GLint));
for (i = 0; i < settings->n_texture_units; i++)
{
char *matrix_var_name = g_strdup_printf ("texture_matrix[%d]", i);
char *sampler_var_name = g_strdup_printf ("texture_unit[%d]", i);
char *tex_coord_var_name =
g_strdup_printf ("multi_tex_coord_attrib%d", i);
GLint location;
location = glGetUniformLocation (program, matrix_var_name);
g_array_append_val (uniforms->texture_matrix_uniforms, location);
location = glGetUniformLocation (program, sampler_var_name);
g_array_append_val (uniforms->texture_sampler_uniforms, location);
location = glGetAttribLocation (program, tex_coord_var_name);
g_array_append_val (attribs->multi_texture_coords, location);
g_free (tex_coord_var_name);
g_free (sampler_var_name);
g_free (matrix_var_name);
}
uniforms->fog_density_uniform
= glGetUniformLocation (program, "fog_density");
uniforms->fog_start_uniform
= glGetUniformLocation (program, "fog_start");
uniforms->fog_end_uniform
= glGetUniformLocation (program, "fog_end");
uniforms->fog_color_uniform
= glGetUniformLocation (program, "fog_color");
uniforms->alpha_test_ref_uniform
= glGetUniformLocation (program, "alpha_test_ref");
}
static void
cogl_gles2_wrapper_bind_attributes (GLuint program)
{
glBindAttribLocation (program, COGL_GLES2_WRAPPER_VERTEX_ATTRIB,
"vertex_attrib");
glBindAttribLocation (program, COGL_GLES2_WRAPPER_COLOR_ATTRIB,
"color_attrib");
glBindAttribLocation (program, COGL_GLES2_WRAPPER_NORMAL_ATTRIB,
"normal_attrib");
}
static CoglGles2WrapperProgram *
cogl_gles2_wrapper_get_program (const CoglGles2WrapperSettings *settings)
{
GSList *node;
CoglGles2WrapperProgram *program;
CoglGles2WrapperShader *vertex_shader, *fragment_shader;
GLint status;
gboolean custom_vertex_shader = FALSE, custom_fragment_shader = FALSE;
CoglProgram *user_program = NULL;
int i;
_COGL_GET_GLES2_WRAPPER (w, NULL);
/* Check if we've already got a program for these settings */
for (node = w->compiled_programs; node; node = node->next)
{
program = (CoglGles2WrapperProgram *) node->data;
if (cogl_gles2_settings_equal (settings, &program->settings, TRUE, TRUE)
&& program->settings.user_program == settings->user_program)
return (CoglGles2WrapperProgram *) node->data;
}
/* Otherwise create a new program */
/* Check whether the currently used custom program has vertex and
fragment shaders */
if (w->settings.user_program != COGL_INVALID_HANDLE)
{
user_program
= _cogl_program_pointer_from_handle (w->settings.user_program);
for (node = user_program->attached_shaders; node; node = node->next)
{
CoglShader *shader
= _cogl_shader_pointer_from_handle ((CoglHandle) node->data);
if (shader->type == CGL_VERTEX_SHADER)
custom_vertex_shader = TRUE;
else if (shader->type == CGL_FRAGMENT_SHADER)
custom_fragment_shader = TRUE;
}
}
/* Get or create the fixed functionality shaders for these settings
if there is no custom replacement */
if (!custom_vertex_shader)
{
vertex_shader = cogl_gles2_get_vertex_shader (settings);
if (vertex_shader == NULL)
return NULL;
}
if (!custom_fragment_shader)
{
fragment_shader = cogl_gles2_get_fragment_shader (settings);
if (fragment_shader == NULL)
return NULL;
}
program = g_slice_new (CoglGles2WrapperProgram);
program->program = glCreateProgram ();
if (!custom_vertex_shader)
glAttachShader (program->program, vertex_shader->shader);
if (!custom_fragment_shader)
glAttachShader (program->program, fragment_shader->shader);
if (user_program)
for (node = user_program->attached_shaders; node; node = node->next)
{
CoglShader *shader
= _cogl_shader_pointer_from_handle ((CoglHandle) node->data);
glAttachShader (program->program, shader->gl_handle);
}
cogl_gles2_wrapper_bind_attributes (program->program);
glLinkProgram (program->program);
glGetProgramiv (program->program, GL_LINK_STATUS, &status);
if (!status)
{
char log[1024];
GLint len;
glGetProgramInfoLog (program->program, sizeof (log) - 1, &len, log);
log[len] = '\0';
g_critical ("%s", log);
glDeleteProgram (program->program);
g_slice_free (CoglGles2WrapperProgram, program);
return NULL;
}
program->settings = *settings;
cogl_gles2_wrapper_get_locations (program->program,
&program->settings,
&program->uniforms,
&program->attributes);
/* We haven't tried to get a location for any of the custom uniforms
yet */
for (i = 0; i < COGL_GLES2_NUM_CUSTOM_UNIFORMS; i++)
program->custom_uniforms[i] = COGL_GLES2_UNBOUND_CUSTOM_UNIFORM;
w->compiled_programs = g_slist_append (w->compiled_programs, program);
return program;
}
void
cogl_gles2_wrapper_deinit (CoglGles2Wrapper *wrapper)
{
GSList *node, *next;
int i;
for (node = wrapper->compiled_programs; node; node = next)
{
next = node->next;
glDeleteProgram (((CoglGles2WrapperProgram *) node->data)->program);
g_slist_free1 (node);
}
wrapper->compiled_programs = NULL;
for (node = wrapper->compiled_vertex_shaders; node; node = next)
{
next = node->next;
glDeleteShader (((CoglGles2WrapperShader *) node->data)->shader);
g_slist_free1 (node);
}
wrapper->compiled_vertex_shaders = NULL;
for (node = wrapper->compiled_fragment_shaders; node; node = next)
{
next = node->next;
glDeleteShader (((CoglGles2WrapperShader *) node->data)->shader);
g_slist_free1 (node);
}
wrapper->compiled_fragment_shaders = NULL;
for (i = 0; i < COGL_GLES2_NUM_CUSTOM_UNIFORMS; i++)
if (wrapper->custom_uniforms[i].count > 1)
g_free (wrapper->custom_uniforms[i].v.array);
}
static void
cogl_gles2_wrapper_update_matrix (CoglGles2Wrapper *wrapper, GLenum matrix_num)
{
CoglGles2WrapperTextureUnit *texture_unit;
switch (matrix_num)
{
default:
case GL_MODELVIEW:
wrapper->dirty_uniforms |= COGL_GLES2_DIRTY_MVP_MATRIX
| COGL_GLES2_DIRTY_MODELVIEW_MATRIX;
break;
case GL_PROJECTION:
wrapper->dirty_uniforms |= COGL_GLES2_DIRTY_MVP_MATRIX;
break;
case GL_TEXTURE:
wrapper->dirty_uniforms |= COGL_GLES2_DIRTY_TEXTURE_MATRICES;
texture_unit = g_array_index (wrapper->texture_units,
CoglGles2WrapperTextureUnit *,
wrapper->active_texture_unit);
texture_unit->dirty_matrix = 1;
break;
}
}
void
cogl_wrap_glClearColorx (GLclampx r, GLclampx g, GLclampx b, GLclampx a)
{
glClearColor (COGL_FIXED_TO_FLOAT (r),
COGL_FIXED_TO_FLOAT (g),
COGL_FIXED_TO_FLOAT (b),
COGL_FIXED_TO_FLOAT (a));
}
void
cogl_wrap_glPushMatrix ()
{
const float *src;
float *dst;
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
/* Get a pointer to the old and new matrix position and increment
the stack pointer */
switch (w->matrix_mode)
{
default:
case GL_MODELVIEW:
src = w->modelview_stack + w->modelview_stack_pos * 16;
w->modelview_stack_pos = (w->modelview_stack_pos + 1)
& (COGL_GLES2_MODELVIEW_STACK_SIZE - 1);
dst = w->modelview_stack + w->modelview_stack_pos * 16;
break;
case GL_PROJECTION:
src = w->projection_stack + w->projection_stack_pos * 16;
w->projection_stack_pos = (w->projection_stack_pos + 1)
& (COGL_GLES2_PROJECTION_STACK_SIZE - 1);
dst = w->projection_stack + w->projection_stack_pos * 16;
break;
case GL_TEXTURE:
{
CoglGles2WrapperTextureUnit *texture_unit;
texture_unit = g_array_index (w->texture_units,
CoglGles2WrapperTextureUnit *,
w->active_texture_unit);
src = texture_unit->texture_stack
+ texture_unit->texture_stack_pos * 16;
texture_unit->texture_stack_pos = (texture_unit->texture_stack_pos + 1)
& (COGL_GLES2_TEXTURE_STACK_SIZE - 1);
dst = texture_unit->texture_stack
+ texture_unit->texture_stack_pos * 16;
break;
}
}
/* Copy the old matrix to the new position */
memcpy (dst, src, sizeof (float) * 16);
}
void
cogl_wrap_glPopMatrix ()
{
CoglGles2WrapperTextureUnit *texture_unit;
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
/* Decrement the stack pointer */
switch (w->matrix_mode)
{
default:
case GL_MODELVIEW:
w->modelview_stack_pos = (w->modelview_stack_pos - 1)
& (COGL_GLES2_MODELVIEW_STACK_SIZE - 1);
break;
case GL_PROJECTION:
w->projection_stack_pos = (w->projection_stack_pos - 1)
& (COGL_GLES2_PROJECTION_STACK_SIZE - 1);
break;
case GL_TEXTURE:
texture_unit = g_array_index (w->texture_units,
CoglGles2WrapperTextureUnit *,
w->active_texture_unit);
texture_unit->texture_stack_pos = (texture_unit->texture_stack_pos - 1)
& (COGL_GLES2_TEXTURE_STACK_SIZE - 1);
break;
}
/* Update the matrix in the program object */
cogl_gles2_wrapper_update_matrix (w, w->matrix_mode);
}
void
cogl_wrap_glMatrixMode (GLenum mode)
{
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
w->matrix_mode = mode;
}
static float *
cogl_gles2_get_matrix_stack_top (CoglGles2Wrapper *wrapper)
{
CoglGles2WrapperTextureUnit *texture_unit;
switch (wrapper->matrix_mode)
{
default:
case GL_MODELVIEW:
return wrapper->modelview_stack + wrapper->modelview_stack_pos * 16;
case GL_PROJECTION:
return wrapper->projection_stack + wrapper->projection_stack_pos * 16;
case GL_TEXTURE:
texture_unit = g_array_index (wrapper->texture_units,
CoglGles2WrapperTextureUnit *,
wrapper->active_texture_unit);
return texture_unit->texture_stack
+ texture_unit->texture_stack_pos * 16;
}
}
void
cogl_wrap_glLoadIdentity ()
{
float *matrix;
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
matrix = cogl_gles2_get_matrix_stack_top (w);
memset (matrix, 0, sizeof (float) * 16);
matrix[0] = 1.0f;
matrix[5] = 1.0f;
matrix[10] = 1.0f;
matrix[15] = 1.0f;
cogl_gles2_wrapper_update_matrix (w, w->matrix_mode);
}
static void
cogl_gles2_wrapper_mult_matrix (float *dst, const float *a, const float *b)
{
int i, j, k;
for (i = 0; i < 4; i++)
for (j = 0; j < 4; j++)
{
float sum = 0.0f;
for (k = 0; k < 4; k++)
sum += a[k * 4 + j] * b[i * 4 + k];
dst[i * 4 + j] = sum;
}
}
static void
cogl_wrap_glMultMatrix (const float *m)
{
float new_matrix[16];
float *old_matrix;
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
old_matrix = cogl_gles2_get_matrix_stack_top (w);
cogl_gles2_wrapper_mult_matrix (new_matrix, old_matrix, m);
memcpy (old_matrix, new_matrix, sizeof (float) * 16);
cogl_gles2_wrapper_update_matrix (w, w->matrix_mode);
}
void
cogl_wrap_glMultMatrixx (const GLfixed *m)
{
float new_matrix[16];
int i;
for (i = 0; i < 16; i++)
new_matrix[i] = COGL_FIXED_TO_FLOAT (m[i]);
cogl_wrap_glMultMatrix (new_matrix);
}
void
cogl_wrap_glFrustumx (GLfixed left, GLfixed right,
GLfixed bottom, GLfixed top,
GLfixed z_near, GLfixed z_far)
{
float matrix[16];
float two_near = COGL_FIXED_TO_FLOAT (2 * z_near);
memset (matrix, 0, sizeof (matrix));
matrix[0] = two_near / COGL_FIXED_TO_FLOAT (right - left);
matrix[5] = two_near / COGL_FIXED_TO_FLOAT (top - bottom);
matrix[8] = COGL_FIXED_TO_FLOAT (right + left)
/ COGL_FIXED_TO_FLOAT (right - left);
matrix[9] = COGL_FIXED_TO_FLOAT (top + bottom)
/ COGL_FIXED_TO_FLOAT (top - bottom);
matrix[10] = -COGL_FIXED_TO_FLOAT (z_far + z_near)
/ COGL_FIXED_TO_FLOAT (z_far - z_near);
matrix[11] = -1.0f;
matrix[14] = -two_near * COGL_FIXED_TO_FLOAT (z_far)
/ COGL_FIXED_TO_FLOAT (z_far - z_near);
cogl_wrap_glMultMatrix (matrix);
}
void
cogl_wrap_glScalex (GLfixed x, GLfixed y, GLfixed z)
{
float matrix[16];
memset (matrix, 0, sizeof (matrix));
matrix[0] = COGL_FIXED_TO_FLOAT (x);
matrix[5] = COGL_FIXED_TO_FLOAT (y);
matrix[10] = COGL_FIXED_TO_FLOAT (z);
matrix[15] = 1.0f;
cogl_wrap_glMultMatrix (matrix);
}
void
cogl_wrap_glTranslatex (GLfixed x, GLfixed y, GLfixed z)
{
float matrix[16];
memset (matrix, 0, sizeof (matrix));
matrix[0] = 1.0f;
matrix[5] = 1.0f;
matrix[10] = 1.0f;
matrix[12] = COGL_FIXED_TO_FLOAT (x);
matrix[13] = COGL_FIXED_TO_FLOAT (y);
matrix[14] = COGL_FIXED_TO_FLOAT (z);
matrix[15] = 1.0f;
cogl_wrap_glMultMatrix (matrix);
}
void
cogl_wrap_glRotatex (GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
{
float matrix[16];
float xf = COGL_FIXED_TO_FLOAT (x);
float yf = COGL_FIXED_TO_FLOAT (y);
float zf = COGL_FIXED_TO_FLOAT (z);
float anglef = COGL_FIXED_TO_FLOAT (angle) * G_PI / 180.0f;
float c = cosf (anglef);
float s = sinf (anglef);
matrix[0] = xf * xf * (1.0f - c) + c;
matrix[1] = yf * xf * (1.0f - c) + zf * s;
matrix[2] = xf * zf * (1.0f - c) - yf * s;
matrix[3] = 0.0f;
matrix[4] = xf * yf * (1.0f - c) - zf * s;
matrix[5] = yf * yf * (1.0f - c) + c;
matrix[6] = yf * zf * (1.0f - c) + xf * s;
matrix[7] = 0.0f;
matrix[8] = xf * zf * (1.0f - c) + yf * s;
matrix[9] = yf * zf * (1.0f - c) - xf * s;
matrix[10] = zf * zf * (1.0f - c) + c;
matrix[11] = 0.0f;
matrix[12] = 0.0f;
matrix[13] = 0.0f;
matrix[14] = 0.0f;
matrix[15] = 1.0f;
cogl_wrap_glMultMatrix (matrix);
}
void
cogl_wrap_glOrthox (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top,
GLfixed near, GLfixed far)
{
float matrix[16];
float xrange = COGL_FIXED_TO_FLOAT (right - left);
float yrange = COGL_FIXED_TO_FLOAT (top - bottom);
float zrange = COGL_FIXED_TO_FLOAT (far - near);
memset (matrix, 0, sizeof (matrix));
matrix[0] = 2.0f / xrange;
matrix[5] = 2.0f / yrange;
matrix[10] = 2.0f / zrange;
matrix[12] = COGL_FIXED_TO_FLOAT (right + left) / xrange;
matrix[13] = COGL_FIXED_TO_FLOAT (top + bottom) / yrange;
matrix[14] = COGL_FIXED_TO_FLOAT (far + near) / zrange;
matrix[15] = 1.0f;
cogl_wrap_glMultMatrix (matrix);
}
void
cogl_wrap_glVertexPointer (GLint size, GLenum type, GLsizei stride,
const GLvoid *pointer)
{
glVertexAttribPointer (COGL_GLES2_WRAPPER_VERTEX_ATTRIB, size, type,
GL_FALSE, stride, pointer);
}
void
cogl_wrap_glTexCoordPointer (GLint size, GLenum type, GLsizei stride,
const GLvoid *pointer)
{
int active_unit;
CoglGles2WrapperTextureUnit *texture_unit;
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
active_unit = w->active_client_texture_unit;
texture_unit = g_array_index (w->texture_units,
CoglGles2WrapperTextureUnit *,
active_unit);
texture_unit->texture_coords_size = size;
texture_unit->texture_coords_type = type;
texture_unit->texture_coords_stride = stride;
texture_unit->texture_coords_pointer = pointer;
w->dirty_attribute_pointers
|= COGL_GLES2_DIRTY_TEX_COORD_VERTEX_ATTRIB;
}
void
cogl_wrap_glColorPointer (GLint size, GLenum type, GLsizei stride,
const GLvoid *pointer)
{
glVertexAttribPointer (COGL_GLES2_WRAPPER_COLOR_ATTRIB, size, type,
GL_TRUE, stride, pointer);
}
void
cogl_wrap_glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer)
{
glVertexAttribPointer (COGL_GLES2_WRAPPER_NORMAL_ATTRIB, 1, type,
GL_FALSE, stride, pointer);
}
static void
cogl_gles2_do_set_uniform (GLint location, CoglBoxedValue *value)
{
switch (value->type)
{
case COGL_BOXED_NONE:
break;
case COGL_BOXED_INT:
{
gint *ptr;
if (value->count == 1)
ptr = value->v.int_value;
else
ptr = value->v.int_array;
switch (value->size)
{
case 1: glUniform1iv (location, value->count, ptr); break;
case 2: glUniform2iv (location, value->count, ptr); break;
case 3: glUniform3iv (location, value->count, ptr); break;
case 4: glUniform4iv (location, value->count, ptr); break;
}
}
break;
case COGL_BOXED_FLOAT:
{
gfloat *ptr;
if (value->count == 1)
ptr = value->v.float_value;
else
ptr = value->v.float_array;
switch (value->size)
{
case 1: glUniform1fv (location, value->count, ptr); break;
case 2: glUniform2fv (location, value->count, ptr); break;
case 3: glUniform3fv (location, value->count, ptr); break;
case 4: glUniform4fv (location, value->count, ptr); break;
}
}
break;
case COGL_BOXED_MATRIX:
{
gfloat *ptr;
if (value->count == 1)
ptr = value->v.matrix;
else
ptr = value->v.float_array;
switch (value->size)
{
case 2:
glUniformMatrix2fv (location, value->count, value->transpose, ptr);
break;
case 3:
glUniformMatrix3fv (location, value->count, value->transpose, ptr);
break;
case 4:
glUniformMatrix4fv (location, value->count, value->transpose, ptr);
break;
}
}
break;
}
}
void
cogl_wrap_glDrawArrays (GLenum mode, GLint first, GLsizei count)
{
CoglGles2WrapperProgram *program;
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
/* Check if we need to switch programs */
if (w->settings_dirty)
{
/* Find or create a program for the current settings */
program = cogl_gles2_wrapper_get_program (&w->settings);
if (program == NULL)
/* Can't compile a shader so there is nothing we can do */
return;
/* Start using it if we aren't already */
if (w->current_program != program)
{
glUseProgram (program->program);
w->current_program = program;
/* All of the uniforms are probably now out of date */
w->dirty_uniforms = COGL_GLES2_DIRTY_ALL;
w->dirty_custom_uniforms = (1 << COGL_GLES2_NUM_CUSTOM_UNIFORMS) - 1;
}
w->settings_dirty = FALSE;
}
else
program = w->current_program;
/* Make sure all of the uniforms are up to date */
if (w->dirty_uniforms)
{
if ((w->dirty_uniforms & (COGL_GLES2_DIRTY_MVP_MATRIX
| COGL_GLES2_DIRTY_MODELVIEW_MATRIX)))
{
float mvp_matrix[16];
const float *modelview_matrix = w->modelview_stack
+ w->modelview_stack_pos * 16;
cogl_gles2_wrapper_mult_matrix (mvp_matrix,
w->projection_stack
+ w->projection_stack_pos * 16,
modelview_matrix);
if (program->uniforms.mvp_matrix_uniform != -1)
glUniformMatrix4fv (program->uniforms.mvp_matrix_uniform, 1,
GL_FALSE, mvp_matrix);
if (program->uniforms.modelview_matrix_uniform != -1)
glUniformMatrix4fv (program->uniforms.modelview_matrix_uniform, 1,
GL_FALSE, modelview_matrix);
}
if ((w->dirty_uniforms & COGL_GLES2_DIRTY_TEXTURE_MATRICES))
{
int i;
/* TODO - we should probably have a per unit dirty flag too */
for (i = 0; i < program->uniforms.texture_matrix_uniforms->len; i++)
{
CoglGles2WrapperTextureUnit *texture_unit;
GLint uniform =
g_array_index (program->uniforms.texture_matrix_uniforms,
GLint, i);
texture_unit = g_array_index (w->texture_units,
CoglGles2WrapperTextureUnit *,
i);
if (uniform != -1)
glUniformMatrix4fv (uniform, 1, GL_FALSE,
texture_unit->texture_stack
+ texture_unit->texture_stack_pos * 16);
}
}
if ((w->dirty_uniforms & COGL_GLES2_DIRTY_FOG_DENSITY)
&& program->uniforms.fog_density_uniform != -1)
glUniform1f (program->uniforms.fog_density_uniform, w->fog_density);
if ((w->dirty_uniforms & COGL_GLES2_DIRTY_FOG_START)
&& program->uniforms.fog_start_uniform != -1)
glUniform1f (program->uniforms.fog_start_uniform, w->fog_start);
if ((w->dirty_uniforms & COGL_GLES2_DIRTY_FOG_END)
&& program->uniforms.fog_end_uniform != -1)
glUniform1f (program->uniforms.fog_end_uniform, w->fog_end);
if ((w->dirty_uniforms & COGL_GLES2_DIRTY_ALPHA_TEST_REF)
&& program->uniforms.alpha_test_ref_uniform != -1)
glUniform1f (program->uniforms.alpha_test_ref_uniform,
w->alpha_test_ref);
if ((w->dirty_uniforms & COGL_GLES2_DIRTY_TEXTURE_UNITS))
{
int i;
/* TODO - we should probably have a per unit dirty flag too */
for (i = 0; i < program->uniforms.texture_sampler_uniforms->len; i++)
{
GLint uniform =
g_array_index (program->uniforms.texture_sampler_uniforms,
GLint, i);
if (uniform != -1)
glUniform1i (uniform, i);
}
}
w->dirty_uniforms = 0;
}
if (w->dirty_custom_uniforms)
{
int i;
if (w->settings.user_program != COGL_INVALID_HANDLE)
{
CoglProgram *user_program
= _cogl_program_pointer_from_handle (w->settings.user_program);
const char *uniform_name;
for (i = 0; i < COGL_GLES2_NUM_CUSTOM_UNIFORMS; i++)
if ((w->dirty_custom_uniforms & (1 << i))
&& (uniform_name = user_program->custom_uniform_names[i]))
{
if (program->custom_uniforms[i]
== COGL_GLES2_UNBOUND_CUSTOM_UNIFORM)
program->custom_uniforms[i]
= glGetUniformLocation (program->program, uniform_name);
if (program->custom_uniforms[i] >= 0)
cogl_gles2_do_set_uniform (program->custom_uniforms[i],
&w->custom_uniforms[i]);
}
}
w->dirty_custom_uniforms = 0;
}
if (w->dirty_attribute_pointers
& COGL_GLES2_DIRTY_TEX_COORD_VERTEX_ATTRIB)
{
int i;
/* TODO - coverage test */
for (i = 0; i < w->settings.n_texture_units; i++)
{
GLint tex_coord_var_index;
CoglGles2WrapperTextureUnit *texture_unit;
if (!w->settings.texture_units[i].enabled)
continue;
texture_unit = g_array_index (w->texture_units,
CoglGles2WrapperTextureUnit *,
w->active_texture_unit);
if (!texture_unit->texture_coords_enabled)
continue;
/* TODO - we should probably have a per unit dirty flag too */
/* TODO - coverage test */
tex_coord_var_index =
g_array_index (program->attributes.multi_texture_coords,
GLint, i);
glVertexAttribPointer (tex_coord_var_index,
texture_unit->texture_coords_size,
texture_unit->texture_coords_type,
GL_FALSE,
texture_unit->texture_coords_stride,
texture_unit->texture_coords_pointer);
}
}
if (w->dirty_vertex_attrib_enables)
{
int i;
/* TODO - coverage test */
/* TODO - we should probably have a per unit dirty flag too */
for (i = 0; i < w->texture_units->len; i++)
{
CoglGles2WrapperTextureUnit *texture_unit =
g_array_index (w->texture_units,
CoglGles2WrapperTextureUnit *,
w->active_texture_unit);
if (texture_unit->texture_coords_enabled)
glEnableVertexAttribArray (
g_array_index (program->attributes.multi_texture_coords,
GLint, i));
else
glDisableVertexAttribArray (
g_array_index (program->attributes.multi_texture_coords,
GLint, i));
w->dirty_vertex_attrib_enables = 0;
}
}
glDrawArrays (mode, first, count);
}
void
cogl_gles2_wrapper_bind_texture (GLenum target, GLuint texture,
GLenum internal_format)
{
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
glBindTexture (target, texture);
/* We need to keep track of whether the texture is alpha-only
because the emulation of GL_MODULATE needs to work differently in
that case */
_COGL_GLES2_CHANGE_SETTING (
w, texture_units[w->active_texture_unit].alpha_only,
internal_format == GL_ALPHA);
}
void
cogl_wrap_glTexEnvx (GLenum target, GLenum pname, GLfixed param)
{
/* This function is only used to set the texture mode once to
GL_MODULATE. The shader is hard-coded to modulate the texture so
nothing needs to be done here. */
}
static void
realize_texture_units (CoglGles2Wrapper *w, int texture_unit_index)
{
/* We save the active texture unit since we may need to temporarily
* change this to initialise each new texture unit and we want to
* restore the active unit afterwards */
int initial_active_unit = w->active_texture_unit;
if (texture_unit_index >= w->settings.n_texture_units)
{
int n_new_texture_units =
texture_unit_index + 1 - w->settings.n_texture_units;
GLint prev_mode;
int i;
w->settings.texture_units =
g_realloc (w->settings.texture_units,
texture_unit_index + 1
* sizeof (CoglGles2WrapperTextureUnitSettings));
/* We will need to set the matrix mode to GL_TEXTURE to
* initialise any new texture units, so we save the current
* mode for restoring afterwards */
GE( cogl_wrap_glGetIntegerv (CGL_MATRIX_MODE, &prev_mode));
for (i = 0; i < n_new_texture_units; i++)
{
CoglGles2WrapperTextureUnit *new_unit;
CoglGles2WrapperTextureUnitSettings *new_unit_settings;
new_unit = g_new0 (CoglGles2WrapperTextureUnit, 1);
g_array_append_val (w->texture_units, new_unit);
w->active_texture_unit = i;
GE( cogl_wrap_glMatrixMode (GL_TEXTURE));
GE( cogl_wrap_glLoadIdentity ());
new_unit_settings =
&w->settings.texture_units[w->settings.n_texture_units + i];
new_unit_settings->enabled = FALSE;
new_unit_settings->alpha_only = FALSE;
}
GE( cogl_wrap_glMatrixMode ((GLenum)prev_mode));
w->settings.n_texture_units = w->texture_units->len;
}
w->active_texture_unit = initial_active_unit;
}
void
cogl_wrap_glClientActiveTexture (GLenum texture)
{
int texture_unit_index = texture - GL_TEXTURE0;
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
w->active_client_texture_unit = texture_unit_index;
realize_texture_units (w, texture_unit_index);
}
void
cogl_wrap_glActiveTexture (GLenum texture)
{
int texture_unit_index = texture - GL_TEXTURE0;
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
w->active_texture_unit = texture_unit_index;
realize_texture_units (w, texture_unit_index);
}
void
cogl_wrap_glEnable (GLenum cap)
{
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
switch (cap)
{
case GL_TEXTURE_2D:
_COGL_GLES2_CHANGE_SETTING (
w, texture_units[w->active_texture_unit].enabled, TRUE);
break;
case GL_FOG:
_COGL_GLES2_CHANGE_SETTING (w, fog_enabled, TRUE);
break;
case GL_ALPHA_TEST:
_COGL_GLES2_CHANGE_SETTING (w, alpha_test_enabled, TRUE);
break;
default:
glEnable (cap);
}
}
void
cogl_wrap_glDisable (GLenum cap)
{
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
switch (cap)
{
case GL_TEXTURE_2D:
_COGL_GLES2_CHANGE_SETTING (
w, texture_units[w->active_texture_unit].enabled, FALSE);
break;
case GL_FOG:
_COGL_GLES2_CHANGE_SETTING (w, fog_enabled, FALSE);
break;
case GL_ALPHA_TEST:
_COGL_GLES2_CHANGE_SETTING (w, alpha_test_enabled, FALSE);
break;
default:
glDisable (cap);
}
}
void
cogl_wrap_glEnableClientState (GLenum array)
{
CoglGles2WrapperTextureUnit *texture_unit;
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
switch (array)
{
case GL_VERTEX_ARRAY:
glEnableVertexAttribArray (COGL_GLES2_WRAPPER_VERTEX_ATTRIB);
break;
case GL_TEXTURE_COORD_ARRAY:
/* TODO - review if this should be in w->settings? */
texture_unit = g_array_index (w->texture_units,
CoglGles2WrapperTextureUnit *,
w->active_texture_unit);
if (texture_unit->texture_coords_enabled != 1)
{
texture_unit->texture_coords_enabled = 1;
w->dirty_vertex_attrib_enables
|= COGL_GLES2_DIRTY_TEX_COORD_ATTRIB_ENABLES;
}
break;
case GL_COLOR_ARRAY:
glEnableVertexAttribArray (COGL_GLES2_WRAPPER_COLOR_ATTRIB);
break;
case GL_NORMAL_ARRAY:
glEnableVertexAttribArray (COGL_GLES2_WRAPPER_NORMAL_ATTRIB);
break;
}
}
void
cogl_wrap_glDisableClientState (GLenum array)
{
CoglGles2WrapperTextureUnit *texture_unit;
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
switch (array)
{
case GL_VERTEX_ARRAY:
glDisableVertexAttribArray (COGL_GLES2_WRAPPER_VERTEX_ATTRIB);
break;
case GL_TEXTURE_COORD_ARRAY:
texture_unit = g_array_index (w->texture_units,
CoglGles2WrapperTextureUnit *,
w->active_texture_unit);
/* TODO - review if this should be in w->settings? */
if (texture_unit->texture_coords_enabled != 0)
{
texture_unit->texture_coords_enabled = 0;
w->dirty_vertex_attrib_enables
|= COGL_GLES2_DIRTY_TEX_COORD_ATTRIB_ENABLES;
}
break;
case GL_COLOR_ARRAY:
glDisableVertexAttribArray (COGL_GLES2_WRAPPER_COLOR_ATTRIB);
break;
case GL_NORMAL_ARRAY:
glDisableVertexAttribArray (COGL_GLES2_WRAPPER_NORMAL_ATTRIB);
break;
}
}
void
cogl_wrap_glAlphaFunc (GLenum func, GLclampf ref)
{
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
if (ref < 0.0f)
ref = 0.0f;
else if (ref > 1.0f)
ref = 1.0f;
_COGL_GLES2_CHANGE_SETTING (w, alpha_test_func, func);
_COGL_GLES2_CHANGE_UNIFORM (w, ALPHA_TEST_REF, alpha_test_ref, ref);
}
void
cogl_wrap_glColor4x (GLclampx r, GLclampx g, GLclampx b, GLclampx a)
{
glVertexAttrib4f (COGL_GLES2_WRAPPER_COLOR_ATTRIB,
COGL_FIXED_TO_FLOAT (r),
COGL_FIXED_TO_FLOAT (g),
COGL_FIXED_TO_FLOAT (b),
COGL_FIXED_TO_FLOAT (a));
}
void
cogl_wrap_glClipPlanex (GLenum plane, GLfixed *equation)
{
/* FIXME */
}
static void
cogl_gles2_float_array_to_fixed (int size,
const GLfloat *floats,
GLfixed *fixeds)
{
while (size-- > 0)
*(fixeds++) = COGL_FIXED_FROM_FLOAT (*(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;
case CGL_MATRIX_MODE:
*params = w->matrix_mode;
break;
default:
glGetIntegerv (pname, params);
break;
}
}
void
cogl_wrap_glGetFixedv (GLenum pname, GLfixed *params)
{
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
switch (pname)
{
case GL_MODELVIEW_MATRIX:
cogl_gles2_float_array_to_fixed (16, w->modelview_stack
+ w->modelview_stack_pos * 16,
params);
break;
case GL_PROJECTION_MATRIX:
cogl_gles2_float_array_to_fixed (16, w->projection_stack
+ w->projection_stack_pos * 16,
params);
break;
case GL_VIEWPORT:
{
GLfloat v[4];
glGetFloatv (GL_VIEWPORT, v);
cogl_gles2_float_array_to_fixed (4, v, params);
}
break;
}
}
void
cogl_wrap_glFogx (GLenum pname, GLfixed param)
{
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
switch (pname)
{
case GL_FOG_MODE:
_COGL_GLES2_CHANGE_SETTING (w, fog_mode, param);
break;
case GL_FOG_DENSITY:
_COGL_GLES2_CHANGE_UNIFORM (w, FOG_DENSITY, fog_density,
COGL_FIXED_TO_FLOAT (param));
break;
case GL_FOG_START:
_COGL_GLES2_CHANGE_UNIFORM (w, FOG_START, fog_start,
COGL_FIXED_TO_FLOAT (param));
break;
case GL_FOG_END:
_COGL_GLES2_CHANGE_UNIFORM (w, FOG_END, fog_end,
COGL_FIXED_TO_FLOAT (param));
break;
}
}
void
cogl_wrap_glFogxv (GLenum pname, const GLfixed *params)
{
int i;
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
if (pname == GL_FOG_COLOR)
{
for (i = 0; i < 4; i++)
w->fog_color[i] = COGL_FIXED_TO_FLOAT (params[i]);
w->dirty_uniforms |= COGL_GLES2_DIRTY_FOG_COLOR;
}
}
void
cogl_wrap_glTexParameteri (GLenum target, GLenum pname, GLfloat param)
{
if (pname != GL_GENERATE_MIPMAP)
glTexParameteri (target, pname, param);
}
void
_cogl_gles2_clear_cache_for_program (CoglHandle user_program)
{
GSList *node, *next, *last = NULL;
CoglGles2WrapperProgram *program;
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
/* Remove any cached programs that link against this custom program */
for (node = w->compiled_programs; node; node = next)
{
next = node->next;
program = (CoglGles2WrapperProgram *) node->data;
if (program->settings.user_program == user_program)
{
glDeleteProgram (program->program);
if (last)
last->next = next;
else
w->compiled_programs = next;
g_slist_free1 (node);
}
else
last = node;
}
}