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"); }
void rut_transform_rotate (RutTransform *transform, float angle, float x, float y, float z) { cogl_matrix_rotate (&transform->matrix, angle, x, y, z); }
static void paint_matrix_pipeline (CoglPipeline *pipeline) { CoglMatrix matrices[4]; float matrix_floats[16 * 4]; int uniform_location; int i; for (i = 0; i < 4; i++) cogl_matrix_init_identity (matrices + i); /* Use the first matrix to make the color red */ cogl_matrix_translate (matrices + 0, 1.0f, 0.0f, 0.0f); /* Rotate the vertex so that it ends up green */ cogl_matrix_rotate (matrices + 1, 90.0f, 0.0f, 0.0f, 1.0f); /* Scale the vertex so it ends up halved */ cogl_matrix_scale (matrices + 2, 0.5f, 0.5f, 0.5f); /* Add a blue component in the final matrix. The final matrix is uploaded as transposed so we need to transpose first to cancel that out */ cogl_matrix_translate (matrices + 3, 0.0f, 0.0f, 1.0f); cogl_matrix_transpose (matrices + 3); for (i = 0; i < 4; i++) memcpy (matrix_floats + i * 16, cogl_matrix_get_array (matrices + i), sizeof (float) * 16); /* Set the first three matrices as transposed */ uniform_location = cogl_pipeline_get_uniform_location (pipeline, "matrix_array"); cogl_pipeline_set_uniform_matrix (pipeline, uniform_location, 4, /* dimensions */ 3, /* count */ FALSE, /* not transposed */ matrix_floats); /* Set the last matrix as untransposed */ uniform_location = cogl_pipeline_get_uniform_location (pipeline, "matrix_array[3]"); cogl_pipeline_set_uniform_matrix (pipeline, uniform_location, 4, /* dimensions */ 1, /* count */ TRUE, /* transposed */ matrix_floats + 16 * 3); paint_pipeline (pipeline, 12); }
void _cogl_matrix_stack_rotate (CoglMatrixStack *stack, float angle, float x, float y, float z) { CoglMatrixState *state; state = _cogl_matrix_stack_top_mutable (stack, TRUE); cogl_matrix_rotate (&state->matrix, angle, x, y, z); state->is_identity = FALSE; stack->age++; }
void mai_node_draw_recursive (MaiNode *self) { CoglMatrix initial_mtx; cogl_matrix_init_identity (&initial_mtx); cogl_set_modelview_matrix (&initial_mtx); cogl_set_source_color4ub ('\x1', '\x1', '\xFF', 255); cogl_set_source_texture (g_testtex); cogl_ortho (0, 64, 0, 64, -1, 1); cogl_matrix_translate (&initial_mtx, 20.0f, 20.0f, 0.0f); cogl_matrix_scale (&initial_mtx, 5.0f, 5.0f, 1.0f); cogl_matrix_rotate(&initial_mtx, -90.0f, 1.0f, 0.0f, 0.0f); _mai_node_draw_recursive (self, &initial_mtx); cogl_flush (); }
G_MODULE_EXPORT int test_cogl_multitexture_main (int argc, char *argv[]) { GError *error = NULL; ClutterActor *stage; ClutterColor stage_color = { 0x61, 0x56, 0x56, 0xff }; TestMultiLayerMaterialState *state = g_new0 (TestMultiLayerMaterialState, 1); gfloat stage_w, stage_h; gchar **files; gfloat tex_coords[] = { /* tx1 ty1 tx2 ty2 */ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 }; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); clutter_actor_get_size (stage, &stage_w, &stage_h); clutter_stage_set_title (CLUTTER_STAGE (stage), "Cogl: Multi-texturing"); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); /* We create a non-descript actor that we know doesn't have a * default paint handler, so that we can easily control * painting in a paint signal handler, without having to * sub-class anything etc. */ state->group = clutter_group_new (); clutter_actor_set_position (state->group, stage_w / 2, stage_h / 2); g_signal_connect (state->group, "paint", G_CALLBACK(material_rectangle_paint), state); files = g_new (gchar*, 4); files[0] = g_build_filename (TESTS_DATADIR, "redhand_alpha.png", NULL); files[1] = g_build_filename (TESTS_DATADIR, "redhand.png", NULL); files[2] = g_build_filename (TESTS_DATADIR, "light0.png", NULL); files[3] = NULL; state->alpha_tex = cogl_texture_new_from_file (files[0], COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_ANY, &error); if (!state->alpha_tex) g_critical ("Failed to load redhand_alpha.png: %s", error->message); state->redhand_tex = cogl_texture_new_from_file (files[1], COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_ANY, &error); if (!state->redhand_tex) g_critical ("Failed to load redhand.png: %s", error->message); state->light_tex0 = cogl_texture_new_from_file (files[2], COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_ANY, &error); if (!state->light_tex0) g_critical ("Failed to load light0.png: %s", error->message); state->light_tex1 = cogl_texture_new_from_file (files[2], COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_ANY, &error); if (!state->light_tex1) g_critical ("Failed to load light0.png: %s", error->message); g_strfreev (files); state->material0 = cogl_material_new (); cogl_material_set_layer (state->material0, 0, state->alpha_tex); cogl_material_set_layer (state->material0, 1, state->redhand_tex); cogl_material_set_layer (state->material0, 2, state->light_tex0); state->material1 = cogl_material_new (); cogl_material_set_layer (state->material1, 0, state->alpha_tex); cogl_material_set_layer (state->material1, 1, state->redhand_tex); cogl_material_set_layer (state->material1, 2, state->light_tex1); state->tex_coords = tex_coords; cogl_matrix_init_identity (&state->tex_matrix0); cogl_matrix_init_identity (&state->tex_matrix1); cogl_matrix_init_identity (&state->rot_matrix0); cogl_matrix_init_identity (&state->rot_matrix1); cogl_matrix_translate (&state->rot_matrix0, 0.5, 0.5, 0); cogl_matrix_rotate (&state->rot_matrix0, 10.0, 0, 0, 1.0); cogl_matrix_translate (&state->rot_matrix0, -0.5, -0.5, 0); cogl_matrix_translate (&state->rot_matrix1, 0.5, 0.5, 0); cogl_matrix_rotate (&state->rot_matrix1, -10.0, 0, 0, 1.0); cogl_matrix_translate (&state->rot_matrix1, -0.5, -0.5, 0); clutter_actor_set_anchor_point (state->group, 86, 125); clutter_container_add_actor (CLUTTER_CONTAINER(stage), state->group); state->timeline = clutter_timeline_new (2812); g_signal_connect (state->timeline, "new-frame", G_CALLBACK (frame_cb), state); clutter_actor_animate_with_timeline (state->group, CLUTTER_LINEAR, state->timeline, "rotation-angle-y", 30.0, "signal-after::completed", animation_completed_cb, state, NULL); /* start the timeline and thus the animations */ clutter_timeline_start (state->timeline); clutter_actor_show_all (stage); clutter_main(); cogl_handle_unref (state->material1); cogl_handle_unref (state->material0); cogl_handle_unref (state->alpha_tex); cogl_handle_unref (state->redhand_tex); cogl_handle_unref (state->light_tex0); cogl_handle_unref (state->light_tex1); g_free (state); return 0; }
/* 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; }
static RutDiamondSlice * diamond_slice_new (RutContext *ctx, float size, int tex_width, int tex_height) { RutDiamondSlice *diamond_slice = g_slice_new (RutDiamondSlice); float width = size; float height = size; #define DIAMOND_SLICE_CORNER_RADIUS 20 CoglMatrix matrix; float tex_aspect; rut_object_init (&diamond_slice->_parent, &rut_diamond_slice_type); diamond_slice->ref_count = 1; diamond_slice->size = size; { /* x0,y0,x1,y1 and s0,t0,s1,t1 define the postion and texture * coordinates for the center rectangle... */ float x0 = DIAMOND_SLICE_CORNER_RADIUS; float y0 = DIAMOND_SLICE_CORNER_RADIUS; float x1 = width - DIAMOND_SLICE_CORNER_RADIUS; float y1 = height - DIAMOND_SLICE_CORNER_RADIUS; /* The center region of the nine-slice can simply map to the * degenerate center of the circle */ float s0 = 0.5; float t0 = 0.5; float s1 = 0.5; float t1 = 0.5; int n_vertices; int i; /* * 0,0 x0,0 x1,0 width,0 * 0,0 s0,0 s1,0 1,0 * 0 1 2 3 * * 0,y0 x0,y0 x1,y0 width,y0 * 0,t0 s0,t0 s1,t0 1,t0 * 4 5 6 7 * * 0,y1 x0,y1 x1,y1 width,y1 * 0,t1 s0,t1 s1,t1 1,t1 * 8 9 10 11 * * 0,height x0,height x1,height width,height * 0,1 s0,1 s1,1 1,1 * 12 13 14 15 */ VertexP2T2T2 vertices[] = { { 0, 0, 0, 0, 0, 0 }, { x0, 0, s0, 0, x0, 0}, { x1, 0, s1, 0, x1, 0}, { width, 0, 1, 0, width, 0}, { 0, y0, 0, t0, 0, y0}, { x0, y0, s0, t0, x0, y0}, { x1, y0, s1, t0, x1, y0}, { width, y0, 1, t0, width, y0}, { 0, y1, 0, t1, 0, y1}, { x0, y1, s0, t1, x0, y1}, { x1, y1, s1, t1, x1, y1}, { width, y1, 1, t1, width, y1}, { 0, height, 0, 1, 0, height}, { x0, height, s0, 1, x0, height}, { x1, height, s1, 1, x1, height}, { width, height, 1, 1, width, height}, }; cogl_matrix_init_identity (&diamond_slice->rotate_matrix); cogl_matrix_rotate (&diamond_slice->rotate_matrix, 45, 0, 0, 1); cogl_matrix_translate (&diamond_slice->rotate_matrix, - width / 2.0, - height / 2.0, 0); n_vertices = sizeof (vertices) / sizeof (VertexP2T2T2); for (i = 0; i < n_vertices; i++) { float z = 0, w = 1; cogl_matrix_transform_point (&diamond_slice->rotate_matrix, &vertices[i].x, &vertices[i].y, &z, &w); #ifdef MESA_CONST_ATTRIB_BUG_WORKAROUND vertices[i].Nx = 0; vertices[i].Ny = 0; vertices[i].Nz = 1; vertices[i].Tx = 1; vertices[i].Ty = 0; vertices[i].Tz = 0; #endif } cogl_matrix_init_identity (&matrix); { float s_scale = 1.0, t_scale = 1.0; float s0, t0; float diagonal_size_scale = 1.0 / (sinf (G_PI_4) * 2.0); tex_aspect = (float)tex_width / (float)tex_height; if (tex_aspect < 1) /* taller than it is wide */ t_scale *= tex_aspect; else /* wider than it is tall */ { float inverse_aspect = 1.0f / tex_aspect; s_scale *= inverse_aspect; } s_scale *= diagonal_size_scale; t_scale *= diagonal_size_scale; s0 = 0.5 - (s_scale / 2.0); t0 = 0.5 - (t_scale / 2.0); cogl_matrix_translate (&matrix, s0, t0, 0); cogl_matrix_scale (&matrix, s_scale / width, t_scale / height, 1); cogl_matrix_translate (&matrix, width / 2.0, height / 2.0, 1); cogl_matrix_rotate (&matrix, 45, 0, 0, 1); cogl_matrix_translate (&matrix, -width / 2.0, -height / 2.0, 1); } n_vertices = sizeof (vertices) / sizeof (VertexP2T2T2); for (i = 0; i < n_vertices; i++) { float z = 0, w = 1; cogl_matrix_transform_point (&matrix, &vertices[i].s1, &vertices[i].t1, &z, &w); } diamond_slice->primitive = primitive_new_p2t2t2 (ctx->cogl_context, COGL_VERTICES_MODE_TRIANGLES, n_vertices, vertices); /* The vertices uploaded only map to the key intersection points of the * 9-slice grid which isn't a topology that GPUs can handle directly so * this specifies an array of indices that allow the GPU to interpret the * vertices as a list of triangles... */ cogl_primitive_set_indices (diamond_slice->primitive, ctx->nine_slice_indices, sizeof (_rut_nine_slice_indices_data) / sizeof (_rut_nine_slice_indices_data[0])); } return diamond_slice; }
static gboolean clutter_matrix_progress (const GValue *a, const GValue *b, gdouble progress, GValue *retval) { const ClutterMatrix *matrix1 = g_value_get_boxed (a); const ClutterMatrix *matrix2 = g_value_get_boxed (b); ClutterVertex scale1 = CLUTTER_VERTEX_INIT (1.f, 1.f, 1.f); float shear1[3] = { 0.f, 0.f, 0.f }; ClutterVertex rotate1 = CLUTTER_VERTEX_INIT_ZERO; ClutterVertex translate1 = CLUTTER_VERTEX_INIT_ZERO; ClutterVertex4 perspective1 = { 0.f, 0.f, 0.f, 0.f }; ClutterVertex scale2 = CLUTTER_VERTEX_INIT (1.f, 1.f, 1.f); float shear2[3] = { 0.f, 0.f, 0.f }; ClutterVertex rotate2 = CLUTTER_VERTEX_INIT_ZERO; ClutterVertex translate2 = CLUTTER_VERTEX_INIT_ZERO; ClutterVertex4 perspective2 = { 0.f, 0.f, 0.f, 0.f }; ClutterVertex scale_res = CLUTTER_VERTEX_INIT (1.f, 1.f, 1.f); float shear_res = 0.f; ClutterVertex rotate_res = CLUTTER_VERTEX_INIT_ZERO; ClutterVertex translate_res = CLUTTER_VERTEX_INIT_ZERO; ClutterVertex4 perspective_res = { 0.f, 0.f, 0.f, 0.f }; ClutterMatrix res; clutter_matrix_init_identity (&res); _clutter_util_matrix_decompose (matrix1, &scale1, shear1, &rotate1, &translate1, &perspective1); _clutter_util_matrix_decompose (matrix2, &scale2, shear2, &rotate2, &translate2, &perspective2); /* perspective */ _clutter_util_vertex4_interpolate (&perspective1, &perspective2, progress, &perspective_res); res.wx = perspective_res.x; res.wy = perspective_res.y; res.wz = perspective_res.z; res.ww = perspective_res.w; /* translation */ clutter_vertex_interpolate (&translate1, &translate2, progress, &translate_res); cogl_matrix_translate (&res, translate_res.x, translate_res.y, translate_res.z); /* rotation */ clutter_vertex_interpolate (&rotate1, &rotate2, progress, &rotate_res); cogl_matrix_rotate (&res, rotate_res.x, 1.0f, 0.0f, 0.0f); cogl_matrix_rotate (&res, rotate_res.y, 0.0f, 1.0f, 0.0f); cogl_matrix_rotate (&res, rotate_res.z, 0.0f, 0.0f, 1.0f); /* skew */ shear_res = shear1[2] + (shear2[2] - shear1[2]) * progress; /* YZ */ if (shear_res != 0.f) _clutter_util_matrix_skew_yz (&res, shear_res); shear_res = shear1[1] + (shear2[1] - shear1[1]) * progress; /* XZ */ if (shear_res != 0.f) _clutter_util_matrix_skew_xz (&res, shear_res); shear_res = shear1[0] + (shear2[0] - shear1[0]) * progress; /* XY */ if (shear_res != 0.f) _clutter_util_matrix_skew_xy (&res, shear_res); /* scale */ clutter_vertex_interpolate (&scale1, &scale2, progress, &scale_res); cogl_matrix_scale (&res, scale_res.x, scale_res.y, scale_res.z); g_value_set_boxed (retval, &res); return TRUE; }