2009-02-24 18:51:25 +00:00
|
|
|
/*
|
2009-04-27 14:48:12 +00:00
|
|
|
* Cogl
|
2009-02-24 18:51:25 +00:00
|
|
|
*
|
2009-04-27 14:48:12 +00:00
|
|
|
* An object oriented GL/GLES Abstraction/Utility Layer
|
2009-02-24 18:51:25 +00:00
|
|
|
*
|
2010-12-10 11:34:02 +00:00
|
|
|
* Copyright (C) 2009,2010 Intel Corporation.
|
2009-02-24 18:51:25 +00:00
|
|
|
*
|
|
|
|
* 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
|
2010-03-01 12:56:10 +00:00
|
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*
|
2009-04-27 14:48:12 +00:00
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Havoc Pennington <hp@pobox.com> for litl
|
2009-10-22 15:13:01 +00:00
|
|
|
* Robert Bragg <robert@linux.intel.com>
|
2009-02-24 18:51:25 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2010-11-04 22:25:52 +00:00
|
|
|
#include "cogl-context-private.h"
|
2009-02-24 18:51:25 +00:00
|
|
|
#include "cogl-internal.h"
|
|
|
|
#include "cogl-matrix-stack.h"
|
2009-11-26 19:06:35 +00:00
|
|
|
#include "cogl-framebuffer-private.h"
|
2010-12-10 16:06:16 +00:00
|
|
|
#include "cogl-object-private.h"
|
2012-02-18 01:19:17 +00:00
|
|
|
#include "cogl-offscreen.h"
|
2009-02-24 18:51:25 +00:00
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
CoglMatrix matrix;
|
2009-10-06 11:36:32 +00:00
|
|
|
gboolean is_identity;
|
2009-02-24 18:51:25 +00:00
|
|
|
/* count of pushes with no changes; when a change is
|
|
|
|
* requested, we create a new state and decrement this
|
|
|
|
*/
|
|
|
|
int push_count;
|
|
|
|
} CoglMatrixState;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* CoglMatrixStack:
|
|
|
|
*
|
|
|
|
* Stores a cogl-side matrix stack, which we use as a cache
|
|
|
|
* so we can get the matrix efficiently when using indirect
|
|
|
|
* rendering.
|
|
|
|
*/
|
|
|
|
struct _CoglMatrixStack
|
|
|
|
{
|
2010-12-10 16:06:16 +00:00
|
|
|
CoglObject _parent;
|
|
|
|
|
2010-11-01 22:07:11 +00:00
|
|
|
GArray *stack;
|
2009-02-24 18:51:25 +00:00
|
|
|
|
2010-12-10 11:13:09 +00:00
|
|
|
unsigned int age;
|
2009-02-24 18:51:25 +00:00
|
|
|
};
|
|
|
|
|
2010-12-10 16:06:16 +00:00
|
|
|
static void _cogl_matrix_stack_free (CoglMatrixStack *stack);
|
|
|
|
|
|
|
|
COGL_OBJECT_INTERNAL_DEFINE (MatrixStack, matrix_stack);
|
|
|
|
|
2009-10-06 09:52:07 +00:00
|
|
|
/* XXX: this doesn't initialize the matrix! */
|
2010-11-01 22:07:11 +00:00
|
|
|
static void
|
|
|
|
_cogl_matrix_state_init (CoglMatrixState *state)
|
2009-02-24 18:51:25 +00:00
|
|
|
{
|
2009-10-06 09:52:07 +00:00
|
|
|
state->push_count = 0;
|
2009-10-06 11:36:32 +00:00
|
|
|
state->is_identity = FALSE;
|
2009-02-24 18:51:25 +00:00
|
|
|
}
|
|
|
|
|
2010-11-01 22:07:11 +00:00
|
|
|
static CoglMatrixState *
|
2009-02-24 18:51:25 +00:00
|
|
|
_cogl_matrix_stack_top (CoglMatrixStack *stack)
|
|
|
|
{
|
2010-11-01 22:07:11 +00:00
|
|
|
return &g_array_index (stack->stack, CoglMatrixState, stack->stack->len - 1);
|
2009-02-24 18:51:25 +00:00
|
|
|
}
|
|
|
|
|
2009-10-06 11:36:32 +00:00
|
|
|
/* XXX:
|
|
|
|
* Operations like scale, translate, rotate etc need to have an
|
|
|
|
* initialized state->matrix to work with, so they will pass
|
|
|
|
* initialize = TRUE.
|
|
|
|
*
|
|
|
|
* _cogl_matrix_stack_load_identity and _cogl_matrix_stack_set on the
|
|
|
|
* other hand don't so they will pass initialize = FALSE
|
|
|
|
*
|
|
|
|
* NB: Identity matrices are represented by setting
|
|
|
|
* state->is_identity=TRUE in which case state->matrix will be
|
|
|
|
* uninitialized.
|
|
|
|
*/
|
2009-10-06 09:52:07 +00:00
|
|
|
static CoglMatrixState *
|
|
|
|
_cogl_matrix_stack_top_mutable (CoglMatrixStack *stack,
|
|
|
|
gboolean initialize)
|
2009-02-24 18:51:25 +00:00
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
CoglMatrixState *new_top;
|
|
|
|
|
|
|
|
state = _cogl_matrix_stack_top (stack);
|
|
|
|
|
|
|
|
if (state->push_count == 0)
|
2009-10-06 11:36:32 +00:00
|
|
|
{
|
|
|
|
if (state->is_identity && initialize)
|
|
|
|
cogl_matrix_init_identity (&state->matrix);
|
|
|
|
return state;
|
|
|
|
}
|
2009-02-24 18:51:25 +00:00
|
|
|
|
|
|
|
state->push_count -= 1;
|
|
|
|
|
2010-11-01 22:07:11 +00:00
|
|
|
g_array_set_size (stack->stack, stack->stack->len + 1);
|
|
|
|
new_top = &g_array_index (stack->stack, CoglMatrixState,
|
|
|
|
stack->stack->len - 1);
|
|
|
|
_cogl_matrix_state_init (new_top);
|
2009-02-24 18:51:25 +00:00
|
|
|
|
2009-10-06 09:52:07 +00:00
|
|
|
if (initialize)
|
2009-02-24 18:51:25 +00:00
|
|
|
{
|
2009-10-06 11:36:32 +00:00
|
|
|
if (state->is_identity)
|
|
|
|
cogl_matrix_init_identity (&new_top->matrix);
|
|
|
|
else
|
|
|
|
new_top->matrix = state->matrix;
|
2009-02-24 18:51:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return new_top;
|
|
|
|
}
|
|
|
|
|
|
|
|
CoglMatrixStack*
|
|
|
|
_cogl_matrix_stack_new (void)
|
|
|
|
{
|
|
|
|
CoglMatrixStack *stack;
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
|
|
|
stack = g_slice_new0 (CoglMatrixStack);
|
2009-10-06 09:52:07 +00:00
|
|
|
|
2010-11-01 22:07:11 +00:00
|
|
|
stack->stack = g_array_sized_new (FALSE, FALSE,
|
|
|
|
sizeof (CoglMatrixState), 10);
|
|
|
|
g_array_set_size (stack->stack, 1);
|
|
|
|
state = &g_array_index (stack->stack, CoglMatrixState, 0);
|
|
|
|
_cogl_matrix_state_init (state);
|
2009-10-06 11:36:32 +00:00
|
|
|
state->is_identity = TRUE;
|
2009-10-06 09:52:07 +00:00
|
|
|
|
2010-12-10 11:13:09 +00:00
|
|
|
stack->age = 0;
|
|
|
|
|
2010-12-10 16:06:16 +00:00
|
|
|
return _cogl_matrix_stack_object_new (stack);
|
2009-02-24 18:51:25 +00:00
|
|
|
}
|
|
|
|
|
2010-12-10 16:06:16 +00:00
|
|
|
static void
|
|
|
|
_cogl_matrix_stack_free (CoglMatrixStack *stack)
|
2009-02-24 18:51:25 +00:00
|
|
|
{
|
2010-11-01 22:07:11 +00:00
|
|
|
g_array_free (stack->stack, TRUE);
|
2009-02-24 18:51:25 +00:00
|
|
|
g_slice_free (CoglMatrixStack, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_matrix_stack_push (CoglMatrixStack *stack)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
|
|
|
state = _cogl_matrix_stack_top (stack);
|
|
|
|
|
|
|
|
/* we lazily create a new stack top if someone changes the matrix
|
|
|
|
* while push_count > 0
|
|
|
|
*/
|
|
|
|
state->push_count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_matrix_stack_pop (CoglMatrixStack *stack)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
|
|
|
state = _cogl_matrix_stack_top (stack);
|
|
|
|
|
|
|
|
if (state->push_count > 0)
|
|
|
|
{
|
|
|
|
state->push_count -= 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-11-01 22:07:11 +00:00
|
|
|
if (stack->stack->len == 1)
|
2009-02-24 18:51:25 +00:00
|
|
|
{
|
|
|
|
g_warning ("Too many matrix pops");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-12-10 11:13:09 +00:00
|
|
|
stack->age++;
|
2010-11-01 22:07:11 +00:00
|
|
|
g_array_set_size (stack->stack, stack->stack->len - 1);
|
2009-02-24 18:51:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_matrix_stack_load_identity (CoglMatrixStack *stack)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
2009-10-06 09:52:07 +00:00
|
|
|
state = _cogl_matrix_stack_top_mutable (stack, FALSE);
|
2009-02-24 18:51:25 +00:00
|
|
|
|
2009-10-06 11:36:32 +00:00
|
|
|
/* NB: Identity matrices are represented by setting
|
|
|
|
* state->is_identity = TRUE and leaving state->matrix
|
|
|
|
* uninitialized.
|
|
|
|
*
|
|
|
|
* This is done to optimize the heavy usage of
|
|
|
|
* _cogl_matrix_stack_load_identity by the Cogl Journal.
|
|
|
|
*/
|
|
|
|
if (!state->is_identity)
|
|
|
|
{
|
|
|
|
state->is_identity = TRUE;
|
2010-12-10 11:13:09 +00:00
|
|
|
stack->age++;
|
2009-10-06 11:36:32 +00:00
|
|
|
}
|
2009-02-24 18:51:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_matrix_stack_scale (CoglMatrixStack *stack,
|
|
|
|
float x,
|
|
|
|
float y,
|
|
|
|
float z)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
2009-10-06 09:52:07 +00:00
|
|
|
state = _cogl_matrix_stack_top_mutable (stack, TRUE);
|
2009-02-24 18:51:25 +00:00
|
|
|
cogl_matrix_scale (&state->matrix, x, y, z);
|
2009-10-06 11:36:32 +00:00
|
|
|
state->is_identity = FALSE;
|
2010-12-10 11:13:09 +00:00
|
|
|
stack->age++;
|
2009-02-24 18:51:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_matrix_stack_translate (CoglMatrixStack *stack,
|
|
|
|
float x,
|
|
|
|
float y,
|
|
|
|
float z)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
2009-10-06 09:52:07 +00:00
|
|
|
state = _cogl_matrix_stack_top_mutable (stack, TRUE);
|
2009-02-24 18:51:25 +00:00
|
|
|
cogl_matrix_translate (&state->matrix, x, y, z);
|
2009-10-06 11:36:32 +00:00
|
|
|
state->is_identity = FALSE;
|
2010-12-10 11:13:09 +00:00
|
|
|
stack->age++;
|
2009-02-24 18:51:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_matrix_stack_rotate (CoglMatrixStack *stack,
|
|
|
|
float angle,
|
|
|
|
float x,
|
|
|
|
float y,
|
|
|
|
float z)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
2009-10-06 09:52:07 +00:00
|
|
|
state = _cogl_matrix_stack_top_mutable (stack, TRUE);
|
2009-02-24 18:51:25 +00:00
|
|
|
cogl_matrix_rotate (&state->matrix, angle, x, y, z);
|
2009-10-06 11:36:32 +00:00
|
|
|
state->is_identity = FALSE;
|
2010-12-10 11:13:09 +00:00
|
|
|
stack->age++;
|
2009-02-24 18:51:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_matrix_stack_multiply (CoglMatrixStack *stack,
|
|
|
|
const CoglMatrix *matrix)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
2009-10-06 09:52:07 +00:00
|
|
|
state = _cogl_matrix_stack_top_mutable (stack, TRUE);
|
2009-02-24 18:51:25 +00:00
|
|
|
cogl_matrix_multiply (&state->matrix, &state->matrix, matrix);
|
2009-10-06 11:36:32 +00:00
|
|
|
state->is_identity = FALSE;
|
2010-12-10 11:13:09 +00:00
|
|
|
stack->age++;
|
2009-02-24 18:51:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-05-26 10:33:54 +00:00
|
|
|
_cogl_matrix_stack_frustum (CoglMatrixStack *stack,
|
|
|
|
float left,
|
|
|
|
float right,
|
|
|
|
float bottom,
|
|
|
|
float top,
|
|
|
|
float z_near,
|
|
|
|
float z_far)
|
2009-02-24 18:51:25 +00:00
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
2009-10-06 09:52:07 +00:00
|
|
|
state = _cogl_matrix_stack_top_mutable (stack, TRUE);
|
2009-05-26 10:33:54 +00:00
|
|
|
cogl_matrix_frustum (&state->matrix,
|
|
|
|
left, right, bottom, top,
|
|
|
|
z_near, z_far);
|
2009-10-06 11:36:32 +00:00
|
|
|
state->is_identity = FALSE;
|
2010-12-10 11:13:09 +00:00
|
|
|
stack->age++;
|
2009-05-26 10:33:54 +00:00
|
|
|
}
|
2009-02-24 18:51:25 +00:00
|
|
|
|
2009-05-26 10:33:54 +00:00
|
|
|
void
|
|
|
|
_cogl_matrix_stack_perspective (CoglMatrixStack *stack,
|
|
|
|
float fov_y,
|
|
|
|
float aspect,
|
|
|
|
float z_near,
|
|
|
|
float z_far)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
2009-10-06 09:52:07 +00:00
|
|
|
state = _cogl_matrix_stack_top_mutable (stack, TRUE);
|
2009-05-26 10:33:54 +00:00
|
|
|
cogl_matrix_perspective (&state->matrix,
|
|
|
|
fov_y, aspect, z_near, z_far);
|
2009-10-06 11:36:32 +00:00
|
|
|
state->is_identity = FALSE;
|
2010-12-10 11:13:09 +00:00
|
|
|
stack->age++;
|
2009-02-24 18:51:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-05-26 10:33:54 +00:00
|
|
|
_cogl_matrix_stack_ortho (CoglMatrixStack *stack,
|
|
|
|
float left,
|
|
|
|
float right,
|
|
|
|
float bottom,
|
|
|
|
float top,
|
|
|
|
float z_near,
|
|
|
|
float z_far)
|
2009-02-24 18:51:25 +00:00
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
2009-10-06 09:52:07 +00:00
|
|
|
state = _cogl_matrix_stack_top_mutable (stack, TRUE);
|
2009-05-26 10:33:54 +00:00
|
|
|
cogl_matrix_ortho (&state->matrix,
|
|
|
|
left, right, bottom, top, z_near, z_far);
|
2009-10-06 11:36:32 +00:00
|
|
|
state->is_identity = FALSE;
|
2010-12-10 11:13:09 +00:00
|
|
|
stack->age++;
|
2009-02-24 18:51:25 +00:00
|
|
|
}
|
|
|
|
|
2009-10-26 17:51:34 +00:00
|
|
|
gboolean
|
|
|
|
_cogl_matrix_stack_get_inverse (CoglMatrixStack *stack,
|
|
|
|
CoglMatrix *inverse)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
|
|
|
state = _cogl_matrix_stack_top_mutable (stack, TRUE);
|
|
|
|
|
|
|
|
return cogl_matrix_get_inverse (&state->matrix, inverse);
|
|
|
|
}
|
|
|
|
|
2009-02-24 18:51:25 +00:00
|
|
|
void
|
2009-05-26 10:33:54 +00:00
|
|
|
_cogl_matrix_stack_get (CoglMatrixStack *stack,
|
|
|
|
CoglMatrix *matrix)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
|
|
|
state = _cogl_matrix_stack_top (stack);
|
|
|
|
|
2009-10-06 11:36:32 +00:00
|
|
|
/* NB: identity matrices are lazily initialized because we can often avoid
|
|
|
|
* initializing them at all if nothing is pushed on top of them since we
|
|
|
|
* load them using glLoadIdentity()
|
|
|
|
*
|
|
|
|
* The Cogl journal typically loads an identiy matrix because it performs
|
|
|
|
* software transformations, which is why we have optimized this case.
|
|
|
|
*/
|
|
|
|
if (state->is_identity)
|
|
|
|
cogl_matrix_init_identity (matrix);
|
|
|
|
else
|
|
|
|
*matrix = state->matrix;
|
2009-05-26 10:33:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_matrix_stack_set (CoglMatrixStack *stack,
|
|
|
|
const CoglMatrix *matrix)
|
2009-02-24 18:51:25 +00:00
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
2009-10-06 11:36:32 +00:00
|
|
|
state = _cogl_matrix_stack_top_mutable (stack, FALSE);
|
2009-05-26 10:33:54 +00:00
|
|
|
state->matrix = *matrix;
|
2009-10-06 11:36:32 +00:00
|
|
|
state->is_identity = FALSE;
|
2010-12-06 12:31:51 +00:00
|
|
|
stack->age++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2011-11-29 14:21:07 +00:00
|
|
|
_cogl_matrix_stack_flush_matrix_to_gl_builtin (CoglContext *ctx,
|
|
|
|
gboolean is_identity,
|
|
|
|
CoglMatrix *matrix,
|
|
|
|
CoglMatrixMode mode)
|
2010-12-06 12:31:51 +00:00
|
|
|
{
|
2011-11-29 14:21:07 +00:00
|
|
|
g_assert (ctx->driver == COGL_DRIVER_GL ||
|
|
|
|
ctx->driver == COGL_DRIVER_GLES1);
|
2010-12-06 12:31:51 +00:00
|
|
|
|
2011-11-29 14:21:07 +00:00
|
|
|
#if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
|
|
|
|
if (ctx->flushed_matrix_mode != mode)
|
2010-12-06 12:31:51 +00:00
|
|
|
{
|
2011-11-29 14:21:07 +00:00
|
|
|
GLenum gl_mode = 0;
|
2010-02-09 16:57:14 +00:00
|
|
|
|
2009-10-14 09:53:48 +00:00
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case COGL_MATRIX_MODELVIEW:
|
2011-11-29 14:21:07 +00:00
|
|
|
gl_mode = GL_MODELVIEW;
|
2009-10-14 09:53:48 +00:00
|
|
|
break;
|
2010-02-09 16:57:14 +00:00
|
|
|
|
2009-10-14 09:53:48 +00:00
|
|
|
case COGL_MATRIX_PROJECTION:
|
2011-11-29 14:21:07 +00:00
|
|
|
gl_mode = GL_PROJECTION;
|
2009-10-14 09:53:48 +00:00
|
|
|
break;
|
2010-02-09 16:57:14 +00:00
|
|
|
|
2009-10-14 09:53:48 +00:00
|
|
|
case COGL_MATRIX_TEXTURE:
|
2011-11-29 14:21:07 +00:00
|
|
|
gl_mode = GL_TEXTURE;
|
2009-10-14 09:53:48 +00:00
|
|
|
break;
|
|
|
|
}
|
2011-11-29 14:21:07 +00:00
|
|
|
|
|
|
|
GE (ctx, glMatrixMode (gl_mode));
|
|
|
|
ctx->flushed_matrix_mode = mode;
|
2009-09-29 01:58:27 +00:00
|
|
|
}
|
2009-02-24 18:51:25 +00:00
|
|
|
|
2011-11-29 14:21:07 +00:00
|
|
|
if (is_identity)
|
|
|
|
GE (ctx, glLoadIdentity ());
|
2011-07-07 19:44:56 +00:00
|
|
|
else
|
2011-11-29 14:21:07 +00:00
|
|
|
GE (ctx, glLoadMatrixf (cogl_matrix_get_array (matrix)));
|
|
|
|
#endif
|
|
|
|
}
|
2011-07-07 19:44:56 +00:00
|
|
|
|
2011-11-29 14:21:07 +00:00
|
|
|
void
|
|
|
|
_cogl_matrix_stack_flush_to_gl_builtins (CoglContext *ctx,
|
|
|
|
CoglMatrixStack *stack,
|
|
|
|
CoglMatrixMode mode,
|
|
|
|
gboolean disable_flip)
|
|
|
|
{
|
|
|
|
g_assert (ctx->driver == COGL_DRIVER_GL ||
|
|
|
|
ctx->driver == COGL_DRIVER_GLES1);
|
2011-07-07 19:44:56 +00:00
|
|
|
|
2011-11-29 14:21:07 +00:00
|
|
|
#if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
|
|
|
|
{
|
|
|
|
gboolean needs_flip;
|
|
|
|
CoglMatrixState *state;
|
|
|
|
CoglMatrixStackCache *cache;
|
|
|
|
|
|
|
|
state = _cogl_matrix_stack_top (stack);
|
|
|
|
|
|
|
|
if (mode == COGL_MATRIX_PROJECTION)
|
|
|
|
{
|
|
|
|
/* Because Cogl defines texture coordinates to have a top left
|
|
|
|
* origin and because offscreen framebuffers may be used for
|
|
|
|
* rendering to textures we always render upside down to
|
|
|
|
* offscreen buffers. Also for some backends we need to render
|
|
|
|
* onscreen buffers upside-down too.
|
|
|
|
*/
|
|
|
|
if (disable_flip)
|
|
|
|
needs_flip = FALSE;
|
|
|
|
else
|
|
|
|
needs_flip = cogl_is_offscreen (cogl_get_draw_framebuffer ());
|
|
|
|
|
|
|
|
cache = &ctx->builtin_flushed_projection;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
needs_flip = FALSE;
|
|
|
|
|
|
|
|
if (mode == COGL_MATRIX_MODELVIEW)
|
|
|
|
cache = &ctx->builtin_flushed_modelview;
|
|
|
|
else
|
|
|
|
cache = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We don't need to do anything if the state is the same */
|
|
|
|
if (!cache ||
|
|
|
|
_cogl_matrix_stack_check_and_update_cache (stack, cache, needs_flip))
|
|
|
|
{
|
|
|
|
gboolean is_identity = state->is_identity && !needs_flip;
|
|
|
|
|
|
|
|
if (needs_flip)
|
|
|
|
{
|
|
|
|
CoglMatrix flipped_matrix;
|
|
|
|
|
|
|
|
cogl_matrix_multiply (&flipped_matrix,
|
|
|
|
&ctx->y_flip_matrix,
|
|
|
|
state->is_identity ?
|
|
|
|
&ctx->identity_matrix :
|
|
|
|
&state->matrix);
|
|
|
|
|
|
|
|
_cogl_matrix_stack_flush_matrix_to_gl_builtin (ctx,
|
|
|
|
/* not identity */
|
|
|
|
FALSE,
|
|
|
|
&flipped_matrix,
|
|
|
|
mode);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
_cogl_matrix_stack_flush_matrix_to_gl_builtin (ctx,
|
|
|
|
is_identity,
|
|
|
|
&state->matrix,
|
|
|
|
mode);
|
|
|
|
}
|
|
|
|
}
|
2011-07-07 19:44:56 +00:00
|
|
|
#endif
|
2009-06-17 01:08:31 +00:00
|
|
|
}
|
|
|
|
|
2010-12-10 11:13:09 +00:00
|
|
|
unsigned int
|
|
|
|
_cogl_matrix_stack_get_age (CoglMatrixStack *stack)
|
|
|
|
{
|
|
|
|
return stack->age;
|
|
|
|
}
|
2010-12-10 17:42:39 +00:00
|
|
|
|
|
|
|
gboolean
|
|
|
|
_cogl_matrix_stack_has_identity_flag (CoglMatrixStack *stack)
|
|
|
|
{
|
|
|
|
return _cogl_matrix_stack_top (stack)->is_identity;
|
|
|
|
}
|
2011-11-21 15:49:58 +00:00
|
|
|
|
|
|
|
gboolean
|
|
|
|
_cogl_matrix_stack_equal (CoglMatrixStack *stack0,
|
|
|
|
CoglMatrixStack *stack1)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state0 = _cogl_matrix_stack_top (stack0);
|
|
|
|
CoglMatrixState *state1 = _cogl_matrix_stack_top (stack1);
|
|
|
|
|
|
|
|
if (state0->is_identity != state1->is_identity)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (state0->is_identity)
|
|
|
|
return TRUE;
|
|
|
|
else
|
|
|
|
return cogl_matrix_equal (&state0->matrix, &state1->matrix);
|
|
|
|
}
|
2011-11-29 14:21:07 +00:00
|
|
|
|
|
|
|
gboolean
|
|
|
|
_cogl_matrix_stack_check_and_update_cache (CoglMatrixStack *stack,
|
|
|
|
CoglMatrixStackCache *cache,
|
|
|
|
gboolean flip)
|
|
|
|
{
|
|
|
|
gboolean is_identity =
|
|
|
|
_cogl_matrix_stack_has_identity_flag (stack) && !flip;
|
|
|
|
gboolean is_dirty;
|
|
|
|
|
|
|
|
if (is_identity && cache->flushed_identity)
|
|
|
|
is_dirty = FALSE;
|
|
|
|
else if (cache->stack == NULL ||
|
|
|
|
cache->stack->age != cache->age ||
|
|
|
|
flip != cache->flipped)
|
|
|
|
is_dirty = TRUE;
|
|
|
|
else
|
|
|
|
is_dirty = (cache->stack != stack &&
|
|
|
|
!_cogl_matrix_stack_equal (cache->stack, stack));
|
|
|
|
|
|
|
|
/* We'll update the cache values even if the stack isn't dirty in
|
|
|
|
case the reason it wasn't dirty is because we compared the
|
|
|
|
matrices and found them to be the same. In that case updating the
|
|
|
|
cache values will avoid the comparison next time */
|
|
|
|
cache->age = stack->age;
|
|
|
|
cogl_object_ref (stack);
|
|
|
|
if (cache->stack)
|
|
|
|
cogl_object_unref (cache->stack);
|
|
|
|
cache->stack = stack;
|
|
|
|
cache->flushed_identity = is_identity;
|
|
|
|
cache->flipped = flip;
|
|
|
|
|
|
|
|
return is_dirty;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_matrix_stack_init_cache (CoglMatrixStackCache *cache)
|
|
|
|
{
|
|
|
|
cache->stack = NULL;
|
|
|
|
cache->flushed_identity = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_matrix_stack_destroy_cache (CoglMatrixStackCache *cache)
|
|
|
|
{
|
|
|
|
if (cache->stack)
|
|
|
|
cogl_object_unref (cache->stack);
|
|
|
|
}
|