void rut_camera_unproject_coord (RutCamera *camera, const CoglMatrix *modelview, const CoglMatrix *inverse_modelview, float object_coord_z, float *x, float *y) { const CoglMatrix *projection = rut_camera_get_projection (camera); const CoglMatrix *inverse_projection = rut_camera_get_inverse_projection (camera); //float z; float ndc_x, ndc_y, ndc_z, ndc_w; float eye_x, eye_y, eye_z, eye_w; const float *viewport = rut_camera_get_viewport (camera); /* Convert item z into NDC z */ { //float x = 0, y = 0, z = 0, w = 1; float z = 0, w = 1; float tmp_x, tmp_y, tmp_z; const CoglMatrix *m = modelview; tmp_x = m->xw; tmp_y = m->yw; tmp_z = m->zw; m = projection; z = m->zx * tmp_x + m->zy * tmp_y + m->zz * tmp_z + m->zw; w = m->wx * tmp_x + m->wy * tmp_y + m->wz * tmp_z + m->ww; ndc_z = z / w; } /* Undo the Viewport transform, putting us in Normalized Device Coords */ ndc_x = (*x - viewport[0]) * 2.0f / viewport[2] - 1.0f; ndc_y = ((viewport[3] - 1 + viewport[1] - *y) * 2.0f / viewport[3] - 1.0f); /* Undo the Projection, putting us in Eye Coords. */ ndc_w = 1; cogl_matrix_transform_point (inverse_projection, &ndc_x, &ndc_y, &ndc_z, &ndc_w); eye_x = ndc_x / ndc_w; eye_y = ndc_y / ndc_w; eye_z = ndc_z / ndc_w; eye_w = 1; /* Undo the Modelview transform, putting us in Object Coords */ cogl_matrix_transform_point (inverse_modelview, &eye_x, &eye_y, &eye_z, &eye_w); *x = eye_x; *y = eye_y; //*z = eye_z; }
static void project_vertex (const CoglMatrix *modelview_matrix, const CoglMatrix *projection_matrix, float *vertex) { int i; /* Apply the modelview matrix */ cogl_matrix_transform_point (modelview_matrix, &vertex[0], &vertex[1], &vertex[2], &vertex[3]); /* Apply the projection matrix */ cogl_matrix_transform_point (projection_matrix, &vertex[0], &vertex[1], &vertex[2], &vertex[3]); /* Convert from homogenized coordinates */ for (i = 0; i < 4; i++) vertex[i] /= vertex[3]; }
/* Transform a homogeneous vertex position from model space to Cogl * window coordinates (with 0,0 being top left) */ static void transform_point (CoglMatrix *matrix_mv, CoglMatrix *matrix_p, float *viewport, float *x, float *y) { float z = 0; float w = 1; /* Apply the modelview matrix transform */ cogl_matrix_transform_point (matrix_mv, x, y, &z, &w); /* Apply the projection matrix transform */ cogl_matrix_transform_point (matrix_p, x, y, &z, &w); /* Perform perspective division */ *x /= w; *y /= w; /* Apply viewport transform */ *x = VIEWPORT_TRANSFORM_X (*x, viewport[0], viewport[2]); *y = VIEWPORT_TRANSFORM_Y (*y, viewport[1], viewport[3]); }
/* Check if we're painting the MetaWindowGroup "untransformed". This can * differ from the result of actor_is_untransformed(window_group) if we're * inside a clone paint. The integer translation, if any, is returned. */ static gboolean painting_untransformed (MetaWindowGroup *window_group, int *x_origin, int *y_origin) { CoglMatrix modelview, projection, modelview_projection; ClutterVertex vertices[4]; int width, height; float viewport[4]; int i; cogl_get_modelview_matrix (&modelview); cogl_get_projection_matrix (&projection); cogl_matrix_multiply (&modelview_projection, &projection, &modelview); meta_screen_get_size (window_group->screen, &width, &height); vertices[0].x = 0; vertices[0].y = 0; vertices[0].z = 0; vertices[1].x = width; vertices[1].y = 0; vertices[1].z = 0; vertices[2].x = 0; vertices[2].y = height; vertices[2].z = 0; vertices[3].x = width; vertices[3].y = height; vertices[3].z = 0; cogl_get_viewport (viewport); for (i = 0; i < 4; i++) { float w = 1; cogl_matrix_transform_point (&modelview_projection, &vertices[i].x, &vertices[i].y, &vertices[i].z, &w); vertices[i].x = MTX_GL_SCALE_X (vertices[i].x, w, viewport[2], viewport[0]); vertices[i].y = MTX_GL_SCALE_Y (vertices[i].y, w, viewport[3], viewport[1]); } return meta_actor_vertices_are_untransformed (vertices, width, height, x_origin, y_origin); }
void _clutter_paint_volume_transform (ClutterPaintVolume *pv, const CoglMatrix *matrix) { int transform_count; if (pv->is_empty) { gfloat w = 1; /* Just transform the origin */ cogl_matrix_transform_point (matrix, &pv->vertices[0].x, &pv->vertices[0].y, &pv->vertices[0].z, &w); return; } /* All the vertices must be up to date, since after the transform * it wont be trivial to derive the other vertices. */ _clutter_paint_volume_complete (pv); /* Most actors are 2D so we only have to transform the front 4 * vertices of the paint volume... */ if (G_LIKELY (pv->is_2d)) transform_count = 4; else transform_count = 8; cogl_matrix_transform_points (matrix, 3, sizeof (ClutterVertex), pv->vertices, sizeof (ClutterVertex), pv->vertices, transform_count); pv->is_axis_aligned = FALSE; }
void _rut_volume_transform (RutVolume *volume, const CoglMatrix *matrix) { int transform_count; if (volume->is_empty) { float w = 1; /* Just transform the origin */ cogl_matrix_transform_point (matrix, &volume->vertices[0].x, &volume->vertices[0].y, &volume->vertices[0].z, &w); return; } /* All the vertices must be up to date, since after the transform * it wont be trivial to derive the other vertices. */ _rut_volume_complete (volume); /* Most actors are 2D so we only have to transform the front 4 * vertices of the volume... */ if (G_LIKELY (volume->is_2d)) transform_count = 4; else transform_count = 8; cogl_matrix_transform_points (matrix, 3, sizeof (RutVector3), volume->vertices, sizeof (RutVector3), volume->vertices, transform_count); volume->is_axis_aligned = FALSE; }
/** * mash_light_set_direction_uniform: * @light: The #MashLight which is generating the shader * @uniform_location: The location of the uniform * @direction_in: The untransformed direction uniform * * This is a convenience intended to be used within * mash_light_update_uniforms() to help set uniforms. It * should not generally need to be called by an application unless it * is implementing its own lighting algorithms. * * This is intended to help when setting a direction * uniform. @direction_in should be an untransformed array of 3 floats * representing a vector. The vector will be transformed into eye * space according to the inverse transposed matrix of @light so that * it won't change direction for non-uniform scaling transformations. */ void mash_light_set_direction_uniform (MashLight *light, CoglHandle program, int uniform_location, const float *direction_in) { float light_direction[4]; CoglMatrix matrix, inverse_matrix; float magnitude; memcpy (light_direction, direction_in, sizeof (light_direction)); mash_light_get_modelview_matrix (light, &matrix); /* To safely transform the direction when the matrix might not be orthogonal we need the transposed inverse matrix */ cogl_matrix_get_inverse (&matrix, &inverse_matrix); transpose_matrix (&inverse_matrix, &matrix); cogl_matrix_transform_point (&matrix, light_direction + 0, light_direction + 1, light_direction + 2, light_direction + 3); /* Normalize the light direction */ magnitude = sqrtf ((light_direction[0] * light_direction[0]) + (light_direction[1] * light_direction[1]) + (light_direction[2] * light_direction[2])); light_direction[0] /= magnitude; light_direction[1] /= magnitude; light_direction[2] /= magnitude; cogl_program_set_uniform_float (program, uniform_location, 3, 1, light_direction); }
void _clutter_util_fully_transform_vertices (const CoglMatrix *modelview, const CoglMatrix *projection, const int *viewport, const ClutterVertex *vertices_in, ClutterVertex *vertices_out, int n_vertices) { CoglMatrix modelview_projection; int i; /* XXX: we should find a way to cache this per actor */ cogl_matrix_multiply (&modelview_projection, projection, modelview); for (i = 0; i < n_vertices; i++) { const ClutterVertex *vertex_in = &vertices_in[i]; ClutterVertex *vertex_out = &vertices_out[i]; gfloat x, y, z, w; x = vertex_in->x; y = vertex_in->y; z = vertex_in->z; w = 1.0; /* Transform the point using the modelview matrix */ cogl_matrix_transform_point (&modelview_projection, &x, &y, &z, &w); /* Finally translate from OpenGL coords to window coords */ vertex_out->x = MTX_GL_SCALE_X (x, w, viewport[2], viewport[0]); vertex_out->y = MTX_GL_SCALE_Y (y, w, viewport[3], viewport[1]); vertex_out->z = MTX_GL_SCALE_Z (z, w, viewport[2], viewport[0]); } }
static RutShapeModel * shape_model_new (RutContext *ctx, CoglBool shaped, float tex_width, float tex_height) { RutShapeModel *shape_model = g_slice_new (RutShapeModel); RutBuffer *buffer = rut_buffer_new (sizeof (CoglVertexP3) * 6); RutMesh *pick_mesh = rut_mesh_new_from_buffer_p3 (COGL_VERTICES_MODE_TRIANGLES, 6, buffer); CoglVertexP3 *pick_vertices = (CoglVertexP3 *)buffer->data; CoglMatrix matrix; float tex_aspect; float size_x; float size_y; float half_size_x; float half_size_y; float geom_size_x; float geom_size_y; float half_geom_size_x; float half_geom_size_y; rut_object_init (&shape_model->_parent, &rut_shape_model_type); shape_model->ref_count = 1; if (shaped) { /* In this case we are using a shape mask texture which is has a * square size and is padded with transparent pixels to provide * antialiasing. The shape mask is half the size of the texture * itself so we make the geometry twice as large to compensate. */ size_x = MIN (tex_width, tex_height); size_y = size_x; geom_size_x = size_x * 2.0; geom_size_y = geom_size_x; } else { size_x = tex_width; size_y = tex_height; geom_size_x = tex_width; geom_size_y = tex_height; } half_size_x = size_x / 2.0; half_size_y = size_y / 2.0; half_geom_size_x = geom_size_x / 2.0; half_geom_size_y = geom_size_y / 2.0; { int n_vertices; int i; VertexP2T2T2 vertices[] = { { -half_geom_size_x, -half_geom_size_y, 0, 0, 0, 0 }, { -half_geom_size_x, half_geom_size_y, 0, 1, 0, 1 }, { half_geom_size_x, half_geom_size_y, 1, 1, 1, 1 }, { -half_geom_size_x, -half_geom_size_y, 0, 0, 0, 0 }, { half_geom_size_x, half_geom_size_y, 1, 1, 1, 1 }, { half_geom_size_x, -half_geom_size_y, 1, 0, 1, 0 }, }; cogl_matrix_init_identity (&matrix); tex_aspect = (float)tex_width / (float)tex_height; if (shaped) { float s_scale, t_scale; float s0, t0; /* NB: The circle mask texture has a centered circle that is * half the width of the texture itself. We want the primary * texture to be mapped to this center circle. */ s_scale = 2; t_scale = 2; 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; } 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, t_scale, 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); #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 } shape_model->primitive = primitive_new_p2t2t2 (ctx->cogl_context, COGL_VERTICES_MODE_TRIANGLES, n_vertices, vertices); } shape_model->shape_texture = cogl_object_ref (ctx->circle_texture); pick_vertices[0].x = -half_size_x; pick_vertices[0].y = -half_size_y; pick_vertices[1].x = -half_size_x; pick_vertices[1].y = half_size_y; pick_vertices[2].x = half_size_x; pick_vertices[2].y = half_size_y; pick_vertices[3] = pick_vertices[0]; pick_vertices[4] = pick_vertices[2]; pick_vertices[5].x = half_size_x; pick_vertices[5].y = -half_size_y; shape_model->pick_mesh = pick_mesh; return shape_model; }
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; }
CoglPrimitive * rut_camera_create_frustum_primitive (RutCamera *camera) { RutVertex4 vertices[8] = { /* near plane in projection space */ {-1, -1, -1, 1, }, { 1, -1, -1, 1, }, { 1, 1, -1, 1, }, {-1, 1, -1, 1, }, /* far plane in projection space */ {-1, -1, 1, 1, }, { 1, -1, 1, 1, }, { 1, 1, 1, 1, }, {-1, 1, 1, 1, } }; const CoglMatrix *projection_inv; CoglAttributeBuffer *attribute_buffer; CoglAttribute *attributes[1]; CoglPrimitive *primitive; CoglIndices *indices; unsigned char indices_data[24] = { 0,1, 1,2, 2,3, 3,0, 4,5, 5,6, 6,7, 7,4, 0,4, 1,5, 2,6, 3,7 }; int i; projection_inv = rut_camera_get_inverse_projection (camera); for (i = 0; i < 8; i++) { cogl_matrix_transform_point (projection_inv, &vertices[i].x, &vertices[i].y, &vertices[i].z, &vertices[i].w); vertices[i].x /= vertices[i].w; vertices[i].y /= vertices[i].w; vertices[i].z /= vertices[i].w; vertices[i].w /= 1.0f; } attribute_buffer = cogl_attribute_buffer_new (rut_cogl_context, 8 * sizeof (RutVertex4), vertices); attributes[0] = cogl_attribute_new (attribute_buffer, "cogl_position_in", sizeof (RutVertex4), offsetof (RutVertex4, x), 3, COGL_ATTRIBUTE_TYPE_FLOAT); indices = cogl_indices_new (rut_cogl_context, COGL_INDICES_TYPE_UNSIGNED_BYTE, indices_data, G_N_ELEMENTS (indices_data)); primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_LINES, 8, attributes, 1); cogl_primitive_set_indices (primitive, indices, G_N_ELEMENTS(indices_data)); cogl_object_unref (attribute_buffer); cogl_object_unref (attributes[0]); cogl_object_unref (indices); return primitive; }