Index: src/OFMatrix4x4.h ================================================================== --- src/OFMatrix4x4.h +++ src/OFMatrix4x4.h @@ -56,42 +56,37 @@ * @param values An array of 16 floats in column-major format * @return An initialized OFMatrix4x4 */ - (instancetype)initWithValues: (const float [_Nonnull 16])values; -/** - * @brief Transposes the matrix. - */ -- (void)transpose; - /** * @brief Mulitplies the receiver with the specified matrix on the left side * and the receiver on the right side. * * @param matrix The matrix to multiply the receiver with */ - (void)multiplyWithMatrix: (OFMatrix4x4 *)matrix; /** - * @brief Translates the matrix with the specified 3D vector. + * @brief Translates the matrix with the specified vector. * * @param vector The vector to translate the matrix with */ -- (void)translateWithVector3D: (OFVector3D)vector; +- (void)translateWithVector: (OFVector3D)vector; /** - * @brief Scales the matrix with the specified 3D vector. + * @brief Scales the matrix with the specified vector. * * @param vector The vector to scale the matrix with */ -- (void)scaleWithVector3D: (OFVector3D)vector; +- (void)scaleWithVector: (OFVector3D)vector; /** - * @brief Transforms the specified point in 3D space according to the matrix. + * @brief Transforms the specified vector according to the matrix. * - * @param point The point to transform - * @return The transformed point + * @param vector The vector to transform + * @return The transformed vector */ -- (OFVector3D)transformedPoint3D: (OFVector3D)point; +- (OFVector4D)transformedVector: (OFVector4D)vector; @end OF_ASSUME_NONNULL_END Index: src/OFMatrix4x4.m ================================================================== --- src/OFMatrix4x4.m +++ src/OFMatrix4x4.m @@ -92,101 +92,34 @@ OFHashFinalize(&hash); return hash; } -- (void)transpose -{ - float copy[16]; - memcpy(copy, _values, 16 * sizeof(float)); - - _values[1] = copy[4]; - _values[2] = copy[8]; - _values[3] = copy[12]; - _values[4] = copy[1]; - _values[6] = copy[9]; - _values[7] = copy[13]; - _values[8] = copy[2]; - _values[9] = copy[6]; - _values[11] = copy[14]; - _values[12] = copy[3]; - _values[13] = copy[7]; - _values[14] = copy[11]; -} - -- (void)multiplyWithMatrix: (OFMatrix4x4 *)matrix -{ - float copy[16]; - memcpy(copy, _values, 16 * sizeof(float)); - - _values[0] = matrix->_values[0] * copy[0] + - matrix->_values[4] * copy[1] + - matrix->_values[8] * copy[2] + - matrix->_values[12] * copy[3]; - _values[1] = matrix->_values[1] * copy[0] + - matrix->_values[5] * copy[1] + - matrix->_values[9] * copy[2] + - matrix->_values[13] * copy[3]; - _values[2] = matrix->_values[2] * copy[0] + - matrix->_values[6] * copy[1] + - matrix->_values[10] * copy[2] + - matrix->_values[14] * copy[3]; - _values[3] = matrix->_values[3] * copy[0] + - matrix->_values[7] * copy[1] + - matrix->_values[11] * copy[2] + - matrix->_values[15] * copy[3]; - _values[4] = matrix->_values[0] * copy[4] + - matrix->_values[4] * copy[5] + - matrix->_values[8] * copy[6] + - matrix->_values[12] * copy[7]; - _values[5] = matrix->_values[1] * copy[4] + - matrix->_values[5] * copy[5] + - matrix->_values[9] * copy[6] + - matrix->_values[13] * copy[7]; - _values[6] = matrix->_values[2] * copy[4] + - matrix->_values[6] * copy[5] + - matrix->_values[10] * copy[6] + - matrix->_values[14] * copy[7]; - _values[7] = matrix->_values[3] * copy[4] + - matrix->_values[7] * copy[5] + - matrix->_values[11] * copy[6] + - matrix->_values[15] * copy[7]; - _values[8] = matrix->_values[0] * copy[8] + - matrix->_values[4] * copy[9] + - matrix->_values[8] * copy[10] + - matrix->_values[12] * copy[11]; - _values[9] = matrix->_values[1] * copy[8] + - matrix->_values[5] * copy[9] + - matrix->_values[9] * copy[10] + - matrix->_values[13] * copy[11]; - _values[10] = matrix->_values[2] * copy[8] + - matrix->_values[6] * copy[9] + - matrix->_values[10] * copy[10] + - matrix->_values[14] * copy[11]; - _values[11] = matrix->_values[3] * copy[8] + - matrix->_values[7] * copy[9] + - matrix->_values[11] * copy[10] + - matrix->_values[15] * copy[11]; - _values[12] = matrix->_values[0] * copy[12] + - matrix->_values[4] * copy[13] + - matrix->_values[8] * copy[14] + - matrix->_values[12] * copy[15]; - _values[13] = matrix->_values[1] * copy[12] + - matrix->_values[5] * copy[13] + - matrix->_values[9] * copy[14] + - matrix->_values[13] * copy[15]; - _values[14] = matrix->_values[2] * copy[12] + - matrix->_values[6] * copy[13] + - matrix->_values[10] * copy[14] + - matrix->_values[14] * copy[15]; - _values[15] = matrix->_values[3] * copy[12] + - matrix->_values[7] * copy[13] + - matrix->_values[11] * copy[14] + - matrix->_values[15] * copy[15]; -} - -- (void)translateWithVector3D: (OFVector3D)vector +- (void)multiplyWithMatrix: (OFMatrix4x4 *)matrix +{ + float r[16], *m = _values, *l = matrix->_values; + memcpy(r, m, sizeof(r)); + + m[ 0] = l[0] * r[ 0] + l[4] * r[ 1] + l[ 8] * r[ 2] + l[12] * r[ 3]; + m[ 1] = l[1] * r[ 0] + l[5] * r[ 1] + l[ 9] * r[ 2] + l[13] * r[ 3]; + m[ 2] = l[2] * r[ 0] + l[6] * r[ 1] + l[10] * r[ 2] + l[14] * r[ 3]; + m[ 3] = l[3] * r[ 0] + l[7] * r[ 1] + l[11] * r[ 2] + l[15] * r[ 3]; + m[ 4] = l[0] * r[ 4] + l[4] * r[ 5] + l[ 8] * r[ 6] + l[12] * r[ 7]; + m[ 5] = l[1] * r[ 4] + l[5] * r[ 5] + l[ 9] * r[ 6] + l[13] * r[ 7]; + m[ 6] = l[2] * r[ 4] + l[6] * r[ 5] + l[10] * r[ 6] + l[14] * r[ 7]; + m[ 7] = l[3] * r[ 4] + l[7] * r[ 5] + l[11] * r[ 6] + l[15] * r[ 7]; + m[ 8] = l[0] * r[ 8] + l[4] * r[ 9] + l[ 8] * r[10] + l[12] * r[11]; + m[ 9] = l[1] * r[ 8] + l[5] * r[ 9] + l[ 9] * r[10] + l[13] * r[11]; + m[10] = l[2] * r[ 8] + l[6] * r[ 9] + l[10] * r[10] + l[14] * r[11]; + m[11] = l[3] * r[ 8] + l[7] * r[ 9] + l[11] * r[10] + l[15] * r[11]; + m[12] = l[0] * r[12] + l[4] * r[13] + l[ 8] * r[14] + l[12] * r[15]; + m[13] = l[1] * r[12] + l[5] * r[13] + l[ 9] * r[14] + l[13] * r[15]; + m[14] = l[2] * r[12] + l[6] * r[13] + l[10] * r[14] + l[14] * r[15]; + m[15] = l[3] * r[12] + l[7] * r[13] + l[11] * r[14] + l[15] * r[15]; +} + +- (void)translateWithVector: (OFVector3D)vector { OFMatrix4x4 *translation = [[OFMatrix4x4 alloc] initWithValues: (float [16]){ 1, 0, 0, 0, 0, 1, 0, 0, @@ -195,11 +128,11 @@ }]; [self multiplyWithMatrix: translation]; [translation release]; } -- (void)scaleWithVector3D: (OFVector3D)vector +- (void)scaleWithVector: (OFVector3D)vector { OFMatrix4x4 *scale = [[OFMatrix4x4 alloc] initWithValues: (float [16]){ vector.x, 0, 0, 0, 0, vector.y, 0, 0, @@ -208,19 +141,19 @@ }]; [self multiplyWithMatrix: scale]; [scale release]; } -- (OFVector3D)transformedPoint3D: (OFVector3D)point -{ - return OFMakeVector3D( - _values[0] * point.x + _values[4] * point.y + - _values[8] * point.z + _values[12], - _values[1] * point.x + _values[5] * point.y + - _values[9] * point.z + _values[13], - _values[2] * point.x + _values[6] * point.y + - _values[10] * point.z + _values[14]); +- (OFVector4D)transformedVector: (OFVector4D)vec +{ + float *m = _values; + + return OFMakeVector4D( + m[0] * vec.x + m[4] * vec.y + m[ 8] * vec.z + m[12] * vec.w, + m[1] * vec.x + m[5] * vec.y + m[ 9] * vec.z + m[13] * vec.w, + m[2] * vec.x + m[6] * vec.y + m[10] * vec.z + m[14] * vec.w, + m[3] * vec.x + m[7] * vec.y + m[11] * vec.z + m[15] * vec.w); } - (OFString *)description { return [OFString stringWithFormat: Index: src/OFObject.h ================================================================== --- src/OFObject.h +++ src/OFObject.h @@ -342,10 +342,68 @@ return false; if (vector1.z != vector2.z) return false; + return true; +} + +/** + * @struct OFVector4D OFObject.h ObjFW/OFObject.h + * + * @brief A vector in 4D space. + */ +typedef struct OF_BOXABLE { + /** The x coordinate of the vector */ + float x; + /** The y coordinate of the vector */ + float y; + /** The z coordinate of the vector */ + float z; + /** The w coordinate of the vector */ + float w; +} OFVector4D; + +/** + * @brief Creates a new OFVector4D. + * + * @param x The x coordinate of the vector + * @param y The x coordinate of the vector + * @param z The z coordinate of the vector + * @param w The w coordinate of the vector + * @return An OFVector4D with the specified coordinates + */ +static OF_INLINE OFVector4D OF_CONST_FUNC +OFMakeVector4D(float x, float y, float z, float w) +{ + OFVector4D vector = { x, y, z, w }; + + return vector; +} + +/** + * @brief Returns whether the two vectors are equal. + * + * @param vector1 The first vector for the comparison + * @param vector2 The second vectors for the comparison + * @return Whether the two vectors are equal + */ +static OF_INLINE bool +OFEqualVectors4D(OFVector4D vector1, OFVector4D vector2) +{ + if (vector1.x != vector2.x) + return false; + + if (vector1.y != vector2.y) + return false; + + if (vector1.z != vector2.z) + return false; + + if (vector1.w != vector2.w) + return false; + return true; } /** * @brief Adds the specified byte to the hash. Index: tests/OFMatrix4x4Tests.m ================================================================== --- tests/OFMatrix4x4Tests.m +++ tests/OFMatrix4x4Tests.m @@ -22,11 +22,11 @@ @implementation TestsAppDelegate (OFMatrix4x4Tests) - (void)matrix4x4Tests { void *pool = objc_autoreleasePoolPush(); OFMatrix4x4 *matrix, *matrix2; - OFVector3D point; + OFVector4D point; TEST(@"+[identityMatrix]", memcmp([[OFMatrix4x4 identityMatrix] values], (float [16]){ 1, 0, 0, 0, 0, 1, 0, 0, @@ -34,32 +34,24 @@ 0, 0, 0, 1 }, 16 * sizeof(float)) == 0) TEST(@"+[matrixWithValues:]", (matrix = [OFMatrix4x4 matrixWithValues: (float [16]){ - 1, 2, 3, 4, - 5, 6, 7, 8, - 9, 10, 11, 12, - 13, 14, 15, 16 + 1, 5, 9, 13, + 2, 6, 10, 14, + 3, 7, 11, 15, + 4, 8, 12, 16 }])) TEST(@"-[description]", [matrix.description isEqual: @""]) - TEST(@"-[transpose]", - R([matrix transpose]) && memcmp(matrix.values, (float [16]){ - 1, 5, 9, 13, - 2, 6, 10, 14, - 3, 7, 11, 15, - 4, 8, 12, 16 - }, 16 * sizeof(float)) == 0) - TEST(@"-[isEqual:]", [[OFMatrix4x4 identityMatrix] isEqual: [OFMatrix4x4 matrixWithValues: (float [16]){ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, @@ -85,23 +77,26 @@ 10000, 22800, 35600, 48400, 11000, 25400, 39800, 54200, 12000, 28000, 44000, 60000 }]]) - TEST(@"[-translateWithVector3D:]", - R(matrix2 = [OFMatrix4x4 identityMatrix]) && - R([matrix2 translateWithVector3D: OFMakeVector3D(1, 2, 3)]) && - R(point = [matrix2 transformedPoint3D: OFMakeVector3D(2, 3, 4)]) && - point.x == 3 && point.y == 5 && point.z == 7) - - TEST(@"-[scaleWithVector3D:]", - R([matrix2 scaleWithVector3D: OFMakeVector3D(-1, 0.5, 2)]) && - R(point = [matrix2 transformedPoint3D: OFMakeVector3D(2, 3, 4)]) && - point.x == -3 && point.y == 2.5 && point.z == 14) - - TEST(@"-[transformedPoint3D:]", - R((point = [matrix transformedPoint3D: OFMakeVector3D(1, 2, 3)])) && - point.x == 18 && point.y == 46 && point.z == 74) + TEST(@"[-translateWithVector:]", + R(matrix2 = [OFMatrix4x4 identityMatrix]) && + R([matrix2 translateWithVector: OFMakeVector3D(1, 2, 3)]) && + R(point = + [matrix2 transformedVector: OFMakeVector4D(2, 3, 4, 1)]) && + point.x == 3 && point.y == 5 && point.z == 7 && point.w == 1) + + TEST(@"-[scaleWithVector:]", + R([matrix2 scaleWithVector: OFMakeVector3D(-1, 0.5, 2)]) && + R(point = + [matrix2 transformedVector: OFMakeVector4D(2, 3, 4, 1)]) && + point.x == -3 && point.y == 2.5 && point.z == 14 && point.w == 1) + + TEST(@"-[transformedVector:]", + R((point = + [matrix transformedVector: OFMakeVector4D(1, 2, 3, 1)])) && + point.x == 18 && point.y == 46 && point.z == 74 && point.w == 102) objc_autoreleasePoolPop(pool); } @end