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); }
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; }
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; }
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); }
/* 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; }
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; }
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; }