Example #1
0
static void *
_cogl_matrix_stack_push_replacement_entry (CoglMatrixStack *stack,
                                           CoglMatrixOp operation)
{
  CoglMatrixEntry *old_top = stack->last_entry;
  CoglMatrixEntry *new_top;

  /* This would only be called for operations that completely replace
   * the matrix. In that case we don't need to keep a reference to
   * anything up to the last save entry. This optimisation could be
   * important for applications that aren't using the stack but
   * instead just perform their own matrix manipulations and load a
   * new stack every frame. If this optimisation isn't done then the
   * stack would just grow endlessly. See the comments
   * cogl_matrix_stack_pop for a description of how popping works. */
  for (new_top = old_top;
       new_top->op != COGL_MATRIX_OP_SAVE && new_top->parent;
       new_top = new_top->parent)
    ;

  cogl_matrix_entry_ref (new_top);
  cogl_matrix_entry_unref (old_top);
  stack->last_entry = new_top;

  return _cogl_matrix_stack_push_operation (stack, operation);
}
Example #2
0
void
_cogl_context_set_current_modelview_entry (CoglContext *context,
                                           CoglMatrixEntry *entry)
{
  cogl_matrix_entry_ref (entry);
  if (context->current_modelview_entry)
    cogl_matrix_entry_unref (context->current_modelview_entry);
  context->current_modelview_entry = entry;
}
Example #3
0
CoglClipStack *
_cogl_clip_stack_push_primitive (CoglClipStack *stack,
                                 CoglPrimitive *primitive,
                                 float bounds_x1,
                                 float bounds_y1,
                                 float bounds_x2,
                                 float bounds_y2,
                                 CoglMatrixEntry *modelview_entry,
                                 CoglMatrixEntry *projection_entry,
                                 const float *viewport)
{
  CoglClipStackPrimitive *entry;
  CoglMatrix modelview;
  CoglMatrix projection;
  float transformed_corners[8];

  entry = _cogl_clip_stack_push_entry (stack,
                                       sizeof (CoglClipStackPrimitive),
                                       COGL_CLIP_STACK_PRIMITIVE);

  entry->primitive = cogl_object_ref (primitive);

  entry->matrix_entry = cogl_matrix_entry_ref (modelview_entry);

  entry->bounds_x1 = bounds_x1;
  entry->bounds_y1 = bounds_y1;
  entry->bounds_x2 = bounds_x2;
  entry->bounds_y2 = bounds_y2;

  cogl_matrix_entry_get (modelview_entry, &modelview);
  cogl_matrix_entry_get (projection_entry, &projection);

  get_transformed_corners (bounds_x1, bounds_y1, bounds_x2, bounds_y2,
                           &modelview,
                           &projection,
                           viewport,
                           transformed_corners);

  /* NB: this is referring to the bounds in window coordinates as opposed
   * to the bounds above in primitive local coordinates. */
  _cogl_clip_stack_entry_set_bounds ((CoglClipStack *) entry,
                                     transformed_corners);

  return (CoglClipStack *) entry;
}
Example #4
0
CoglMatrixStack *
cogl_matrix_stack_new (CoglContext *ctx)
{
  CoglMatrixStack *stack = g_slice_new (CoglMatrixStack);

  if (G_UNLIKELY (cogl_matrix_stack_magazine == NULL))
    {
      cogl_matrix_stack_magazine =
        _cogl_magazine_new (sizeof (CoglMatrixEntryFull), 20);
      cogl_matrix_stack_matrices_magazine =
        _cogl_magazine_new (sizeof (CoglMatrix), 20);
    }

  stack->context = ctx;
  stack->last_entry = NULL;

  cogl_matrix_entry_ref (&ctx->identity_entry);
  _cogl_matrix_stack_push_entry (stack, &ctx->identity_entry);

  return _cogl_matrix_stack_object_new (stack);
}
Example #5
0
/* NB: This function can report false negatives since it never does a
 * deep comparison of the stack matrices. */
CoglBool
_cogl_matrix_entry_cache_maybe_update (CoglMatrixEntryCache *cache,
                                       CoglMatrixEntry *entry,
                                       CoglBool flip)
{
  CoglBool is_identity;
  CoglBool updated = FALSE;

  if (cache->flipped != flip)
    {
      cache->flipped = flip;
      updated = TRUE;
    }

  is_identity = (entry->op == COGL_MATRIX_OP_LOAD_IDENTITY);
  if (cache->flushed_identity != is_identity)
    {
      cache->flushed_identity = is_identity;
      updated = TRUE;
    }

  if (cache->entry != entry)
    {
      cogl_matrix_entry_ref (entry);
      if (cache->entry)
        cogl_matrix_entry_unref (cache->entry);
      cache->entry = entry;

      /* We want to make sure here that if the cache->entry and the
       * given @entry are both identity matrices then even though they
       * are different entries we don't want to consider this an
       * update...
       */
      updated |= !is_identity;
    }

  return updated;
}
Example #6
0
void
cogl_matrix_stack_pop (CoglMatrixStack *stack)
{
  CoglMatrixEntry *old_top;
  CoglMatrixEntry *new_top;

  _COGL_RETURN_IF_FAIL (stack != NULL);

  old_top = stack->last_entry;
  _COGL_RETURN_IF_FAIL (old_top != NULL);

  /* To pop we are moving the top of the stack to the old top's parent
   * node. The stack always needs to have a reference to the top entry
   * so we must take a reference to the new top. The stack would have
   * previously had a reference to the old top so we need to decrease
   * the ref count on that. We need to ref the new head first in case
   * this stack was the only thing referencing the old top. In that
   * case the call to cogl_matrix_entry_unref will unref the parent.
   */

  /* Find the last save operation and remove it */

  /* XXX: it would be an error to pop to the very beginning of the
   * stack so we don't need to check for NULL pointer dereferencing. */
  for (new_top = old_top;
       new_top->op != COGL_MATRIX_OP_SAVE;
       new_top = new_top->parent)
    ;

  new_top = new_top->parent;
  cogl_matrix_entry_ref (new_top);

  cogl_matrix_entry_unref (old_top);

  stack->last_entry = new_top;
}
Example #7
0
CoglClipStack *
_cogl_clip_stack_push_rectangle (CoglClipStack *stack,
                                 float x_1,
                                 float y_1,
                                 float x_2,
                                 float y_2,
                                 CoglMatrixEntry *modelview_entry,
                                 CoglMatrixEntry *projection_entry,
                                 const float *viewport)
{
  CoglClipStackRect *entry;
  CoglMatrix modelview;
  CoglMatrix projection;
  CoglMatrix modelview_projection;

  /* Corners of the given rectangle in an clockwise order:
   *  (0, 1)     (2, 3)
   *
   *
   *
   *  (6, 7)     (4, 5)
   */
  float rect[] = {
    x_1, y_1,
    x_2, y_1,
    x_2, y_2,
    x_1, y_2
  };

  /* Make a new entry */
  entry = _cogl_clip_stack_push_entry (stack,
                                       sizeof (CoglClipStackRect),
                                       COGL_CLIP_STACK_RECT);

  entry->x0 = x_1;
  entry->y0 = y_1;
  entry->x1 = x_2;
  entry->y1 = y_2;

  entry->matrix_entry = cogl_matrix_entry_ref (modelview_entry);

  cogl_matrix_entry_get (modelview_entry, &modelview);
  cogl_matrix_entry_get (projection_entry, &projection);

  cogl_matrix_multiply (&modelview_projection,
                        &projection,
                        &modelview);

  /* Technically we could avoid the viewport transform at this point
   * if we want to make this a bit faster. */
  _cogl_transform_point (&modelview, &projection, viewport, &rect[0], &rect[1]);
  _cogl_transform_point (&modelview, &projection, viewport, &rect[2], &rect[3]);
  _cogl_transform_point (&modelview, &projection, viewport, &rect[4], &rect[5]);
  _cogl_transform_point (&modelview, &projection, viewport, &rect[6], &rect[7]);

  /* If the fully transformed rectangle isn't still axis aligned we
   * can't handle it using a scissor.
   *
   * We don't use an epsilon here since we only really aim to catch
   * simple cases where the transform doesn't leave the rectangle screen
   * aligned and don't mind some false positives.
   */
  if (rect[0] != rect[6] ||
      rect[1] != rect[3] ||
      rect[2] != rect[4] ||
      rect[7] != rect[5])
    {
      entry->can_be_scissor = FALSE;

      _cogl_clip_stack_entry_set_bounds ((CoglClipStack *) entry,
                                         rect);
    }
  else
    {
      CoglClipStack *base_entry = (CoglClipStack *) entry;
      x_1 = rect[0];
      y_1 = rect[1];
      x_2 = rect[4];
      y_2 = rect[5];

      /* Consider that the modelview matrix may flip the rectangle
       * along the x or y axis... */
#define SWAP(A,B) do { float tmp = B; B = A; A = tmp; } while (0)
      if (x_1 > x_2)
        SWAP (x_1, x_2);
      if (y_1 > y_2)
        SWAP (y_1, y_2);
#undef SWAP

      base_entry->bounds_x0 = COGL_UTIL_NEARBYINT (x_1);
      base_entry->bounds_y0 = COGL_UTIL_NEARBYINT (y_1);
      base_entry->bounds_x1 = COGL_UTIL_NEARBYINT (x_2);
      base_entry->bounds_y1 = COGL_UTIL_NEARBYINT (y_2);
      entry->can_be_scissor = TRUE;
    }

  return (CoglClipStack *) entry;
}