@@ -596,101 +596,229 @@ Projection Projection::inverse() const {
596596}
597597
598598void Projection::invert () {
599- int i, j, k;
600- int pvt_i[4 ], pvt_j[4 ]; /* Locations of pivot matrix */
601- real_t pvt_val; /* Value of current pivot element */
602- real_t hold; /* Temporary storage */
603- real_t determinant = 1 .0f ;
604- for (k = 0 ; k < 4 ; k++) {
605- /* * Locate k'th pivot element **/
606- pvt_val = columns[k][k]; /* * Initialize for search **/
607- pvt_i[k] = k;
608- pvt_j[k] = k;
609- for (i = k; i < 4 ; i++) {
610- for (j = k; j < 4 ; j++) {
611- if (Math::abs (columns[i][j]) > Math::abs (pvt_val)) {
612- pvt_i[k] = i;
613- pvt_j[k] = j;
614- pvt_val = columns[i][j];
615- }
616- }
617- }
618-
619- /* * Product of pivots, gives determinant when finished **/
620- determinant *= pvt_val;
621- if (Math::is_zero_approx (determinant)) {
622- return ; /* * Matrix is singular (zero determinant). **/
623- }
624-
625- /* * "Interchange" rows (with sign change stuff) **/
626- i = pvt_i[k];
627- if (i != k) { /* * If rows are different **/
628- for (j = 0 ; j < 4 ; j++) {
629- hold = -columns[k][j];
630- columns[k][j] = columns[i][j];
631- columns[i][j] = hold;
632- }
633- }
634-
635- /* * "Interchange" columns **/
636- j = pvt_j[k];
637- if (j != k) { /* * If columns are different **/
638- for (i = 0 ; i < 4 ; i++) {
639- hold = -columns[i][k];
640- columns[i][k] = columns[i][j];
641- columns[i][j] = hold;
642- }
643- }
644-
645- /* * Divide column by minus pivot value **/
646- for (i = 0 ; i < 4 ; i++) {
647- if (i != k) {
648- columns[i][k] /= (-pvt_val);
649- }
650- }
651-
652- /* * Reduce the matrix **/
653- for (i = 0 ; i < 4 ; i++) {
654- hold = columns[i][k];
655- for (j = 0 ; j < 4 ; j++) {
656- if (i != k && j != k) {
657- columns[i][j] += hold * columns[k][j];
658- }
659- }
660- }
661-
662- /* * Divide row by pivot **/
663- for (j = 0 ; j < 4 ; j++) {
664- if (j != k) {
665- columns[k][j] /= pvt_val;
666- }
667- }
668-
669- /* * Replace pivot by reciprocal (at last we can touch it). **/
670- columns[k][k] = 1.0 / pvt_val;
599+ // Adapted from Mesa's `src/util/u_math.c` `util_invert_mat4x4`.
600+ // MIT licensed. Copyright 2008 VMware, Inc. Authored by Jacques Leroy.
601+ Projection temp;
602+ real_t *out = (real_t *)temp.columns ;
603+ real_t *m = (real_t *)columns;
604+
605+ real_t wtmp[4 ][8 ];
606+ real_t m0, m1, m2, m3, s;
607+ real_t *r0, *r1, *r2, *r3;
608+
609+ #define MAT (m, r, c ) (m)[(c) * 4 + (r)]
610+
611+ r0 = wtmp[0 ];
612+ r1 = wtmp[1 ];
613+ r2 = wtmp[2 ];
614+ r3 = wtmp[3 ];
615+
616+ r0[0 ] = MAT (m, 0 , 0 );
617+ r0[1 ] = MAT (m, 0 , 1 );
618+ r0[2 ] = MAT (m, 0 , 2 );
619+ r0[3 ] = MAT (m, 0 , 3 );
620+ r0[4 ] = 1.0 ;
621+ r0[5 ] = 0.0 ;
622+ r0[6 ] = 0.0 ;
623+ r0[7 ] = 0.0 ;
624+
625+ r1[0 ] = MAT (m, 1 , 0 );
626+ r1[1 ] = MAT (m, 1 , 1 );
627+ r1[2 ] = MAT (m, 1 , 2 );
628+ r1[3 ] = MAT (m, 1 , 3 );
629+ r1[5 ] = 1.0 ;
630+ r1[4 ] = 0.0 ;
631+ r1[6 ] = 0.0 ;
632+ r1[7 ] = 0.0 ;
633+
634+ r2[0 ] = MAT (m, 2 , 0 );
635+ r2[1 ] = MAT (m, 2 , 1 );
636+ r2[2 ] = MAT (m, 2 , 2 );
637+ r2[3 ] = MAT (m, 2 , 3 );
638+ r2[6 ] = 1.0 ;
639+ r2[4 ] = 0.0 ;
640+ r2[5 ] = 0.0 ;
641+ r2[7 ] = 0.0 ;
642+
643+ r3[0 ] = MAT (m, 3 , 0 );
644+ r3[1 ] = MAT (m, 3 , 1 );
645+ r3[2 ] = MAT (m, 3 , 2 );
646+ r3[3 ] = MAT (m, 3 , 3 );
647+
648+ r3[7 ] = 1.0 ;
649+ r3[4 ] = 0.0 ;
650+ r3[5 ] = 0.0 ;
651+ r3[6 ] = 0.0 ;
652+
653+ /* choose pivot - or die */
654+ if (Math::abs (r3[0 ]) > Math::abs (r2[0 ])) {
655+ SWAP (r3, r2);
656+ }
657+ if (Math::abs (r2[0 ]) > Math::abs (r1[0 ])) {
658+ SWAP (r2, r1);
659+ }
660+ if (Math::abs (r1[0 ]) > Math::abs (r0[0 ])) {
661+ SWAP (r1, r0);
662+ }
663+ ERR_FAIL_COND (0.0 == r0[0 ]);
664+
665+ /* eliminate first variable */
666+ m1 = r1[0 ] / r0[0 ];
667+ m2 = r2[0 ] / r0[0 ];
668+ m3 = r3[0 ] / r0[0 ];
669+ s = r0[1 ];
670+ r1[1 ] -= m1 * s;
671+ r2[1 ] -= m2 * s;
672+ r3[1 ] -= m3 * s;
673+ s = r0[2 ];
674+ r1[2 ] -= m1 * s;
675+ r2[2 ] -= m2 * s;
676+ r3[2 ] -= m3 * s;
677+ s = r0[3 ];
678+ r1[3 ] -= m1 * s;
679+ r2[3 ] -= m2 * s;
680+ r3[3 ] -= m3 * s;
681+ s = r0[4 ];
682+ if (s != 0.0 ) {
683+ r1[4 ] -= m1 * s;
684+ r2[4 ] -= m2 * s;
685+ r3[4 ] -= m3 * s;
686+ }
687+ s = r0[5 ];
688+ if (s != 0.0 ) {
689+ r1[5 ] -= m1 * s;
690+ r2[5 ] -= m2 * s;
691+ r3[5 ] -= m3 * s;
692+ }
693+ s = r0[6 ];
694+ if (s != 0.0 ) {
695+ r1[6 ] -= m1 * s;
696+ r2[6 ] -= m2 * s;
697+ r3[6 ] -= m3 * s;
698+ }
699+ s = r0[7 ];
700+ if (s != 0.0 ) {
701+ r1[7 ] -= m1 * s;
702+ r2[7 ] -= m2 * s;
703+ r3[7 ] -= m3 * s;
671704 }
672705
673- /* That was most of the work, one final pass of row/column interchange */
674- /* to finish */
675- for (k = 4 - 2 ; k >= 0 ; k--) { /* Don't need to work with 1 by 1 corner*/
676- i = pvt_j[k]; /* Rows to swap correspond to pivot COLUMN */
677- if (i != k) { /* If rows are different */
678- for (j = 0 ; j < 4 ; j++) {
679- hold = columns[k][j];
680- columns[k][j] = -columns[i][j];
681- columns[i][j] = hold;
682- }
683- }
706+ /* choose pivot - or die */
707+ if (Math::abs (r3[1 ]) > Math::abs (r2[1 ])) {
708+ SWAP (r3, r2);
709+ }
710+ if (Math::abs (r2[1 ]) > Math::abs (r1[1 ])) {
711+ SWAP (r2, r1);
712+ }
713+ ERR_FAIL_COND (0.0 == r1[1 ]);
714+
715+ /* eliminate second variable */
716+ m2 = r2[1 ] / r1[1 ];
717+ m3 = r3[1 ] / r1[1 ];
718+ r2[2 ] -= m2 * r1[2 ];
719+ r3[2 ] -= m3 * r1[2 ];
720+ r2[3 ] -= m2 * r1[3 ];
721+ r3[3 ] -= m3 * r1[3 ];
722+ s = r1[4 ];
723+ if (0.0 != s) {
724+ r2[4 ] -= m2 * s;
725+ r3[4 ] -= m3 * s;
726+ }
727+ s = r1[5 ];
728+ if (0.0 != s) {
729+ r2[5 ] -= m2 * s;
730+ r3[5 ] -= m3 * s;
731+ }
732+ s = r1[6 ];
733+ if (0.0 != s) {
734+ r2[6 ] -= m2 * s;
735+ r3[6 ] -= m3 * s;
736+ }
737+ s = r1[7 ];
738+ if (0.0 != s) {
739+ r2[7 ] -= m2 * s;
740+ r3[7 ] -= m3 * s;
741+ }
684742
685- j = pvt_i[k]; /* Columns to swap correspond to pivot ROW */
686- if (j != k) { /* If columns are different */
687- for (i = 0 ; i < 4 ; i++) {
688- hold = columns[i][k];
689- columns[i][k] = -columns[i][j];
690- columns[i][j] = hold;
691- }
692- }
743+ /* choose pivot - or die */
744+ if (Math::abs (r3[2 ]) > Math::abs (r2[2 ])) {
745+ SWAP (r3, r2);
693746 }
747+ ERR_FAIL_COND (0.0 == r2[2 ]);
748+
749+ /* eliminate third variable */
750+ m3 = r3[2 ] / r2[2 ];
751+ r3[3 ] -= m3 * r2[3 ];
752+ r3[4 ] -= m3 * r2[4 ];
753+ r3[5 ] -= m3 * r2[5 ];
754+ r3[6 ] -= m3 * r2[6 ];
755+ r3[7 ] -= m3 * r2[7 ];
756+
757+ /* last check */
758+ ERR_FAIL_COND (0.0 == r3[3 ]);
759+
760+ s = 1.0 / r3[3 ]; /* now back substitute row 3 */
761+ r3[4 ] *= s;
762+ r3[5 ] *= s;
763+ r3[6 ] *= s;
764+ r3[7 ] *= s;
765+
766+ m2 = r2[3 ]; /* now back substitute row 2 */
767+ s = 1.0 / r2[2 ];
768+ r2[4 ] = s * (r2[4 ] - r3[4 ] * m2);
769+ r2[5 ] = s * (r2[5 ] - r3[5 ] * m2);
770+ r2[6 ] = s * (r2[6 ] - r3[6 ] * m2);
771+ r2[7 ] = s * (r2[7 ] - r3[7 ] * m2);
772+ m1 = r1[3 ];
773+ r1[4 ] -= r3[4 ] * m1;
774+ r1[5 ] -= r3[5 ] * m1;
775+ r1[6 ] -= r3[6 ] * m1;
776+ r1[7 ] -= r3[7 ] * m1;
777+ m0 = r0[3 ];
778+ r0[4 ] -= r3[4 ] * m0;
779+ r0[5 ] -= r3[5 ] * m0;
780+ r0[6 ] -= r3[6 ] * m0;
781+ r0[7 ] -= r3[7 ] * m0;
782+
783+ m1 = r1[2 ]; /* now back substitute row 1 */
784+ s = 1.0 / r1[1 ];
785+ r1[4 ] = s * (r1[4 ] - r2[4 ] * m1);
786+ r1[5 ] = s * (r1[5 ] - r2[5 ] * m1),
787+ r1[6 ] = s * (r1[6 ] - r2[6 ] * m1);
788+ r1[7 ] = s * (r1[7 ] - r2[7 ] * m1);
789+ m0 = r0[2 ];
790+ r0[4 ] -= r2[4 ] * m0;
791+ r0[5 ] -= r2[5 ] * m0;
792+ r0[6 ] -= r2[6 ] * m0;
793+ r0[7 ] -= r2[7 ] * m0;
794+
795+ m0 = r0[1 ]; /* now back substitute row 0 */
796+ s = 1.0 / r0[0 ];
797+ r0[4 ] = s * (r0[4 ] - r1[4 ] * m0);
798+ r0[5 ] = s * (r0[5 ] - r1[5 ] * m0),
799+ r0[6 ] = s * (r0[6 ] - r1[6 ] * m0);
800+ r0[7 ] = s * (r0[7 ] - r1[7 ] * m0);
801+
802+ MAT (out, 0 , 0 ) = r0[4 ];
803+ MAT (out, 0 , 1 ) = r0[5 ];
804+ MAT (out, 0 , 2 ) = r0[6 ];
805+ MAT (out, 0 , 3 ) = r0[7 ];
806+ MAT (out, 1 , 0 ) = r1[4 ];
807+ MAT (out, 1 , 1 ) = r1[5 ];
808+ MAT (out, 1 , 2 ) = r1[6 ];
809+ MAT (out, 1 , 3 ) = r1[7 ];
810+ MAT (out, 2 , 0 ) = r2[4 ];
811+ MAT (out, 2 , 1 ) = r2[5 ];
812+ MAT (out, 2 , 2 ) = r2[6 ];
813+ MAT (out, 2 , 3 ) = r2[7 ];
814+ MAT (out, 3 , 0 ) = r3[4 ];
815+ MAT (out, 3 , 1 ) = r3[5 ];
816+ MAT (out, 3 , 2 ) = r3[6 ];
817+ MAT (out, 3 , 3 ) = r3[7 ];
818+
819+ #undef MAT
820+
821+ *this = temp;
694822}
695823
696824void Projection::flip_y () {
0 commit comments