15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* vim: set ts=8 sw=8 noexpandtab: */ 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// qcms 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (C) 2009 Mozilla Foundation 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (C) 1998-2007 Marti Maria 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Permission is hereby granted, free of charge, to any person obtaining 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a copy of this software and associated documentation files (the "Software"), 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to deal in the Software without restriction, including without limitation 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the rights to use, copy, modify, merge, publish, distribute, sublicense, 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and/or sell copies of the Software, and to permit persons to whom the Software 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is furnished to do so, subject to the following conditions: 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The above copyright notice and this permission notice shall be included in 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// all copies or substantial portions of the Software. 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h> 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "qcmsint.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "matrix.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct vector matrix_eval(struct matrix mat, struct vector v) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vector result; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.v[0] = mat.m[0][0]*v.v[0] + mat.m[0][1]*v.v[1] + mat.m[0][2]*v.v[2]; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.v[1] = mat.m[1][0]*v.v[0] + mat.m[1][1]*v.v[1] + mat.m[1][2]*v.v[2]; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.v[2] = mat.m[2][0]*v.v[0] + mat.m[2][1]*v.v[1] + mat.m[2][2]*v.v[2]; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//XXX: should probably pass by reference and we could 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//probably reuse this computation in matrix_invert 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)float matrix_det(struct matrix mat) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float det; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) det = mat.m[0][0]*mat.m[1][1]*mat.m[2][2] + 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mat.m[0][1]*mat.m[1][2]*mat.m[2][0] + 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mat.m[0][2]*mat.m[1][0]*mat.m[2][1] - 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mat.m[0][0]*mat.m[1][2]*mat.m[2][1] - 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mat.m[0][1]*mat.m[1][0]*mat.m[2][2] - 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mat.m[0][2]*mat.m[1][1]*mat.m[2][0]; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return det; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* from pixman and cairo and Mathematics for Game Programmers */ 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* lcms uses gauss-jordan elimination with partial pivoting which is 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * less efficient and not as numerically stable. See Mathematics for 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Game Programmers. */ 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct matrix matrix_invert(struct matrix mat) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct matrix dest_mat; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i,j; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int a[3] = { 2, 2, 1 }; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int b[3] = { 1, 0, 0 }; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* inv (A) = 1/det (A) * adj (A) */ 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float det = matrix_det(mat); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (det == 0) { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest_mat.invalid = true; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest_mat.invalid = false; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) det = 1/det; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (j = 0; j < 3; j++) { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < 3; i++) { 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double p; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ai = a[i]; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int aj = a[j]; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int bi = b[i]; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int bj = b[j]; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = mat.m[ai][aj] * mat.m[bi][bj] - 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mat.m[ai][bj] * mat.m[bi][aj]; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (((i + j) & 1) != 0) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = -p; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest_mat.m[j][i] = det * p; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return dest_mat; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct matrix matrix_identity(void) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct matrix i; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i.m[0][0] = 1; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i.m[0][1] = 0; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i.m[0][2] = 0; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i.m[1][0] = 0; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i.m[1][1] = 1; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i.m[1][2] = 0; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i.m[2][0] = 0; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i.m[2][1] = 0; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i.m[2][2] = 1; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i.invalid = false; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return i; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct matrix matrix_invalid(void) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct matrix inv = matrix_identity(); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inv.invalid = true; 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return inv; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* from pixman */ 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* MAT3per... */ 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct matrix matrix_multiply(struct matrix a, struct matrix b) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct matrix result; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int dx, dy; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int o; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (dy = 0; dy < 3; dy++) { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (dx = 0; dx < 3; dx++) { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double v = 0; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (o = 0; o < 3; o++) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) v += a.m[dy][o] * b.m[o][dx]; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.m[dy][dx] = v; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.invalid = a.invalid || b.invalid; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 137