#include "gamemath/BezierCurve.h" #include "gamemath/Matrix4x4f.h" #include "gamemath/Vector2f.h" #include "gamemath/Vector3f.h" #include "gamemath/Vector4f.h" #include "gamemath/Quaternionf.h" #include #include #include #include #include static bool outputCompact; static bool outputHex; static unsigned int namedMatrixCount; static struct { Matrix4x4f matrix; const char * name; } * namedMatrices; static unsigned int namedQuaternionCount; static struct { Quaternionf quaternion; const char * name; } * namedQuaternions; static unsigned int namedVector2Count; static struct { Vector2f vector; const char * name; } * namedVector2s; static unsigned int namedVector3Count; static struct { Vector3f vector; const char * name; } * namedVector3s; static unsigned int namedVector4Count; static struct { Vector4f vector; const char * name; } * namedVector4s; static void printUsage(void) { fprintf(stderr, "Usage: testharness [OPTION]... [DATA TYPE] [VALUE] [OPERATION]...\n" " Options:\n" " --hex\n" " --compact\n" "\n" " Data types:\n" " matrix: 16 values, @name, \"identity\", or \"-\" to read from stdin\n" " quaternion: 4 values, @name, \"identity\", \"-\" to read from stdin, or \"axis_angle\" followed by x, y, z, radians\n" " vector2: 2 values, @name, \"-\" to read from stdin, or \"barycenter\" followed by x, y, z, x0, y0, x1, y1, x2, y2\n" " vector3: 3 values, @name, \"-\" to read from stdin, or \"barycenter\" followed by x, y, z, x0, y0, z0, x1, y1, z1, x2, y2, z2\n" " vector4: 4 values, @name, \"-\" to read from stdin, or \"barycenter\" followed by x, y, z, x0, y0, z0, w0, x1, y1, z1, w1, x2, y2, z2, w2\n" " bezier: 8 values (point 0, control 0, control 1, point 1), or \"-\" to read from stdin\n" "\n" " Radian values can be raw numbers, \"deg:%%f\" for degrees, or \"pi:%%f\" for a fraction of pi\n" "\n" " For more information on a specific type, invoke with --help type (eg. gamemath_calculator --help matrix)\n"); } static void printMatrixUsage(void) { fprintf(stderr, " Matrix operations:\n" " multiply: matrix\n" " multiply_quaternion: quaternion\n" " translate: vector3\n" " scale: vector3\n" " rotate: vector3, radians\n" " shear_x: y, z\n" " shear_y: x, z\n" " shear_z: x, y\n" " perspective: fovYDegrees, aspect, zNear, zFar\n" " ortho: left, right, bottom, top, zNear, zFar\n" " transpose\n" " inverse (or invert)\n" " determinant (prints and terminates further operations)\n" " print\n" " assign: name\n"); } static void printQuaternionUsage(void) { fprintf(stderr, " Quaternion operations:\n" " multiply: quaternion\n" " rotate: vector3, radians\n" " magnitude (prints and terminates further operations)\n" " normalize\n" " slerp: quaternion, value\n" " inverse (or invert)\n" " to_matrix (prints and terminates further operations)\n" " to_axis_angle (prints and terminates further operations)\n" " print\n" " assign: name\n"); } static void printVector2Usage(void) { fprintf(stderr, " Vector2 operations:\n" " normalize\n" " inverse (or invert)\n" " add: vector2\n" " subtract: vector2\n" " scale_to: value\n" " multiply_scalar: value\n" " multiply_vector: vector2\n" " divide_scalar: value\n" " divide_vector: vector2\n" " interpolate: vector2, value\n" " round\n" " reflect: vector2\n" " project: vector2\n" " line_position: vector2, vector2\n" " dot: vector2 (prints and terminates further operations)\n" " cross: vector2 (prints and terminates further operations)\n" " intersect: vector2 direction, vector2 normal\n" " rotate: radians (counterclockwise)\n" " magnitude (prints and terminates further operations)\n" " distance: vector2 (prints and terminates further operations)\n" " to_barycenter: vector2, vector2, vector2 (prints and terminates further operations)\n" " multiply_matrix: matrix\n" " swizzle: axes (2-4 letters x or y; can change dimensions)\n" " print\n" " assign: name\n"); } static void printVector3Usage(void) { fprintf(stderr, " Vector3 operations:\n" " normalize\n" " inverse (or invert)\n" " add: vector3\n" " subtract: vector3\n" " scale_to: value\n" " multiply_scalar: value\n" " multiply_vector: x, y, z\n" " divide_scalar: value\n" " divide_vector: vector3\n" " interpolate: vector3, value\n" " round\n" " reflect: vector3\n" " project: vector3\n" " line_position: vector3, vector3\n" " plane_position: vector3, vector3\n" " closest_line_to_line: vector3, vector3, vector3\n" " dot: vector3 (prints and terminates further operations)\n" " cross: vector3\n" " intersect: vector3 direction, vector3 normal\n" " magnitude (prints and terminates further operations)\n" " distance: vector3 (prints and terminates further operations)\n" " to_barycenter: vector3, vector3, vector3 (prints and terminates further operations)\n" " multiply_matrix: matrix\n" " multiply_matrix_rotation_only: matrix\n" " multiply_quaternion: quaternion\n" " swizzle: axes (2-4 letters x, y, or z; can change dimensions)\n" " print\n" " assign: name\n"); } static void printVector4Usage(void) { fprintf(stderr, " Vector4 operations:\n" " normalize\n" " normalize_w\n" " inverse (or invert)\n" " add: vector4\n" " subtract: vector4\n" " scale_to: value\n" " multiply_scalar: value\n" " multiply_vector: vector4\n" " divide_scalar: value\n" " divide_vector: vector4\n" " interpolate: vector4, value\n" " round\n" " reflect: vector4\n" " project: vector4\n" " line_position: vector4, vector4\n" " plane_position: vector4, vector4\n" " dot: vector4 (prints and terminates further operations)\n" " magnitude (prints and terminates further operations)\n" " distance: vector4 (prints and terminates further operations)\n" " to_barycenter: vector4, vector4, vector4 (prints and terminates further operations)\n" " multiply_matrix: matrix\n" " multiply_quaternion: quaternion\n" " swizzle: axes (2-4 letters x, y, z, or w; can change dimensions)\n" " print\n" " assign: name\n"); } static void printBezierUsage(void) { fprintf(stderr, " Bezier operations:\n" " sample: value\n" " sample_at_x: x, iterations\n" " sample_at_y: y, iterations\n"); } static unsigned int readUIntArgv(int * ioArgIndex, int argc, const char ** argv) { int argIndex = *ioArgIndex + 1; if (argIndex >= argc) { fprintf(stderr, "Reached end of argv when expecting more numbers\n"); exit(EXIT_FAILURE); } unsigned int uintValue; if (sscanf(argv[argIndex], "0x%X", &uintValue) == 1 || sscanf(argv[argIndex], "%u", &uintValue) == 1) { *ioArgIndex += 1; return uintValue; } fprintf(stderr, "Couldn't parse \"%s\" as unsigned int\n", argv[argIndex]); exit(EXIT_FAILURE); } static float readFloatArgv(int * ioArgIndex, int argc, const char ** argv) { int argIndex = *ioArgIndex + 1; if (argIndex >= argc) { fprintf(stderr, "Reached end of argv when expecting more numbers\n"); exit(EXIT_FAILURE); } unsigned int hexValue; if (sscanf(argv[argIndex], "0x%X", &hexValue) == 1) { *ioArgIndex += 1; return *(float *) &hexValue; } float floatValue; if (sscanf(argv[argIndex], "%f", &floatValue) == 1) { *ioArgIndex += 1; return floatValue; } fprintf(stderr, "Couldn't parse \"%s\" as a number\n", argv[argIndex]); exit(EXIT_FAILURE); } static float readFloatFromFile(FILE * file) { unsigned int hexValue; if (fscanf(file, "0x%X", &hexValue) == 1 || fscanf(file, " 0x%X", &hexValue) == 1) { return *(float *) &hexValue; } float floatValue; if (fscanf(file, "%f", &floatValue) == 1 || fscanf(file, " %f", &floatValue) == 1) { return floatValue; } fprintf(stderr, "Couldn't parse next number from input file\n"); exit(EXIT_FAILURE); } static float readAngleArgv(int * ioArgIndex, int argc, const char ** argv) { int argIndex = *ioArgIndex + 1; if (argIndex >= argc) { fprintf(stderr, "Reached end of argv when expecting more numbers\n"); exit(EXIT_FAILURE); } unsigned int hexValue; if (sscanf(argv[argIndex], "0x%X", &hexValue) == 1) { *ioArgIndex += 1; return *(float *) &hexValue; } float floatValue; if (sscanf(argv[argIndex], "deg:%f", &floatValue) == 1) { *ioArgIndex += 1; floatValue *= M_PI / 180.0f; return floatValue; } if (sscanf(argv[argIndex], "pi:%f", &floatValue) == 1) { *ioArgIndex += 1; floatValue *= M_PI; return floatValue; } if (sscanf(argv[argIndex], "%f", &floatValue) == 1) { *ioArgIndex += 1; return floatValue; } fprintf(stderr, "Couldn't parse \"%s\" as an angle\n", argv[argIndex]); exit(EXIT_FAILURE); } static Matrix4x4f readMatrix4x4fArgv(int * ioArgIndex, int argc, const char ** argv) { Matrix4x4f matrix; int argIndex = *ioArgIndex + 1; if (argIndex >= argc) { fprintf(stderr, "Reached end of argv when expecting a matrix\n"); exit(EXIT_FAILURE); } if (argv[argIndex][0] == '@') { for (unsigned int nameIndex = 0; nameIndex < namedMatrixCount; nameIndex++) { if (!strcmp(namedMatrices[nameIndex].name, argv[argIndex] + 1)) { *ioArgIndex += 1; return namedMatrices[nameIndex].matrix; } } fprintf(stderr, "Matrix with name %s was not found\n", argv[argIndex]); exit(EXIT_FAILURE); } if (!strcmp(argv[argIndex], "identity")) { matrix = MATRIX4x4f_IDENTITY; *ioArgIndex += 1; } else if (!strcmp(argv[argIndex], "-")) { for (int numberIndex = 0; numberIndex < 16; numberIndex++) { matrix.m[numberIndex] = readFloatFromFile(stdin); } *ioArgIndex += 1; } else { for (int numberIndex = 0; numberIndex < 16; numberIndex++) { matrix.m[numberIndex] = readFloatArgv(ioArgIndex, argc, argv); } } Matrix4x4f_transpose(&matrix); return matrix; } static void printMatrix4x4f(Matrix4x4f matrix) { Matrix4x4f_transpose(&matrix); if (outputHex) { printf("0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n", *(unsigned int *) &matrix.m[0], *(unsigned int *) &matrix.m[1], *(unsigned int *) &matrix.m[2], *(unsigned int *) &matrix.m[3], *(unsigned int *) &matrix.m[4], *(unsigned int *) &matrix.m[5], *(unsigned int *) &matrix.m[6], *(unsigned int *) &matrix.m[7], *(unsigned int *) &matrix.m[8], *(unsigned int *) &matrix.m[9], *(unsigned int *) &matrix.m[10], *(unsigned int *) &matrix.m[11], *(unsigned int *) &matrix.m[12], *(unsigned int *) &matrix.m[13], *(unsigned int *) &matrix.m[14], *(unsigned int *) &matrix.m[15]); } else if (outputCompact) { printf("%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n", matrix.m[0], matrix.m[1], matrix.m[2], matrix.m[3], matrix.m[4], matrix.m[5], matrix.m[6], matrix.m[7], matrix.m[8], matrix.m[9], matrix.m[10], matrix.m[11], matrix.m[12], matrix.m[13], matrix.m[14], matrix.m[15]); } else { printf("{%f, %f, %f, %f,\n %f, %f, %f, %f,\n %f, %f, %f, %f,\n %f, %f, %f, %f}\n", matrix.m[0], matrix.m[1], matrix.m[2], matrix.m[3], matrix.m[4], matrix.m[5], matrix.m[6], matrix.m[7], matrix.m[8], matrix.m[9], matrix.m[10], matrix.m[11], matrix.m[12], matrix.m[13], matrix.m[14], matrix.m[15]); } } static Quaternionf readQuaternionfArgv(int * ioArgIndex, int argc, const char ** argv) { Quaternionf quaternion; int argIndex = *ioArgIndex + 1; if (argIndex >= argc) { fprintf(stderr, "Reached end of argv when expecting a quaternion\n"); exit(EXIT_FAILURE); } if (argv[argIndex][0] == '@') { for (unsigned int nameIndex = 0; nameIndex < namedQuaternionCount; nameIndex++) { if (!strcmp(namedQuaternions[nameIndex].name, argv[argIndex] + 1)) { *ioArgIndex += 1; return namedQuaternions[nameIndex].quaternion; } } fprintf(stderr, "Quaternion with name %s was not found\n", argv[argIndex]); exit(EXIT_FAILURE); } if (!strcmp(argv[argIndex], "identity")) { quaternion = QUATERNIONf_IDENTITY; *ioArgIndex += 1; } else if (!strcmp(argv[argIndex], "axis_angle")) { ++*ioArgIndex; Vector3f axis; axis.x = readFloatArgv(ioArgIndex, argc, argv); axis.y = readFloatArgv(ioArgIndex, argc, argv); axis.z = readFloatArgv(ioArgIndex, argc, argv); float angle = readAngleArgv(ioArgIndex, argc, argv); quaternion = Quaternionf_fromAxisAngle(axis, angle); } else if (!strcmp(argv[argIndex], "-")) { quaternion.x = readFloatFromFile(stdin); quaternion.y = readFloatFromFile(stdin); quaternion.z = readFloatFromFile(stdin); quaternion.w = readFloatFromFile(stdin); *ioArgIndex += 1; } else { quaternion.x = readFloatArgv(ioArgIndex, argc, argv); quaternion.y = readFloatArgv(ioArgIndex, argc, argv); quaternion.z = readFloatArgv(ioArgIndex, argc, argv); quaternion.w = readFloatArgv(ioArgIndex, argc, argv); } return quaternion; } static void printQuaternionf(Quaternionf quaternion) { if (outputHex) { printf("0x%X 0x%X 0x%X 0x%X\n", *(unsigned int *) &quaternion.x, *(unsigned int *) &quaternion.y, *(unsigned int *) &quaternion.z, *(unsigned int *) &quaternion.w); } else if (outputCompact) { printf("%f %f %f %f\n", quaternion.x, quaternion.y, quaternion.z, quaternion.w); } else { printf("{%f, %f, %f, %f}\n", quaternion.x, quaternion.y, quaternion.z, quaternion.w); } } static Vector3f readVector3fArgv(int * ioArgIndex, int argc, const char ** argv) { Vector3f vector; int argIndex = *ioArgIndex + 1; if (argIndex >= argc) { fprintf(stderr, "Reached end of argv when expecting a vector3\n"); exit(EXIT_FAILURE); } if (argv[argIndex][0] == '@') { for (unsigned int nameIndex = 0; nameIndex < namedVector3Count; nameIndex++) { if (!strcmp(namedVector3s[nameIndex].name, argv[argIndex] + 1)) { *ioArgIndex += 1; return namedVector3s[nameIndex].vector; } } fprintf(stderr, "Vector3 with name %s was not found\n", argv[argIndex]); exit(EXIT_FAILURE); } if (!strcmp(argv[argIndex], "barycenter")) { *ioArgIndex += 1; Vector3f barycenter = readVector3fArgv(ioArgIndex, argc, argv); Vector3f vertex0 = readVector3fArgv(ioArgIndex, argc, argv); Vector3f vertex1 = readVector3fArgv(ioArgIndex, argc, argv); Vector3f vertex2 = readVector3fArgv(ioArgIndex, argc, argv); vector = Vector3f_fromBarycenter(barycenter, vertex0, vertex1, vertex2); } else if (!strcmp(argv[argIndex], "-")) { vector.x = readFloatFromFile(stdin); vector.y = readFloatFromFile(stdin); vector.z = readFloatFromFile(stdin); *ioArgIndex += 1; } else { vector.x = readFloatArgv(ioArgIndex, argc, argv); vector.y = readFloatArgv(ioArgIndex, argc, argv); vector.z = readFloatArgv(ioArgIndex, argc, argv); } return vector; } static void printVector3f(Vector3f vector) { if (outputHex) { printf("0x%X 0x%X 0x%X\n", *(unsigned int *) &vector.x, *(unsigned int *) &vector.y, *(unsigned int *) &vector.z); } else if (outputCompact) { printf("%f %f %f\n", vector.x, vector.y, vector.z); } else { printf("{%f, %f, %f}\n", vector.x, vector.y, vector.z); } } static Vector2f readVector2fArgv(int * ioArgIndex, int argc, const char ** argv) { Vector2f vector; int argIndex = *ioArgIndex + 1; if (argIndex >= argc) { fprintf(stderr, "Reached end of argv when expecting a vector2\n"); exit(EXIT_FAILURE); } if (argv[argIndex][0] == '@') { for (unsigned int nameIndex = 0; nameIndex < namedVector2Count; nameIndex++) { if (!strcmp(namedVector2s[nameIndex].name, argv[argIndex] + 1)) { *ioArgIndex += 1; return namedVector2s[nameIndex].vector; } } fprintf(stderr, "Vector2 with name %s was not found\n", argv[argIndex]); exit(EXIT_FAILURE); } if (!strcmp(argv[argIndex], "barycenter")) { *ioArgIndex += 1; Vector3f barycenter = readVector3fArgv(ioArgIndex, argc, argv); Vector2f vertex0 = readVector2fArgv(ioArgIndex, argc, argv); Vector2f vertex1 = readVector2fArgv(ioArgIndex, argc, argv); Vector2f vertex2 = readVector2fArgv(ioArgIndex, argc, argv); vector = Vector2f_fromBarycenter(barycenter, vertex0, vertex1, vertex2); } else if (!strcmp(argv[argIndex], "-")) { vector.x = readFloatFromFile(stdin); vector.y = readFloatFromFile(stdin); *ioArgIndex += 1; } else { vector.x = readFloatArgv(ioArgIndex, argc, argv); vector.y = readFloatArgv(ioArgIndex, argc, argv); } return vector; } static void printVector2f(Vector2f vector) { if (outputHex) { printf("0x%X 0x%X\n", *(unsigned int *) &vector.x, *(unsigned int *) &vector.y); } else if (outputCompact) { printf("%f %f\n", vector.x, vector.y); } else { printf("{%f, %f}\n", vector.x, vector.y); } } static Vector4f readVector4fArgv(int * ioArgIndex, int argc, const char ** argv) { Vector4f vector; int argIndex = *ioArgIndex + 1; if (argIndex >= argc) { fprintf(stderr, "Reached end of argv when expecting a vector4\n"); exit(EXIT_FAILURE); } if (argv[argIndex][0] == '@') { for (unsigned int nameIndex = 0; nameIndex < namedVector4Count; nameIndex++) { if (!strcmp(namedVector4s[nameIndex].name, argv[argIndex] + 1)) { *ioArgIndex += 1; return namedVector4s[nameIndex].vector; } } fprintf(stderr, "Vector4 with name %s was not found\n", argv[argIndex]); exit(EXIT_FAILURE); } if (!strcmp(argv[argIndex], "barycenter")) { *ioArgIndex += 1; Vector3f barycenter = readVector3fArgv(ioArgIndex, argc, argv); Vector4f vertex0 = readVector4fArgv(ioArgIndex, argc, argv); Vector4f vertex1 = readVector4fArgv(ioArgIndex, argc, argv); Vector4f vertex2 = readVector4fArgv(ioArgIndex, argc, argv); vector = Vector4f_fromBarycenter(barycenter, vertex0, vertex1, vertex2); } else if (!strcmp(argv[argIndex], "-")) { vector.x = readFloatFromFile(stdin); vector.y = readFloatFromFile(stdin); vector.z = readFloatFromFile(stdin); vector.w = readFloatFromFile(stdin); *ioArgIndex += 1; } else { vector.x = readFloatArgv(ioArgIndex, argc, argv); vector.y = readFloatArgv(ioArgIndex, argc, argv); vector.z = readFloatArgv(ioArgIndex, argc, argv); vector.w = readFloatArgv(ioArgIndex, argc, argv); } return vector; } static unsigned int swizzleVector(float * vector, unsigned int dimensions, float * outComponents, const char * letters) { unsigned int length = strlen(letters); if (length < 2 || length > 4) { fprintf(stderr, "Invalid swizzle: \"%s\"\n", letters); exit(EXIT_FAILURE); } for (unsigned int letterIndex = 0; letterIndex < length; letterIndex++) { switch (letters[letterIndex]) { case 'x': case 'X': outComponents[letterIndex] = vector[0]; break; case 'y': case 'Y': outComponents[letterIndex] = vector[1]; break; case 'z': case 'Z': if (dimensions < 3) { fprintf(stderr, "Swizzle \"%s\" attempts to reference z component in a vector with only %u dimensions\n", letters, dimensions); exit(EXIT_FAILURE); } outComponents[letterIndex] = vector[2]; break; case 'w': case 'W': if (dimensions < 4) { fprintf(stderr, "Swizzle \"%s\" attempts to reference w component in a vector with only %u dimensions\n", letters, dimensions); exit(EXIT_FAILURE); } outComponents[letterIndex] = vector[3]; break; default: fprintf(stderr, "Swizzle \"%s\" contains invalid characters (only x, y, z, and w are allowed)\n", letters); exit(EXIT_FAILURE); } } return length; } static void printVector4f(Vector4f vector) { if (outputHex) { printf("0x%X 0x%X 0x%X 0x%X\n", *(unsigned int *) &vector.x, *(unsigned int *) &vector.y, *(unsigned int *) &vector.z, *(unsigned int *) &vector.w); } else if (outputCompact) { printf("%f %f %f %f\n", vector.x, vector.y, vector.z, vector.w); } else { printf("{%f, %f, %f, %f}\n", vector.x, vector.y, vector.z, vector.w); } } static void printAxisAngle(Vector3f axis, float angle) { if (outputHex) { printf("0x%X 0x%X 0x%X 0x%X\n", *(unsigned int *) &axis.x, *(unsigned int *) &axis.y, *(unsigned int *) &axis.z, *(unsigned int *) &angle); } else if (outputCompact) { printf("%f %f %f %f\n", axis.x, axis.y, axis.z, angle); } else { printf("{%f, %f, %f}, %f\n", axis.x, axis.y, axis.z, angle); } } static void printScalar(float value) { if (outputHex) { printf("0x%X\n", *(unsigned int *) &value); } else { printf("%f\n", value); } } static void matrixLoop(int argc, const char ** argv, int * ioArgIndex, Matrix4x4f matrix); static void quaternionLoop(int argc, const char ** argv, int * ioArgIndex, Quaternionf quaternion); static void vector2Loop(int argc, const char ** argv, int * ioArgIndex, Vector2f vector); static void vector3Loop(int argc, const char ** argv, int * ioArgIndex, Vector3f vector); static void vector4Loop(int argc, const char ** argv, int * ioArgIndex, Vector4f vector); static void restartLoopWithVectorSwizzle(int argc, const char ** argv, int * ioArgIndex, float * vectorComponents, unsigned int dimensionCount) { float components[4]; int argIndex = *ioArgIndex + 1; unsigned int componentCount = swizzleVector(vectorComponents, dimensionCount, components, argv[argIndex]); switch (componentCount) { case 2: { Vector2f vector2 = {components[0], components[1]}; vector2Loop(argc, argv, &argIndex, vector2); break; } case 3: { Vector3f vector3 = {components[0], components[1], components[2]}; vector3Loop(argc, argv, &argIndex, vector3); break; } case 4: { Vector4f vector4 = {components[0], components[1], components[2], components[3]}; vector4Loop(argc, argv, &argIndex, vector4); break; } } *ioArgIndex = argIndex; } static void matrixLoop(int argc, const char ** argv, int * ioArgIndex, Matrix4x4f matrix) { for (int argIndex = *ioArgIndex + 1; argIndex < argc; argIndex++) { if (!strcmp(argv[argIndex], "--hex")) { outputHex = true; } else if (!strcmp(argv[argIndex], "--compact")) { outputCompact = true; } else if (!strcmp(argv[argIndex], "multiply")) { Matrix4x4f matrix2 = readMatrix4x4fArgv(&argIndex, argc, argv); Matrix4x4f_multiply(&matrix, matrix2); } else if (!strcmp(argv[argIndex], "multiply_quaternion")) { Quaternionf quaternion = readQuaternionfArgv(&argIndex, argc, argv); Matrix4x4f matrix2 = Quaternionf_toMatrix(quaternion); Matrix4x4f_multiply(&matrix, matrix2); } else if (!strcmp(argv[argIndex], "translate")) { Vector3f translation = readVector3fArgv(&argIndex, argc, argv); Matrix4x4f_translate(&matrix, translation.x, translation.y, translation.z); } else if (!strcmp(argv[argIndex], "scale")) { Vector3f scale = readVector3fArgv(&argIndex, argc, argv); Matrix4x4f_scale(&matrix, scale.x, scale.y, scale.z); } else if (!strcmp(argv[argIndex], "rotate")) { Vector3f axis = readVector3fArgv(&argIndex, argc, argv); float angle = readAngleArgv(&argIndex, argc, argv); Matrix4x4f_rotate(&matrix, axis, angle); } else if (!strcmp(argv[argIndex], "shear_x")) { float y = readFloatArgv(&argIndex, argc, argv); float z = readFloatArgv(&argIndex, argc, argv); Matrix4x4f_shearX(&matrix, y, z); } else if (!strcmp(argv[argIndex], "shear_y")) { float x = readFloatArgv(&argIndex, argc, argv); float z = readFloatArgv(&argIndex, argc, argv); Matrix4x4f_shearY(&matrix, x, z); } else if (!strcmp(argv[argIndex], "shear_z")) { float x = readFloatArgv(&argIndex, argc, argv); float y = readFloatArgv(&argIndex, argc, argv); Matrix4x4f_shearZ(&matrix, x, y); } else if (!strcmp(argv[argIndex], "perspective")) { float fovYDegrees = readFloatArgv(&argIndex, argc, argv); float aspect = readFloatArgv(&argIndex, argc, argv); float zNear = readFloatArgv(&argIndex, argc, argv); float zFar = readFloatArgv(&argIndex, argc, argv); Matrix4x4f_applyPerspective(&matrix, fovYDegrees, aspect, zNear, zFar); } else if (!strcmp(argv[argIndex], "ortho")) { float left = readFloatArgv(&argIndex, argc, argv); float right = readFloatArgv(&argIndex, argc, argv); float bottom = readFloatArgv(&argIndex, argc, argv); float top = readFloatArgv(&argIndex, argc, argv); float zNear = readFloatArgv(&argIndex, argc, argv); float zFar = readFloatArgv(&argIndex, argc, argv); Matrix4x4f_applyOrtho(&matrix, left, right, bottom, top, zNear, zFar); } else if (!strcmp(argv[argIndex], "transpose")) { Matrix4x4f_transpose(&matrix); } else if (!strcmp(argv[argIndex], "inverse") || !strcmp(argv[argIndex], "invert")) { Matrix4x4f_invert(&matrix); } else if (!strcmp(argv[argIndex], "determinant")) { float determinant = Matrix4x4f_determinant(matrix); printScalar(determinant); exit(EXIT_SUCCESS); } else if (!strcmp(argv[argIndex], "print")) { printMatrix4x4f(matrix); } else if (!strcmp(argv[argIndex], "assign")) { if (argc <= argIndex + 1) { fprintf(stderr, "No name specified after assign command\n"); printUsage(); exit(EXIT_FAILURE); } for (unsigned int namedMatrixIndex = 0; namedMatrixIndex < namedMatrixCount; namedMatrixIndex++) { if (!strcmp(namedMatrices[namedMatrixIndex].name, argv[argIndex + 1])) { namedMatrices[namedMatrixIndex].matrix = matrix; *ioArgIndex = argIndex + 1; return; } } namedMatrices = realloc(namedMatrices, (namedMatrixCount + 1) * sizeof(*namedMatrices)); namedMatrices[namedMatrixCount].name = argv[++argIndex]; namedMatrices[namedMatrixCount++].matrix = matrix; *ioArgIndex = argIndex; return; } else { fprintf(stderr, "Unrecognized matrix operation: %s\n", argv[argIndex]); break; } } printMatrix4x4f(matrix); exit(EXIT_SUCCESS); } static void quaternionLoop(int argc, const char ** argv, int * ioArgIndex, Quaternionf quaternion) { for (int argIndex = *ioArgIndex + 1; argIndex < argc; argIndex++) { if (!strcmp(argv[argIndex], "--hex")) { outputHex = true; } else if (!strcmp(argv[argIndex], "--compact")) { outputCompact = true; } else if (!strcmp(argv[argIndex], "multiply")) { Quaternionf quaternion2 = readQuaternionfArgv(&argIndex, argc, argv); Quaternionf_multiply(&quaternion, quaternion2); } else if (!strcmp(argv[argIndex], "rotate")) { Vector3f axis = readVector3fArgv(&argIndex, argc, argv); float angle = readAngleArgv(&argIndex, argc, argv); Quaternionf_rotate(&quaternion, axis, angle); } else if (!strcmp(argv[argIndex], "magnitude")) { float magnitude = Quaternionf_magnitude(quaternion); printScalar(magnitude); exit(EXIT_SUCCESS); } else if (!strcmp(argv[argIndex], "normalize")) { Quaternionf_normalize(&quaternion); } else if (!strcmp(argv[argIndex], "slerp")) { Quaternionf quaternion2 = readQuaternionfArgv(&argIndex, argc, argv); float value = readFloatArgv(&argIndex, argc, argv); quaternion = Quaternionf_slerp(quaternion, quaternion2, value); } else if (!strcmp(argv[argIndex], "inverse") || !strcmp(argv[argIndex], "invert")) { Quaternionf_invert(&quaternion); } else if (!strcmp(argv[argIndex], "to_matrix")) { Matrix4x4f matrix = Quaternionf_toMatrix(quaternion); printMatrix4x4f(matrix); exit(EXIT_SUCCESS); } else if (!strcmp(argv[argIndex], "to_axis_angle")) { Vector3f axis; float angle; Quaternionf_toAxisAngle(quaternion, &axis, &angle); printAxisAngle(axis, angle); exit(EXIT_SUCCESS); } else if (!strcmp(argv[argIndex], "print")) { printQuaternionf(quaternion); } else if (!strcmp(argv[argIndex], "assign")) { if (argc <= argIndex + 1) { fprintf(stderr, "No name specified after assign command\n"); printUsage(); exit(EXIT_FAILURE); } for (unsigned int namedQuaternionIndex = 0; namedQuaternionIndex < namedQuaternionCount; namedQuaternionIndex++) { if (!strcmp(namedQuaternions[namedQuaternionIndex].name, argv[argIndex + 1])) { namedQuaternions[namedQuaternionIndex].quaternion = quaternion; *ioArgIndex = argIndex + 1; return; } } namedQuaternions = realloc(namedQuaternions, (namedQuaternionCount + 1) * sizeof(*namedQuaternions)); namedQuaternions[namedQuaternionCount].name = argv[++argIndex]; namedQuaternions[namedQuaternionCount++].quaternion = quaternion; *ioArgIndex = argIndex; return; } else { fprintf(stderr, "Unrecognized quaternion operation: %s\n", argv[argIndex]); break; } } printQuaternionf(quaternion); exit(EXIT_SUCCESS); } static void vector2Loop(int argc, const char ** argv, int * ioArgIndex, Vector2f vector) { for (int argIndex = *ioArgIndex + 1; argIndex < argc; argIndex++) { if (!strcmp(argv[argIndex], "--hex")) { outputHex = true; } else if (!strcmp(argv[argIndex], "--compact")) { outputCompact = true; } else if (!strcmp(argv[argIndex], "normalize")) { Vector2f_normalize(&vector); } else if (!strcmp(argv[argIndex], "inverse") || !strcmp(argv[argIndex], "invert")) { Vector2f_invert(&vector); } else if (!strcmp(argv[argIndex], "add")) { Vector2f vector2 = readVector2fArgv(&argIndex, argc, argv); vector = Vector2f_add(vector, vector2); } else if (!strcmp(argv[argIndex], "subtract")) { Vector2f vector2 = readVector2fArgv(&argIndex, argc, argv); vector = Vector2f_subtract(vector, vector2); } else if (!strcmp(argv[argIndex], "scale_to")) { float value = readFloatArgv(&argIndex, argc, argv); Vector2f_scaleTo(&vector, value); } else if (!strcmp(argv[argIndex], "multiply_scalar")) { float multiplier = readFloatArgv(&argIndex, argc, argv); vector = Vector2f_multiplyScalar(vector, multiplier); } else if (!strcmp(argv[argIndex], "multiply_vector")) { Vector2f vector2 = readVector2fArgv(&argIndex, argc, argv); vector = Vector2f_multiplyComponents(vector, vector2); } else if (!strcmp(argv[argIndex], "divide_scalar")) { float divisor = readFloatArgv(&argIndex, argc, argv); vector = Vector2f_divideScalar(vector, divisor); } else if (!strcmp(argv[argIndex], "divide_vector")) { Vector2f vector2 = readVector2fArgv(&argIndex, argc, argv); vector = Vector2f_add(vector, vector2); } else if (!strcmp(argv[argIndex], "interpolate")) { Vector2f vector2 = readVector2fArgv(&argIndex, argc, argv); float value = readFloatArgv(&argIndex, argc, argv); vector = Vector2f_interpolate(vector, vector2, value); } else if (!strcmp(argv[argIndex], "round")) { vector = Vector2f_round(vector); } else if (!strcmp(argv[argIndex], "reflect")) { Vector2f vector2 = readVector2fArgv(&argIndex, argc, argv); vector = Vector2f_reflect(vector, vector2); } else if (!strcmp(argv[argIndex], "project")) { Vector2f vector2 = readVector2fArgv(&argIndex, argc, argv); vector = Vector2f_project(vector, vector2); } else if (!strcmp(argv[argIndex], "line_position")) { Vector2f origin = readVector2fArgv(&argIndex, argc, argv); Vector2f normal = readVector2fArgv(&argIndex, argc, argv); vector = Vector2f_positionOnLine(vector, origin, normal); } else if (!strcmp(argv[argIndex], "dot")) { Vector2f vector2 = readVector2fArgv(&argIndex, argc, argv); float dot = Vector2f_dot(vector, vector2); printScalar(dot); exit(EXIT_SUCCESS); } else if (!strcmp(argv[argIndex], "cross")) { Vector2f vector2 = readVector2fArgv(&argIndex, argc, argv); float cross = Vector2f_cross(vector, vector2); printScalar(cross); exit(EXIT_SUCCESS); } else if (!strcmp(argv[argIndex], "intersect")) { Vector2f direction = readVector2fArgv(&argIndex, argc, argv); Vector2f normal = readVector2fArgv(&argIndex, argc, argv); Vector2f intersection; bool success = Vector2f_intersectLine(vector, direction, normal, &intersection, NULL); if (!success) { fprintf(stderr, "Error: Couldn't find intersection point on parallel lines ({%f, %f} -> {%f, %f}, {%f, %f})\n", vector.x, vector.y, direction.x, direction.y, normal.x, normal.y); exit(EXIT_FAILURE); } vector = intersection; } else if (!strcmp(argv[argIndex], "rotate")) { float radians = readAngleArgv(&argIndex, argc, argv); vector = Vector2f_rotate(vector, radians); } else if (!strcmp(argv[argIndex], "magnitude")) { float magnitude = Vector2f_magnitude(vector); printScalar(magnitude); exit(EXIT_SUCCESS); } else if (!strcmp(argv[argIndex], "distance")) { Vector2f vector2 = readVector2fArgv(&argIndex, argc, argv); float distance = Vector2f_distance(vector, vector2); printScalar(distance); exit(EXIT_SUCCESS); } else if (!strcmp(argv[argIndex], "to_barycenter")) { Vector2f vertex0 = readVector2fArgv(&argIndex, argc, argv); Vector2f vertex1 = readVector2fArgv(&argIndex, argc, argv); Vector2f vertex2 = readVector2fArgv(&argIndex, argc, argv); Vector3f barycenter = Vector2f_toBarycenter(vector, vertex0, vertex1, vertex2); printVector3f(barycenter); exit(EXIT_SUCCESS); } else if (!strcmp(argv[argIndex], "multiply_matrix")) { Matrix4x4f matrix = readMatrix4x4fArgv(&argIndex, argc, argv); vector = Matrix4x4f_multiplyVector2f(matrix, vector); } else if (!strcmp(argv[argIndex], "swizzle")) { restartLoopWithVectorSwizzle(argc, argv, &argIndex, (float *) &vector, 2); *ioArgIndex = argIndex; return; } else if (!strcmp(argv[argIndex], "print")) { printVector2f(vector); } else if (!strcmp(argv[argIndex], "assign")) { if (argc <= argIndex + 1) { fprintf(stderr, "No name specified after assign command\n"); printUsage(); exit(EXIT_FAILURE); } for (unsigned int namedVector2Index = 0; namedVector2Index < namedVector2Count; namedVector2Index++) { if (!strcmp(namedVector2s[namedVector2Index].name, argv[argIndex + 1])) { namedVector2s[namedVector2Index].vector = vector; *ioArgIndex = argIndex + 1; return; } } namedVector2s = realloc(namedVector2s, (namedVector2Count + 1) * sizeof(*namedVector2s)); namedVector2s[namedVector2Count].name = argv[++argIndex]; namedVector2s[namedVector2Count++].vector = vector; *ioArgIndex = argIndex; return; } else { fprintf(stderr, "Unrecognized vector2 operation: %s\n", argv[argIndex]); break; } } printVector2f(vector); exit(EXIT_SUCCESS); } static void vector3Loop(int argc, const char ** argv, int * ioArgIndex, Vector3f vector) { for (int argIndex = *ioArgIndex + 1; argIndex < argc; argIndex++) { if (!strcmp(argv[argIndex], "--hex")) { outputHex = true; } else if (!strcmp(argv[argIndex], "--compact")) { outputCompact = true; } else if (!strcmp(argv[argIndex], "normalize")) { Vector3f_normalize(&vector); } else if (!strcmp(argv[argIndex], "inverse") || !strcmp(argv[argIndex], "invert")) { Vector3f_invert(&vector); } else if (!strcmp(argv[argIndex], "add")) { Vector3f vector2 = readVector3fArgv(&argIndex, argc, argv); vector = Vector3f_add(vector, vector2); } else if (!strcmp(argv[argIndex], "subtract")) { Vector3f vector2 = readVector3fArgv(&argIndex, argc, argv); vector = Vector3f_subtract(vector, vector2); } else if (!strcmp(argv[argIndex], "scale_to")) { float value = readFloatArgv(&argIndex, argc, argv); Vector3f_scaleTo(&vector, value); } else if (!strcmp(argv[argIndex], "multiply_scalar")) { float multiplier = readFloatArgv(&argIndex, argc, argv); vector = Vector3f_multiplyScalar(vector, multiplier); } else if (!strcmp(argv[argIndex], "multiply_vector")) { Vector3f vector2 = readVector3fArgv(&argIndex, argc, argv); vector = Vector3f_multiplyComponents(vector, vector2); } else if (!strcmp(argv[argIndex], "divide_scalar")) { float divisor = readFloatArgv(&argIndex, argc, argv); vector = Vector3f_divideScalar(vector, divisor); } else if (!strcmp(argv[argIndex], "divide_vector")) { Vector3f vector2 = readVector3fArgv(&argIndex, argc, argv); vector = Vector3f_add(vector, vector2); } else if (!strcmp(argv[argIndex], "interpolate")) { Vector3f vector2 = readVector3fArgv(&argIndex, argc, argv); float value = readFloatArgv(&argIndex, argc, argv); vector = Vector3f_interpolate(vector, vector2, value); } else if (!strcmp(argv[argIndex], "round")) { vector = Vector3f_round(vector); } else if (!strcmp(argv[argIndex], "reflect")) { Vector3f vector2 = readVector3fArgv(&argIndex, argc, argv); vector = Vector3f_reflect(vector, vector2); } else if (!strcmp(argv[argIndex], "project")) { Vector3f vector2 = readVector3fArgv(&argIndex, argc, argv); vector = Vector3f_project(vector, vector2); } else if (!strcmp(argv[argIndex], "line_position")) { Vector3f origin = readVector3fArgv(&argIndex, argc, argv); Vector3f normal = readVector3fArgv(&argIndex, argc, argv); vector = Vector3f_positionOnLine(vector, origin, normal); } else if (!strcmp(argv[argIndex], "plane_position")) { Vector3f origin = readVector3fArgv(&argIndex, argc, argv); Vector3f normal = readVector3fArgv(&argIndex, argc, argv); vector = Vector3f_positionOnPlane(vector, origin, normal); } else if (!strcmp(argv[argIndex], "closest_line_to_line")) { Vector3f normal0 = readVector3fArgv(&argIndex, argc, argv); Vector3f origin1 = readVector3fArgv(&argIndex, argc, argv); Vector3f normal1 = readVector3fArgv(&argIndex, argc, argv); vector = Vector3f_closestLinePointToLine(vector, normal0, origin1, normal1); } else if (!strcmp(argv[argIndex], "dot")) { Vector3f vector2 = readVector3fArgv(&argIndex, argc, argv); float dot = Vector3f_dot(vector, vector2); printScalar(dot); exit(EXIT_SUCCESS); } else if (!strcmp(argv[argIndex], "cross")) { Vector3f vector2 = readVector3fArgv(&argIndex, argc, argv); vector = Vector3f_cross(vector, vector2); } else if (!strcmp(argv[argIndex], "intersect")) { Vector3f direction = readVector3fArgv(&argIndex, argc, argv); Vector3f normal = readVector3fArgv(&argIndex, argc, argv); Vector3f intersection; bool success = Vector3f_intersectPlane(vector, direction, normal, &intersection, NULL); if (!success) { fprintf(stderr, "Couldn't find intersection point on line parallel to plane ({%f, %f, %f} -> {%f, %f, %f}, {%f, %f, %f})\n", vector.x, vector.y, vector.z, direction.x, direction.y, direction.z, normal.x, normal.y, normal.z); exit(EXIT_FAILURE); } vector = intersection; } else if (!strcmp(argv[argIndex], "magnitude")) { float magnitude = Vector3f_magnitude(vector); printScalar(magnitude); exit(EXIT_SUCCESS); } else if (!strcmp(argv[argIndex], "distance")) { Vector3f vector2 = readVector3fArgv(&argIndex, argc, argv); float distance = Vector3f_distance(vector, vector2); printScalar(distance); exit(EXIT_SUCCESS); } else if (!strcmp(argv[argIndex], "to_barycenter")) { Vector3f vertex0 = readVector3fArgv(&argIndex, argc, argv); Vector3f vertex1 = readVector3fArgv(&argIndex, argc, argv); Vector3f vertex2 = readVector3fArgv(&argIndex, argc, argv); Vector3f barycenter = Vector3f_toBarycenter(vector, vertex0, vertex1, vertex2); printVector3f(barycenter); exit(EXIT_SUCCESS); } else if (!strcmp(argv[argIndex], "multiply_matrix")) { Matrix4x4f matrix = readMatrix4x4fArgv(&argIndex, argc, argv); vector = Matrix4x4f_multiplyVector3f(matrix, vector); } else if (!strcmp(argv[argIndex], "multiply_matrix_rotation_only")) { Matrix4x4f matrix = readMatrix4x4fArgv(&argIndex, argc, argv); vector = Matrix4x4f_multiplyVector3f_rotationOnly(matrix, vector); } else if (!strcmp(argv[argIndex], "multiply_quaternion")) { Quaternionf quaternion = readQuaternionfArgv(&argIndex, argc, argv); vector = Quaternionf_multiplyVector3f(quaternion, vector); } else if (!strcmp(argv[argIndex], "swizzle")) { restartLoopWithVectorSwizzle(argc, argv, &argIndex, (float *) &vector, 3); *ioArgIndex = argIndex; return; } else if (!strcmp(argv[argIndex], "print")) { printVector3f(vector); } else if (!strcmp(argv[argIndex], "assign")) { if (argc <= argIndex + 1) { fprintf(stderr, "No name specified after assign command\n"); printUsage(); exit(EXIT_FAILURE); } for (unsigned int namedVector3Index = 0; namedVector3Index < namedVector3Count; namedVector3Index++) { if (!strcmp(namedVector3s[namedVector3Index].name, argv[argIndex + 1])) { namedVector3s[namedVector3Index].vector = vector; *ioArgIndex = argIndex + 1; return; } } namedVector3s = realloc(namedVector3s, (namedVector3Count + 1) * sizeof(*namedVector3s)); namedVector3s[namedVector3Count].name = argv[++argIndex]; namedVector3s[namedVector3Count++].vector = vector; *ioArgIndex = argIndex; return; } else { fprintf(stderr, "Unrecognized vector3 operation: %s\n", argv[argIndex]); break; } } printVector3f(vector); exit(EXIT_SUCCESS); } static void vector4Loop(int argc, const char ** argv, int * ioArgIndex, Vector4f vector) { for (int argIndex = *ioArgIndex + 1; argIndex < argc; argIndex++) { if (!strcmp(argv[argIndex], "--hex")) { outputHex = true; } else if (!strcmp(argv[argIndex], "--compact")) { outputCompact = true; } else if (!strcmp(argv[argIndex], "normalize")) { Vector4f_normalize(&vector); } else if (!strcmp(argv[argIndex], "normalize_w")) { Vector4f_normalizeW(&vector); } else if (!strcmp(argv[argIndex], "inverse") || !strcmp(argv[argIndex], "invert")) { Vector4f_invert(&vector); } else if (!strcmp(argv[argIndex], "add")) { Vector4f vector2 = readVector4fArgv(&argIndex, argc, argv); vector = Vector4f_add(vector, vector2); } else if (!strcmp(argv[argIndex], "subtract")) { Vector4f vector2 = readVector4fArgv(&argIndex, argc, argv); vector = Vector4f_subtract(vector, vector2); } else if (!strcmp(argv[argIndex], "scale_to")) { float value = readFloatArgv(&argIndex, argc, argv); Vector4f_scaleTo(&vector, value); } else if (!strcmp(argv[argIndex], "multiply_scalar")) { float multiplier = readFloatArgv(&argIndex, argc, argv); vector = Vector4f_multiplyScalar(vector, multiplier); } else if (!strcmp(argv[argIndex], "multiply_vector")) { Vector4f vector2 = readVector4fArgv(&argIndex, argc, argv); vector = Vector4f_multiplyComponents(vector, vector2); } else if (!strcmp(argv[argIndex], "divide_scalar")) { float divisor = readFloatArgv(&argIndex, argc, argv); vector = Vector4f_divideScalar(vector, divisor); } else if (!strcmp(argv[argIndex], "divide_vector")) { Vector4f vector2 = readVector4fArgv(&argIndex, argc, argv); vector = Vector4f_add(vector, vector2); } else if (!strcmp(argv[argIndex], "interpolate")) { Vector4f vector2 = readVector4fArgv(&argIndex, argc, argv); float value = readFloatArgv(&argIndex, argc, argv); vector = Vector4f_interpolate(vector, vector2, value); } else if (!strcmp(argv[argIndex], "round")) { vector = Vector4f_round(vector); } else if (!strcmp(argv[argIndex], "reflect")) { Vector4f vector2 = readVector4fArgv(&argIndex, argc, argv); vector = Vector4f_reflect(vector, vector2); } else if (!strcmp(argv[argIndex], "project")) { Vector4f vector2 = readVector4fArgv(&argIndex, argc, argv); vector = Vector4f_project(vector, vector2); } else if (!strcmp(argv[argIndex], "line_position")) { Vector4f origin = readVector4fArgv(&argIndex, argc, argv); Vector4f normal = readVector4fArgv(&argIndex, argc, argv); vector = Vector4f_positionOnLine(vector, origin, normal); } else if (!strcmp(argv[argIndex], "plane_position")) { Vector4f origin = readVector4fArgv(&argIndex, argc, argv); Vector4f normal = readVector4fArgv(&argIndex, argc, argv); vector = Vector4f_positionOnPlane(vector, origin, normal); } else if (!strcmp(argv[argIndex], "dot")) { Vector4f vector2 = readVector4fArgv(&argIndex, argc, argv); float dot = Vector4f_dot(vector, vector2); printScalar(dot); exit(EXIT_SUCCESS); } else if (!strcmp(argv[argIndex], "magnitude")) { float magnitude = Vector4f_magnitude(vector); printScalar(magnitude); exit(EXIT_SUCCESS); } else if (!strcmp(argv[argIndex], "distance")) { Vector4f vector2 = readVector4fArgv(&argIndex, argc, argv); float distance = Vector4f_distance(vector, vector2); printScalar(distance); exit(EXIT_SUCCESS); } else if (!strcmp(argv[argIndex], "to_barycenter")) { Vector4f vertex0 = readVector4fArgv(&argIndex, argc, argv); Vector4f vertex1 = readVector4fArgv(&argIndex, argc, argv); Vector4f vertex2 = readVector4fArgv(&argIndex, argc, argv); Vector3f barycenter = Vector4f_toBarycenter(vector, vertex0, vertex1, vertex2); printVector3f(barycenter); exit(EXIT_SUCCESS); } else if (!strcmp(argv[argIndex], "multiply_matrix")) { Matrix4x4f matrix = readMatrix4x4fArgv(&argIndex, argc, argv); vector = Matrix4x4f_multiplyVector4f(matrix, vector); } else if (!strcmp(argv[argIndex], "multiply_quaternion")) { Quaternionf quaternion = readQuaternionfArgv(&argIndex, argc, argv); vector = Quaternionf_multiplyVector4f(quaternion, vector); } else if (!strcmp(argv[argIndex], "swizzle")) { restartLoopWithVectorSwizzle(argc, argv, &argIndex, (float *) &vector, 4); *ioArgIndex = argIndex; return; } else if (!strcmp(argv[argIndex], "print")) { printVector4f(vector); } else if (!strcmp(argv[argIndex], "assign")) { if (argc <= argIndex + 1) { fprintf(stderr, "No name specified after assign command\n"); printUsage(); exit(EXIT_FAILURE); } for (unsigned int namedVector4Index = 0; namedVector4Index < namedVector4Count; namedVector4Index++) { if (!strcmp(namedVector4s[namedVector4Index].name, argv[argIndex + 1])) { namedVector4s[namedVector4Index].vector = vector; *ioArgIndex = argIndex + 1; return; } } namedVector4s = realloc(namedVector4s, (namedVector4Count + 1) * sizeof(*namedVector4s)); namedVector4s[namedVector4Count].name = argv[++argIndex]; namedVector4s[namedVector4Count++].vector = vector; *ioArgIndex = argIndex; return; } else { fprintf(stderr, "Unrecognized vector4 operation: %s\n", argv[argIndex]); break; } } printVector4f(vector); exit(EXIT_SUCCESS); } int main(int argc, const char ** argv) { if (!isatty(fileno(stdout))) { outputCompact = true; } for (int argIndex = 1; argIndex < argc; argIndex++) { if (!strcmp(argv[argIndex], "--help")) { if (argc > argIndex + 1) { if (!strcmp(argv[argIndex + 1], "matrix")) { printMatrixUsage(); } else if (!strcmp(argv[argIndex + 1], "quaternion")) { printQuaternionUsage(); } else if (!strcmp(argv[argIndex + 1], "vector2")) { printVector2Usage(); } else if (!strcmp(argv[argIndex + 1], "vector3")) { printVector3Usage(); } else if (!strcmp(argv[argIndex + 1], "vector4")) { printVector4Usage(); } else if (!strcmp(argv[argIndex + 1], "bezier")) { printBezierUsage(); } else { fprintf(stderr, "Unrecognized help section \"%s\"; available help sections are matrix, quaternion, vector2, vector3, vector4, and bezier\n", argv[argIndex + 1]); return EXIT_FAILURE; } } else { printUsage(); } return EXIT_SUCCESS; } if (!strcmp(argv[argIndex], "--hex")) { outputHex = true; } else if (!strcmp(argv[argIndex], "--compact")) { outputCompact = true; } else if (!strcmp(argv[argIndex], "matrix")) { Matrix4x4f matrix = readMatrix4x4fArgv(&argIndex, argc, argv); matrixLoop(argc, argv, &argIndex, matrix); } else if (!strcmp(argv[argIndex], "quaternion")) { Quaternionf quaternion = readQuaternionfArgv(&argIndex, argc, argv); quaternionLoop(argc, argv, &argIndex, quaternion); } else if (!strcmp(argv[argIndex], "vector2")) { Vector2f vector = readVector2fArgv(&argIndex, argc, argv); vector2Loop(argc, argv, &argIndex, vector); } else if (!strcmp(argv[argIndex], "vector3")) { Vector3f vector = readVector3fArgv(&argIndex, argc, argv); vector3Loop(argc, argv, &argIndex, vector); } else if (!strcmp(argv[argIndex], "vector4")) { Vector4f vector = readVector4fArgv(&argIndex, argc, argv); vector4Loop(argc, argv, &argIndex, vector); } else if (!strcmp(argv[argIndex], "bezier")) { Vector2f p0 = readVector2fArgv(&argIndex, argc, argv); Vector2f p1 = readVector2fArgv(&argIndex, argc, argv); Vector2f p2 = readVector2fArgv(&argIndex, argc, argv); Vector2f p3 = readVector2fArgv(&argIndex, argc, argv); for (argIndex++; argIndex < argc; argIndex++) { if (!strcmp(argv[argIndex], "--hex")) { outputHex = true; } else if (!strcmp(argv[argIndex], "--compact")) { outputCompact = true; } else if (!strcmp(argv[argIndex], "sample")) { float value = readFloatArgv(&argIndex, argc, argv); Vector2f result = BezierCurve_sample(p0, p1, p2, p3, value); printVector2f(result); return EXIT_SUCCESS; } else if (!strcmp(argv[argIndex], "sample_at_x")) { float x = readFloatArgv(&argIndex, argc, argv); unsigned int iterations = readUIntArgv(&argIndex, argc, argv); float result = BezierCurve_sampleYAtX(p0, p1, p2, p3, x, iterations); printScalar(result); return EXIT_SUCCESS; } else if (!strcmp(argv[argIndex], "sample_at_y")) { float y = readFloatArgv(&argIndex, argc, argv); unsigned int iterations = readUIntArgv(&argIndex, argc, argv); float result = BezierCurve_sampleXAtY(p0, p1, p2, p3, y, iterations); printScalar(result); return EXIT_SUCCESS; } else { fprintf(stderr, "Unrecognized bezier operation: %s\n", argv[argIndex]); break; } } } else { fprintf(stderr, "Unrecognized argument: %s\n", argv[argIndex]); break; } } printUsage(); return EXIT_FAILURE; }