2009-02-24 13:51:25 -05:00
|
|
|
/*
|
2009-04-27 10:48:12 -04:00
|
|
|
* Cogl
|
2009-02-24 13:51:25 -05:00
|
|
|
*
|
2009-04-27 10:48:12 -04:00
|
|
|
* An object oriented GL/GLES Abstraction/Utility Layer
|
2009-02-24 13:51:25 -05:00
|
|
|
*
|
2009-04-27 10:48:12 -04:00
|
|
|
* Copyright (C) 2009 Intel Corporation.
|
2009-02-24 13:51:25 -05: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
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
* Boston, MA 02111-1307, USA.
|
2009-04-27 10:48:12 -04:00
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Havoc Pennington <hp@pobox.com> for litl
|
2009-02-24 13:51:25 -05:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "cogl.h"
|
|
|
|
#include "cogl-context.h"
|
|
|
|
#include "cogl-internal.h"
|
|
|
|
#include "cogl-matrix-stack.h"
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
CoglMatrix matrix;
|
|
|
|
/* 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
|
|
|
|
{
|
|
|
|
GSList *stack;
|
|
|
|
|
|
|
|
/* which state does GL have, NULL if unknown */
|
|
|
|
CoglMatrixState *flushed_state;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static CoglMatrixState*
|
|
|
|
_cogl_matrix_state_new (void)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
|
|
|
state = g_slice_new0 (CoglMatrixState);
|
|
|
|
|
|
|
|
/* load identity */
|
|
|
|
cogl_matrix_init_identity (&state->matrix);
|
|
|
|
|
|
|
|
/* state->push_count defaults to 0 */
|
|
|
|
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_cogl_matrix_state_destroy (CoglMatrixState *state)
|
|
|
|
{
|
|
|
|
|
|
|
|
g_slice_free (CoglMatrixState, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
static CoglMatrixState*
|
|
|
|
_cogl_matrix_stack_top (CoglMatrixStack *stack)
|
|
|
|
{
|
|
|
|
return stack->stack->data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static CoglMatrixState*
|
|
|
|
_cogl_matrix_stack_top_mutable (CoglMatrixStack *stack)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
CoglMatrixState *new_top;
|
|
|
|
|
|
|
|
state = _cogl_matrix_stack_top (stack);
|
|
|
|
|
|
|
|
if (state->push_count == 0)
|
|
|
|
return state;
|
|
|
|
|
|
|
|
state->push_count -= 1;
|
|
|
|
|
|
|
|
new_top = _cogl_matrix_state_new ();
|
|
|
|
|
|
|
|
new_top->matrix = state->matrix;
|
|
|
|
|
|
|
|
if (stack->flushed_state == state)
|
|
|
|
{
|
|
|
|
stack->flushed_state = new_top;
|
|
|
|
}
|
|
|
|
|
|
|
|
stack->stack =
|
|
|
|
g_slist_prepend (stack->stack,
|
|
|
|
new_top);
|
|
|
|
|
|
|
|
return new_top;
|
|
|
|
}
|
|
|
|
|
|
|
|
CoglMatrixStack*
|
|
|
|
_cogl_matrix_stack_new (void)
|
|
|
|
{
|
|
|
|
CoglMatrixStack *stack;
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
|
|
|
stack = g_slice_new0 (CoglMatrixStack);
|
|
|
|
state = _cogl_matrix_state_new ();
|
|
|
|
stack->stack =
|
|
|
|
g_slist_prepend (stack->stack,
|
|
|
|
state);
|
|
|
|
|
|
|
|
return stack;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_matrix_stack_destroy (CoglMatrixStack *stack)
|
|
|
|
{
|
|
|
|
while (stack->stack)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
|
|
|
state = stack->stack->data;
|
|
|
|
_cogl_matrix_state_destroy (state);
|
|
|
|
stack->stack =
|
|
|
|
g_slist_delete_link (stack->stack,
|
|
|
|
stack->stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
if (stack->stack->next == NULL)
|
|
|
|
{
|
|
|
|
g_warning ("Too many matrix pops");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stack->flushed_state == state)
|
|
|
|
{
|
|
|
|
stack->flushed_state = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
stack->stack =
|
|
|
|
g_slist_delete_link (stack->stack,
|
|
|
|
stack->stack);
|
|
|
|
_cogl_matrix_state_destroy (state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_matrix_stack_load_identity (CoglMatrixStack *stack)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
|
|
|
state = _cogl_matrix_stack_top_mutable (stack);
|
|
|
|
cogl_matrix_init_identity (&state->matrix);
|
|
|
|
|
|
|
|
/* mark dirty */
|
|
|
|
stack->flushed_state = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_matrix_stack_scale (CoglMatrixStack *stack,
|
|
|
|
float x,
|
|
|
|
float y,
|
|
|
|
float z)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
|
|
|
state = _cogl_matrix_stack_top_mutable (stack);
|
|
|
|
cogl_matrix_scale (&state->matrix, x, y, z);
|
|
|
|
/* mark dirty */
|
|
|
|
stack->flushed_state = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_matrix_stack_translate (CoglMatrixStack *stack,
|
|
|
|
float x,
|
|
|
|
float y,
|
|
|
|
float z)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
|
|
|
state = _cogl_matrix_stack_top_mutable (stack);
|
|
|
|
cogl_matrix_translate (&state->matrix, x, y, z);
|
|
|
|
/* mark dirty */
|
|
|
|
stack->flushed_state = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_matrix_stack_rotate (CoglMatrixStack *stack,
|
|
|
|
float angle,
|
|
|
|
float x,
|
|
|
|
float y,
|
|
|
|
float z)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
|
|
|
state = _cogl_matrix_stack_top_mutable (stack);
|
|
|
|
cogl_matrix_rotate (&state->matrix, angle, x, y, z);
|
|
|
|
/* mark dirty */
|
|
|
|
stack->flushed_state = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_matrix_stack_multiply (CoglMatrixStack *stack,
|
|
|
|
const CoglMatrix *matrix)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
|
|
|
state = _cogl_matrix_stack_top_mutable (stack);
|
|
|
|
cogl_matrix_multiply (&state->matrix, &state->matrix, matrix);
|
|
|
|
/* mark dirty */
|
|
|
|
stack->flushed_state = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-05-26 06:33:54 -04:00
|
|
|
_cogl_matrix_stack_frustum (CoglMatrixStack *stack,
|
|
|
|
float left,
|
|
|
|
float right,
|
|
|
|
float bottom,
|
|
|
|
float top,
|
|
|
|
float z_near,
|
|
|
|
float z_far)
|
2009-02-24 13:51:25 -05:00
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
2009-05-26 06:33:54 -04:00
|
|
|
state = _cogl_matrix_stack_top_mutable (stack);
|
|
|
|
cogl_matrix_frustum (&state->matrix,
|
|
|
|
left, right, bottom, top,
|
|
|
|
z_near, z_far);
|
|
|
|
/* mark dirty */
|
|
|
|
stack->flushed_state = NULL;
|
|
|
|
}
|
2009-02-24 13:51:25 -05:00
|
|
|
|
2009-05-26 06:33:54 -04:00
|
|
|
void
|
|
|
|
_cogl_matrix_stack_perspective (CoglMatrixStack *stack,
|
|
|
|
float fov_y,
|
|
|
|
float aspect,
|
|
|
|
float z_near,
|
|
|
|
float z_far)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
|
|
|
state = _cogl_matrix_stack_top_mutable (stack);
|
|
|
|
cogl_matrix_perspective (&state->matrix,
|
|
|
|
fov_y, aspect, z_near, z_far);
|
|
|
|
/* mark dirty */
|
|
|
|
stack->flushed_state = NULL;
|
2009-02-24 13:51:25 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-05-26 06:33:54 -04:00
|
|
|
_cogl_matrix_stack_ortho (CoglMatrixStack *stack,
|
|
|
|
float left,
|
|
|
|
float right,
|
|
|
|
float bottom,
|
|
|
|
float top,
|
|
|
|
float z_near,
|
|
|
|
float z_far)
|
2009-02-24 13:51:25 -05:00
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
|
|
|
state = _cogl_matrix_stack_top_mutable (stack);
|
2009-05-26 06:33:54 -04:00
|
|
|
cogl_matrix_ortho (&state->matrix,
|
|
|
|
left, right, bottom, top, z_near, z_far);
|
2009-02-24 13:51:25 -05:00
|
|
|
/* mark dirty */
|
|
|
|
stack->flushed_state = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-05-26 06:33:54 -04:00
|
|
|
_cogl_matrix_stack_get (CoglMatrixStack *stack,
|
|
|
|
CoglMatrix *matrix)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
|
|
|
state = _cogl_matrix_stack_top (stack);
|
|
|
|
|
|
|
|
*matrix = state->matrix;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_matrix_stack_set (CoglMatrixStack *stack,
|
|
|
|
const CoglMatrix *matrix)
|
2009-02-24 13:51:25 -05:00
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
|
|
|
state = _cogl_matrix_stack_top_mutable (stack);
|
2009-05-26 06:33:54 -04:00
|
|
|
state->matrix = *matrix;
|
2009-02-24 13:51:25 -05:00
|
|
|
/* mark dirty */
|
|
|
|
stack->flushed_state = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_cogl_matrix_stack_flush_to_gl (CoglMatrixStack *stack,
|
|
|
|
GLenum gl_mode)
|
|
|
|
{
|
|
|
|
CoglMatrixState *state;
|
|
|
|
|
|
|
|
state = _cogl_matrix_stack_top (stack);
|
|
|
|
|
|
|
|
if (stack->flushed_state == state)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* NOTE we assume caller was in MODELVIEW mode */
|
|
|
|
|
|
|
|
if (gl_mode != GL_MODELVIEW)
|
|
|
|
GE (glMatrixMode (gl_mode));
|
|
|
|
|
|
|
|
/* In theory it might help the GL implementation if we used our
|
|
|
|
* local analysis of the matrix and called Translate/Scale rather
|
|
|
|
* than LoadMatrix to send a 2D matrix
|
|
|
|
*/
|
|
|
|
|
|
|
|
GE (glLoadMatrixf (cogl_matrix_get_array (&state->matrix)));
|
|
|
|
stack->flushed_state = state;
|
|
|
|
|
|
|
|
if (gl_mode != GL_MODELVIEW)
|
|
|
|
GE (glMatrixMode (GL_MODELVIEW));
|
|
|
|
}
|