void test_euler_quaternion (void) { CoglEuler euler; CoglQuaternion quaternion; CoglMatrix matrix_a, matrix_b; /* Try doing the rotation with three separate rotations */ cogl_matrix_init_identity (&matrix_a); cogl_matrix_rotate (&matrix_a, -30.0f, 0.0f, 1.0f, 0.0f); cogl_matrix_rotate (&matrix_a, 40.0f, 1.0f, 0.0f, 0.0f); cogl_matrix_rotate (&matrix_a, 50.0f, 0.0f, 0.0f, 1.0f); /* And try the same rotation with a euler */ cogl_euler_init (&euler, -30, 40, 50); cogl_matrix_init_from_euler (&matrix_b, &euler); /* Verify that the matrices are approximately the same */ COMPARE_MATRICES (&matrix_a, &matrix_b); /* Try converting the euler to a matrix via a quaternion */ cogl_quaternion_init_from_euler (&quaternion, &euler); memset (&matrix_b, 0, sizeof (matrix_b)); cogl_matrix_init_from_quaternion (&matrix_b, &quaternion); COMPARE_MATRICES (&matrix_a, &matrix_b); /* Try applying the rotation from a euler to a framebuffer */ cogl_framebuffer_identity_matrix (test_fb); cogl_framebuffer_rotate_euler (test_fb, &euler); memset (&matrix_b, 0, sizeof (matrix_b)); cogl_framebuffer_get_modelview_matrix (test_fb, &matrix_b); COMPARE_MATRICES (&matrix_a, &matrix_b); /* And again with a quaternion */ cogl_framebuffer_identity_matrix (test_fb); cogl_framebuffer_rotate_quaternion (test_fb, &quaternion); memset (&matrix_b, 0, sizeof (matrix_b)); cogl_framebuffer_get_modelview_matrix (test_fb, &matrix_b); COMPARE_MATRICES (&matrix_a, &matrix_b); /* FIXME: This needs a lot more tests! */ if (cogl_test_verbose ()) g_print ("OK\n"); }
/* In addition to writing the stack matrix into the give @matrix * argument this function *may* sometimes also return a pointer * to a matrix too so if we are querying the inverse matrix we * should query from the return matrix so that the result can * be cached within the stack. */ CoglMatrix * cogl_matrix_entry_get (CoglMatrixEntry *entry, CoglMatrix *matrix) { int depth; CoglMatrixEntry *current; CoglMatrixEntry **children; int i; for (depth = 0, current = entry; current; current = current->parent, depth++) { switch (current->op) { case COGL_MATRIX_OP_LOAD_IDENTITY: cogl_matrix_init_identity (matrix); goto initialized; case COGL_MATRIX_OP_LOAD: { CoglMatrixEntryLoad *load = (CoglMatrixEntryLoad *)current; *matrix = *load->matrix; goto initialized; } case COGL_MATRIX_OP_SAVE: { CoglMatrixEntrySave *save = (CoglMatrixEntrySave *)current; if (!save->cache_valid) { CoglMagazine *matrices_magazine = cogl_matrix_stack_matrices_magazine; save->cache = _cogl_magazine_chunk_alloc (matrices_magazine); cogl_matrix_entry_get (current->parent, save->cache); save->cache_valid = TRUE; } *matrix = *save->cache; goto initialized; } default: continue; } } initialized: if (depth == 0) { switch (entry->op) { case COGL_MATRIX_OP_LOAD_IDENTITY: case COGL_MATRIX_OP_TRANSLATE: case COGL_MATRIX_OP_ROTATE: case COGL_MATRIX_OP_ROTATE_QUATERNION: case COGL_MATRIX_OP_ROTATE_EULER: case COGL_MATRIX_OP_SCALE: case COGL_MATRIX_OP_MULTIPLY: return NULL; case COGL_MATRIX_OP_LOAD: { CoglMatrixEntryLoad *load = (CoglMatrixEntryLoad *)entry; return load->matrix; } case COGL_MATRIX_OP_SAVE: { CoglMatrixEntrySave *save = (CoglMatrixEntrySave *)entry; return save->cache; } } g_warn_if_reached (); return NULL; } #ifdef COGL_ENABLE_DEBUG if (!current) { g_warning ("Inconsistent matrix stack"); return NULL; } entry->composite_gets++; #endif children = g_alloca (sizeof (CoglMatrixEntry) * depth); /* We need walk the list of entries from the init/load/save entry * back towards the leaf node but the nodes don't link to their * children so we need to re-walk them here to add to a separate * array. */ for (i = depth - 1, current = entry; i >= 0 && current; i--, current = current->parent) { children[i] = current; } #ifdef COGL_ENABLE_DEBUG if (COGL_DEBUG_ENABLED (COGL_DEBUG_PERFORMANCE) && entry->composite_gets >= 2) { COGL_NOTE (PERFORMANCE, "Re-composing a matrix stack entry multiple times"); } #endif for (i = 0; i < depth; i++) { switch (children[i]->op) { case COGL_MATRIX_OP_TRANSLATE: { CoglMatrixEntryTranslate *translate = (CoglMatrixEntryTranslate *)children[i]; cogl_matrix_translate (matrix, translate->x, translate->y, translate->z); continue; } case COGL_MATRIX_OP_ROTATE: { CoglMatrixEntryRotate *rotate= (CoglMatrixEntryRotate *)children[i]; cogl_matrix_rotate (matrix, rotate->angle, rotate->x, rotate->y, rotate->z); continue; } case COGL_MATRIX_OP_ROTATE_EULER: { CoglMatrixEntryRotateEuler *rotate = (CoglMatrixEntryRotateEuler *)children[i]; CoglEuler euler; cogl_euler_init (&euler, rotate->heading, rotate->pitch, rotate->roll); cogl_matrix_rotate_euler (matrix, &euler); continue; } case COGL_MATRIX_OP_ROTATE_QUATERNION: { CoglMatrixEntryRotateQuaternion *rotate = (CoglMatrixEntryRotateQuaternion *)children[i]; CoglQuaternion quaternion; cogl_quaternion_init_from_array (&quaternion, rotate->values); cogl_matrix_rotate_quaternion (matrix, &quaternion); continue; } case COGL_MATRIX_OP_SCALE: { CoglMatrixEntryScale *scale = (CoglMatrixEntryScale *)children[i]; cogl_matrix_scale (matrix, scale->x, scale->y, scale->z); continue; } case COGL_MATRIX_OP_MULTIPLY: { CoglMatrixEntryMultiply *multiply = (CoglMatrixEntryMultiply *)children[i]; cogl_matrix_multiply (matrix, matrix, multiply->matrix); continue; } case COGL_MATRIX_OP_LOAD_IDENTITY: case COGL_MATRIX_OP_LOAD: case COGL_MATRIX_OP_SAVE: g_warn_if_reached (); continue; } } return NULL; }