diff --git a/update/README.md b/update/README.md index 58c2dc5..ecc7e96 100644 --- a/update/README.md +++ b/update/README.md @@ -1,36 +1,24 @@ # Handmade Math 2.0 Update Tool -Due to the large number of breaking naming changes in Handmade Math 2, we provide a small tool to update your programs automatically. It's a C program that takes a list of files and updates their text, along with some scripts to recursively run the program on all code in a directory. +Due to the large number of breaking naming changes in Handmade Math 2, we provide a small Python script to update your programs automatically. It can run on individual files or on all files in a directory (recursively). -You can compile the tool yourself with any C/C++ compiler: +**Warning!** This tool is not very smart! Please ensure that your work is committed and backed up, in case you have to revert this tool's changes. -```bash -# MSVC (Windows) -cl update_hmm.c - -# gcc -gcc update_hmm.c -o update_hmm - -# clang -clang update_hmm.c -o update_hmm ``` +# see usage info and options +> python3 update_hmm.py -h +usage: update_hmm [-h] [--exts .foo [.foo ...]] filename [filename ...] +... -Once built, the tool can be run on any C or C++ files: +# run on individual files +> python3 update_hmm.py MyPlatformLayer.c MyPlatformLayer.h +Updating: MyPlatformLayer.c +Updating: MyPlatformLayer.h +Updated 2 files with 0 warnings. -```bash -# Windows -update_hmm.exe MyGame.cpp MyPlatformLayer.cpp - -# Other platforms -update_hmm MyGame.cpp MyPlatformLayer.cpp -``` - -Or, update all C/C++ files in a directory by running one of the provided shell scripts: - -```bash -# Windows -update_hmm_all.bat "path\to\project" - -# Other platforms -update_hmm_all.sh path/to/project +# run on a whole directory +> python3 update_hmm.py projects/MyCoolGame +Updating: projects/MyCoolGame/src/MyPlatformLayer.c +Updating: projects/MyCoolGame/include/MyPlatformLayer.h +... ``` diff --git a/update/update_hmm.c b/update/update_hmm.c deleted file mode 100644 index 493a2f6..0000000 --- a/update/update_hmm.c +++ /dev/null @@ -1,569 +0,0 @@ -/* Compile: - Windows (MSVC): cl update_hmm.c - Linux (GCC): gcc update_hmm.c -o update_hmm -*/ - -/** LCF stuff **/ -/* I used my personally library when writing this so I am dumping the necessary things here - so that it's all in one file. */ -#include -#include -#include -#include -/* Types */ -#define global static -#define internal static -typedef int32_t s32; global s32 s32_MAX = 0x7FFFFFFF; global s32 s32_MIN = -1 - 0x7FFFFFFF; -typedef int64_t s64; global s64 s64_MAX = 0x7FFFFFFFFFFFFFFF; global s64 s64_MIN = -1 - 0x7FFFFFFFFFFFFFFF; -typedef uint32_t u32; global u32 u32_MAX = 0xFFFFFFFF; global u32 u32_MIN = 0; -typedef uint64_t u64; global u64 u64_MAX = 0xFFFFFFFFFFFFFFFF; global u64 u64_MIN = 0; -typedef u32 b32; -typedef u64 b64; -#define MIN(a,b) (((a)<(b))?(a):(b)) -#define CLAMPTOP(a,b) MIN(a,b) - -/* Memory */ -struct lcf_Arena { - u64 pos; - u64 size; - u64 alignment; - u64 commited_pos; -}; -typedef struct lcf_Arena Arena; -#define KB(x) ((x) << 10) -#define GB(x) ((x) << 30) -Arena* Arena_create(u64 size); -void* Arena_take(Arena *a, u64 size); -void* Arena_take_custom(Arena *a, u64 size, u64 alignment); -#define Arena_take_array(a, type, count) ((type*) Arena_take(a, sizeof(type)*count)) -void Arena_reset_all(Arena *a); - -#define LCF_MEMORY_PROVIDE_MEMORY "stdlib" -#define LCF_MEMORY_RESERVE_MEMORY(name) void* name(u64 size) -#define LCF_MEMORY_COMMIT_MEMORY(name) b32 name(void* memory, u64 size) -#define LCF_MEMORY_DECOMMIT_MEMORY(name) void name(void* memory, u64 size) -#define LCF_MEMORY_FREE_MEMORY(name) void name(void* memory, u64 size) -/* This implementation of an arena doesn't take advantage of virtual memory at all. - It's just convenient to have something portable so I can use the Arena API I'm used to. */ -internal LCF_MEMORY_RESERVE_MEMORY(_lcf_memory_default_reserve) { - return malloc(size); -} -internal LCF_MEMORY_COMMIT_MEMORY(_lcf_memory_default_commit) { - (void) size, memory; - return 1; /* malloc commits memory automatically */ -} -internal LCF_MEMORY_DECOMMIT_MEMORY(_lcf_memory_default_decommit) { - (void) size, memory; - return; -} -internal LCF_MEMORY_FREE_MEMORY(_lcf_memory_default_free) { - (void) size; - free(memory); -} -#define LCF_MEMORY_reserve _lcf_memory_default_reserve -#define LCF_MEMORY_commit _lcf_memory_default_commit -#define LCF_MEMORY_decommit _lcf_memory_default_decommit -#define LCF_MEMORY_free _lcf_memory_default_free -#define LCF_MEMORY_RESERVE_SIZE GB(1) -#define LCF_MEMORY_COMMIT_SIZE KB(4) - #define LCF_MEMORY_ALIGNMENT (sizeof(void*)) - -Arena* Arena_create(u64 size) { - Arena* a = (Arena*) LCF_MEMORY_reserve(size); - LCF_MEMORY_commit(a, LCF_MEMORY_COMMIT_SIZE); - a->size = size; - a->pos = sizeof(Arena); - a->commited_pos = LCF_MEMORY_COMMIT_SIZE; - a->alignment = LCF_MEMORY_ALIGNMENT; - return a; -} -#define B_PTR(p) (u8*)(p) - -internal b32 is_power_of_2(u64 x) { - return ((x & (x-1)) == 0); -} -internal u64 next_alignment(u64 ptr, u64 alignment) { - /* Fast replacement for mod because alignment is power of 2 */ - u64 modulo = ptr & (alignment-1); - - if (modulo != 0) { - ptr += alignment - modulo; - } - - return ptr; -} -void* Arena_take_custom(Arena *a, u64 size, u64 alignment) { - void* result = 0; - - /* Align pos pointer to check if "size" can fit */ - u64 mem = (u64) a; - u64 aligned_pos = next_alignment(mem + a->pos, alignment) - mem; - u64 new_pos = aligned_pos + size; - - /* Check that there is space */ - if (new_pos < a->size) { - u64 commited_pos = a->commited_pos; - - /* Commit memory if needed */ - if (new_pos > commited_pos) { - u64 new_commited_pos = next_alignment(mem + new_pos, LCF_MEMORY_COMMIT_SIZE)-mem; - if (LCF_MEMORY_commit(a, new_commited_pos)) { - a->commited_pos = commited_pos = new_commited_pos; - } - } - - /* If enough memory is commited, set result and pos. */ - if (new_pos <= commited_pos) { - result = (void*)(mem + aligned_pos); - a->pos = new_pos; - } - } - return result; -} -void* Arena_take(Arena *a, u64 size) { - return Arena_take_custom(a, size, LCF_MEMORY_ALIGNMENT); -} -void Arena_reset_all(Arena *a) { - a->pos = 0; -} - -/* String */ -typedef char chr8; -struct str8 { - u64 len; - chr8 *str; -}; -typedef struct str8 str8; -#define str8_PRINTF_ARGS(s) (int)(s).len, (s).str -#define str8_lit(s) str8_from((chr8*)(s),(u64)sizeof(s)-1) /* -1 to exclude null character */ -#define str8_is_empty(s) ((b32)((s).len == 0)) -#define LCF_STRING_NO_MATCH 0x8000000000000000 -#define str8_iter_custom(s, i, c) \ - s64 i = 0; \ - chr8 c = s.str[i]; \ - for (; (i < (s64) s.len); i++, c = s.str[i]) - -#define str8_iter(s) str8_iter_custom(s, i, c) - -str8 str8_from(chr8* s, u64 len); -str8 str8_from_cstring(chr8 *cstr); -str8 str8_first(str8 s, u64 len); -str8 str8_skip(str8 s, u64 len); -b32 chr8_is_whitespace(chr8 c); -b32 str8_contains_char(str8 s, chr8 c); -u64 str8_char_location(str8 s, chr8 c); - -#define RET_STR8(s,l) \ - str8 _str8; \ - _str8.str = (s); \ - _str8.len = (l); \ - return _str8 -str8 str8_from(chr8* s, u64 len) { - RET_STR8(s, len); -} -str8 str8_from_cstring(chr8 *cstr) { - chr8* p2 = cstr; - while(*p2 != 0) - p2++; - RET_STR8(cstr, (u64)(p2 - cstr)); -} -str8 str8_first(str8 s, u64 len) { - u64 len_clamped = CLAMPTOP(len, s.len); - RET_STR8(s.str, len_clamped); -} -str8 str8_skip(str8 s, u64 len) { - u64 len_clamped = CLAMPTOP(len, s.len); - RET_STR8(s.str + len_clamped, s.len - len_clamped); -} -b32 chr8_is_whitespace(chr8 c) { - switch (c) { - case ' ': - case '\n': - case '\t': - case '\r': - return 1; - default: - return 0; - } -} -b32 str8_contains_char(str8 s, chr8 find) { - return str8_char_location(s,find) != LCF_STRING_NO_MATCH; -} -u64 str8_char_location(str8 s, chr8 find) { - str8_iter(s) { - if (c == find) { - return i; - } - } - return LCF_STRING_NO_MATCH; -} -#undef RET_STR8 - -struct Str8Node { - struct Str8Node *next; - struct str8 str; -}; -struct Str8List { - struct Str8Node *first; - struct Str8Node *last; - u64 count; - u64 total_len; -}; -typedef struct Str8Node Str8Node; -typedef struct Str8List Str8List; - -void Str8List_add_node(Str8List *list, Str8Node *n); -void Str8List_add(Arena *arena, Str8List *list, str8 str); -void Str8List_add_node(Str8List *list, Str8Node *n) { - if (list->last) { - list->last->next = n; - } else { - list->first = n; - } - list->last = n; - list->count++; - list->total_len += n->str.len; -} -void Str8List_add(Arena *arena, Str8List *list, str8 str) { - Str8Node *n = Arena_take_array(arena, Str8Node, 1); - n->str = str; - n->next = 0; - Str8List_add_node(list, n); -} - -/* CRT - stdio */ -str8 stdio_load_entire_file(Arena *arena, str8 filepath); -b32 stdio_write_file(str8 filepath, Str8List text); - -str8 stdio_load_entire_file(Arena *arena, str8 filepath) { - str8 file_content = {0}; - - FILE *file = fopen(filepath.str, "rb"); - if (file != 0) { - fseek(file, 0, SEEK_END); - u64 file_len = ftell(file); - fseek(file, 0, SEEK_SET); - file_content.str = (chr8*) Arena_take(arena, file_len+1); - if (file_content.str != 0) { - file_content.len = file_len; - fread(file_content.str, 1, file_len, file); - file_content.str[file_content.len] = 0; - } - fclose(file); - } - return file_content; -} -b32 stdio_write_file(str8 filepath, Str8List text) { - u64 bytes_written = 0; - FILE *file = fopen(filepath.str, "wb"); - if (file != 0) { - Str8Node* n = text.first; - for (s64 i = 0; i < text.count; i++, n = n->next) { - if (!fwrite(n->str.str, n->str.len, 1, file)) { - break; - } - bytes_written += n->str.len; - } - fclose(file); - } - return bytes_written == text.total_len; -} - -/** HMM2.0 Update Tool **/ -enum Targets { - /* hmm_ and HMM_ prefixes */ - PREFIX_TYPE, PREFIX_FUNCTION, - PREFIXES_Size, - /* Struct/Union types */ - TYPE_VEC, TYPE_MAT, TYPE_QUATERNION, TYPE_BOOL, - TYPE_INTERNAL_ELEMENTS_SSE, - TYPES_Size, - /* Types in Function Names */ - FUN_VEC, FUN_MAT, FUN_QUATERNION, - /* Function Names for Common Operations */ - FUN_EQUALS, FUN_SUBTRACT, FUN_MULTIPLY, FUN_DIVIDE, - FUN_INVERSE, FUN_R_SQUARE_ROOT, FUN_SQUARE_ROOT, - FUN_LENGTH_SQUARED, FUN_LENGTH, FUN_FAST_NORM, FUN_NORM, - FUN_SLERP, FUN_BY, - FUN_LINEAR_COMBINE_SSE, FUN_TRANSPOSE, - FUNCTIONS_Size, - /* Handedness */ - HAND_PERSPECTIVE, HAND_ROTATE, - HAND_ORTHO, HAND_LOOK_AT, HAND_QUAT_AXIS_ANGLE, HAND_MAT_TO_QUAT, - HAND_Size, -}; - -Str8List update_file_content(Arena* arena, str8 file_content) { - Str8List out = {0}; - - str8 Find[HAND_Size]; - str8 Repl[HAND_Size]; - { /* NOTE: Initialization */ - Find[PREFIX_TYPE] = str8_lit("hmm_"); - Find[PREFIX_FUNCTION] = str8_lit("HMM_"); - Repl[PREFIX_TYPE] = Find[PREFIX_FUNCTION]; - - Find[TYPE_VEC] = str8_lit("vec"); - Repl[TYPE_VEC] = str8_lit("Vec"); - Find[TYPE_MAT] = str8_lit("mat"); - Repl[TYPE_MAT] = str8_lit("Mat"); - Find[TYPE_QUATERNION] = str8_lit("quaternion"); - Repl[TYPE_QUATERNION] = str8_lit("Quat"); - Find[TYPE_BOOL] = str8_lit("bool"); - Repl[TYPE_BOOL] = str8_lit("Bool"); - Find[TYPE_INTERNAL_ELEMENTS_SSE] = str8_lit(".InternalElementsSSE"); - Repl[TYPE_INTERNAL_ELEMENTS_SSE] = str8_lit(".SSE"); - - Find[FUN_VEC] = str8_lit("Vec"); - Repl[FUN_VEC] = str8_lit("V"); - Find[FUN_MAT] = str8_lit("Mat"); - Repl[FUN_MAT] = str8_lit("M"); - Find[FUN_QUATERNION] = str8_lit("Quaternion"); - Repl[FUN_QUATERNION] = str8_lit("Q"); - Find[FUN_EQUALS] = str8_lit("Equals"); - Repl[FUN_EQUALS] = str8_lit("Eq"); - Find[FUN_SUBTRACT] = str8_lit("Subtract"); - Repl[FUN_SUBTRACT] = str8_lit("Sub"); - Find[FUN_MULTIPLY] = str8_lit("Multiply"); - Repl[FUN_MULTIPLY] = str8_lit("Mul"); - Find[FUN_DIVIDE] = str8_lit("Divide"); - Repl[FUN_DIVIDE] = str8_lit("Div"); - Find[FUN_INVERSE] = str8_lit("Inverse"); - Repl[FUN_INVERSE] = str8_lit("Inv"); - Find[FUN_R_SQUARE_ROOT] = str8_lit("RSquareRoot"); - Repl[FUN_R_SQUARE_ROOT] = str8_lit("InvSqrt"); - Find[FUN_SQUARE_ROOT] = str8_lit("SquareRoot"); - Repl[FUN_SQUARE_ROOT] = str8_lit("Sqrt"); - Find[FUN_LENGTH_SQUARED] = str8_lit("Squared"); - Repl[FUN_LENGTH_SQUARED] = str8_lit("Sqr"); /* FIXME: not working for some reason */ - Find[FUN_LENGTH] = str8_lit("Length"); - Repl[FUN_LENGTH] = str8_lit("Len"); - - Find[FUN_SLERP] = str8_lit("Slerp"); - Repl[FUN_SLERP] = str8_lit("SLerp"); - Find[FUN_BY] = str8_lit("By"); - Repl[FUN_BY] = str8_lit(""); - Find[FUN_LINEAR_COMBINE_SSE] = str8_lit("LinearCombineSSE"); /* TODO: emit warning */ - Repl[FUN_LINEAR_COMBINE_SSE] = str8_lit("LinearCombineV4M4"); - Find[FUN_TRANSPOSE] = str8_lit("Transpose"); - Repl[FUN_TRANSPOSE] = str8_lit("TransposeM4"); - Find[FUN_FAST_NORM] = str8_lit("Fast"); /* TODO: emit warning, lower precision. */ - Repl[FUN_FAST_NORM] = str8_lit(""); - Find[FUN_NORM] = str8_lit("Normalize"); - Repl[FUN_NORM] = str8_lit("Norm"); - - Find[HAND_PERSPECTIVE] = str8_lit("Perspective"); - Find[HAND_ROTATE] = str8_lit("Rotate"); - Find[HAND_ORTHO] = str8_lit("Orthographic"); - Find[HAND_LOOK_AT] = str8_lit("LookAt"); - Find[HAND_QUAT_AXIS_ANGLE] = str8_lit("FromAxisAngle"); - Find[HAND_MAT_TO_QUAT] = str8_lit("ToQuaternion"); - } - - /* Match with a bunch of sliding windows, skipping when there can't be a match */ - u64 MatchProgress[HAND_Size] = {0}; - b32 FoundTypePrefix = 0; - b32 FoundFunctionPrefix = 0; - u32 Line = 1; - str8_iter(file_content) { - if (c == '\n') { - Line++; - } - if (FoundTypePrefix || FoundFunctionPrefix) { - if (chr8_is_whitespace(c) - || str8_contains_char(str8_lit("(){}[]:;,.<>~?!@#$%^&+-*/'\""), c)) { - FoundTypePrefix = 0; - FoundFunctionPrefix = 0; - } - } - for (u32 t = 0; t < PREFIXES_Size; t++) { - if (c == Find[t].str[MatchProgress[t]]) { - MatchProgress[t]++; - if (MatchProgress[t] == Find[t].len) { - if (t == PREFIX_TYPE) { - FoundTypePrefix = 1; - } else if (t == PREFIX_FUNCTION) { - FoundFunctionPrefix = 1; - } - MatchProgress[t] = 0; - } - } else { - MatchProgress[t] = 0; - } - } - - /* Replace hmm_ types */ - if (FoundTypePrefix) { - for (u32 t = PREFIXES_Size+1; t < TYPES_Size; t++) { - if (c == Find[t].str[MatchProgress[t]]) { - MatchProgress[t]++; - if (MatchProgress[t] == Find[t].len) { - MatchProgress[t] = 0; - printf("\t[%u]: Find: %.*s, Repl: %.*s.\n", Line, str8_PRINTF_ARGS(Find[t]), str8_PRINTF_ARGS(Repl[t])); - Str8List_add(arena, &out, - str8_first(file_content, - i + 1 - (Find[t].len + Find[PREFIX_TYPE].len))); - Str8List_add(arena, &out, Repl[PREFIX_TYPE]); - Str8List_add(arena, &out, Repl[t]); - file_content = str8_skip(file_content, i+1); - i = -1; - } - } else { - MatchProgress[t] = 0; - } - } - } - - /* If in a HMM_ function, do function name replacements */ - if (FoundFunctionPrefix) { - for (u32 t = TYPES_Size+1; t < FUNCTIONS_Size; t++) { - if (c == Find[t].str[MatchProgress[t]]) { - MatchProgress[t]++; - if (MatchProgress[t] == Find[t].len) { - MatchProgress[t] = 0; - printf("\t[%u]: Find: %.*s, Repl: %.*s.\n", Line, str8_PRINTF_ARGS(Find[t]), str8_PRINTF_ARGS(Repl[t])); - Str8List_add(arena, &out, str8_first(file_content, i + 1 - Find[t].len)); - Str8List_add(arena, &out, Repl[t]); - file_content = str8_skip(file_content, i+1); - i = -1; - - /* NOTE(lcf): Special case because Find[] overlaps here */ - if (t == FUN_R_SQUARE_ROOT) { - MatchProgress[FUN_SQUARE_ROOT] = 0; - } - - if (t == FUN_LINEAR_COMBINE_SSE) { - printf("\t[%u]: HMM_LinearCombineSSE is now HMM_LinearCombineV4M4, and will now use a fallback method when SSE is not available. \n\tYou no longer need to check for the availability of SSE.\n", Line); - } - - if (t == FUN_VEC) { - /* NOTE(lcf): if pattern is Vec2i, this is now i */ - c = file_content.str[1]; - if (c == 'i') { - Str8List_add(arena, &out, str8_first(file_content, 1)); - Str8List_add(arena, &out, str8_lit("I")); - file_content = str8_skip(file_content, 2); - } else if (c == 'v') { - Str8List_add(arena, &out, str8_first(file_content, 1)); - Str8List_add(arena, &out, str8_lit("V")); - file_content = str8_skip(file_content, 2); - } else if (c == 'f') { - Str8List_add(arena, &out, str8_first(file_content, 1)); - Str8List_add(arena, &out, str8_lit("F")); - file_content = str8_skip(file_content, 2); - } - } else if (t == FUN_MAT) { - /* if pattern is Mat4d, this is now d */ - c = file_content.str[1]; - if (c == 'd') { - Str8List_add(arena, &out, str8_first(file_content, 1)); - Str8List_add(arena, &out, str8_lit("D")); - file_content = str8_skip(file_content, 2); - } else if (c == 'f') { - Str8List_add(arena, &out, str8_first(file_content, 1)); - Str8List_add(arena, &out, str8_lit("F")); - file_content = str8_skip(file_content, 2); - } - } - } - } else { - MatchProgress[t] = 0; - } - } - } - - /* Handedness cases. */ - if (FoundFunctionPrefix) { - for (u32 t = FUNCTIONS_Size+1; t < HAND_Size; t++) { - if (c == Find[t].str[MatchProgress[t]]) { - MatchProgress[t]++; - if (MatchProgress[t] == Find[t].len) { - MatchProgress[t] = 0; - - chr8 check = file_content.str[i+1]; - if (check == '(') { - Str8List_add(arena, &out, str8_first(file_content, i + 1)); - - if (t == HAND_PERSPECTIVE || t == HAND_ORTHO) { - printf("\t[%u]: Appending _N0 for old default NDC.\n", Line, str8_PRINTF_ARGS(Find[t])); - Str8List_add(arena, &out, str8_lit("_N0")); - } - - printf("\t[%u]: Find: %.*s, Appending: _RH for old default handedness.\n", Line, str8_PRINTF_ARGS(Find[t])); - - Str8List_add(arena, &out, str8_lit("_RH(")); - file_content = str8_skip(file_content, i+2); - i = -1; - - if (t == HAND_PERSPECTIVE || t == HAND_ROTATE) { - printf("\t[%u]: ", Line); - if (t == HAND_PERSPECTIVE) { - printf("HMM_Perspective_RH()"); - } else { - printf("HMM_Rotate_RH()"); - } - printf(" now takes Radians. Wrapping Degrees with HMM_AngleDeg()\n"); - u64 end_arg = str8_char_location(file_content, ','); - if (end_arg != LCF_STRING_NO_MATCH) { - Str8List_add(arena, &out, str8_lit("HMM_AngleDeg(")); - Str8List_add(arena, &out, str8_first(file_content, end_arg)); - Str8List_add(arena, &out, str8_lit(")")); - file_content = str8_skip(file_content, end_arg); - } - } - } - } - } else { - MatchProgress[t] = 0; - } - } - } - } - - Str8List_add(arena, &out, file_content); - - return out; -} - -void print_usage() { - printf("Updates C and C++ source code to use Handmade Math version 2.\n"); -#ifdef _WIN32 - printf("Usage: update_hmm.exe [...]\n"); -#else - printf("Usage: update_hmm [...]\n"); -#endif -} - -int main(int argc, char* argv[]) { - Arena *tempa = Arena_create(GB(1)); - - if (argc == 1) { - print_usage(); - return 1; - } - - s32 argi = 1; - str8 arg = str8_from_cstring(argv[argi]); - - if (arg.len == 2 && (arg.str[1] == 'h' || arg.str[1] == '?')) { - print_usage(); - return 0; - } - - for (; argi < argc; argi++) { - arg = str8_from_cstring(argv[argi]); - str8 file_content = stdio_load_entire_file(tempa, arg); - if (str8_is_empty(file_content)) { - printf("X - Invalid file name: %.*s\n\n", str8_PRINTF_ARGS(arg)); - continue; - } - printf("O - Updating file: %.*s -------------------\n", str8_PRINTF_ARGS(arg)); - Str8List result = update_file_content(tempa, file_content); - printf("\n"); - stdio_write_file(arg, result); - - Arena_reset_all(tempa); - } - - return 0; -} diff --git a/update/update_hmm.py b/update/update_hmm.py new file mode 100755 index 0000000..71b82e6 --- /dev/null +++ b/update/update_hmm.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python3 + +import argparse +import os +import re + +typeReplacements = [ + ('hmm_', 'HMM_'), + + ('vec', 'Vec'), + ('mat', 'Mat'), + ('quaternion', 'Quaternion'), + ('bool', 'Bool'), + ('.InternalElementsSSE', '.SSE'), +] + +funcReplacements = [ + ('HMM_', 'HMM_'), + + ('Vec', 'V'), + ('Mat', 'M'), + ('Quaternion', 'Q'), + ('Equals', 'Eq'), + ('Subtract', 'Sub'), + ('Multiply', 'Mul'), + ('Divide', 'Div'), + ('Inverse', 'Inv'), + ('RSquareRoot', 'InvSqrt'), + ('SquareRoot', 'Sqrt'), + ('Squared', 'Sqr'), + ('Length', 'Len'), + + ('Slerp', 'SLerp'), + ('By', ''), + ('LinearCombineSSE', 'LinearCombineV4M4'), + ('Transpose', 'TransposeM4'), + ('Fast', ''), # TODO(port): emit warning, lower precision + ('Normalize', 'Norm'), + ('ToRadians', 'ToRad') +] + +handedFuncs = [ + 'Perspective', + 'Rotate', + 'Orthographic', + 'LookAt', + 'FromAxisAngle', + 'ToQuaternion', +] + +projectionFuncs = [ + 'Perspective', + 'Orthographic', +] + +numFiles = 0 +numWarnings = 0 + +def printWarning(msg): + global numWarnings + numWarnings += 1 + print('WARNING: {}'.format(msg)) + +def updateFile(filename): + global numFiles + print('Updating: {}'.format(filename)) + numFiles += 1 + result = '' + with open(filename, 'r', newline='') as f: + for lineNo, line in enumerate(f): + updatedLine = line + + def printLineWarning(msg): + printWarning(' Line {}: {}'.format(lineNo + 1, msg)) + + def replaceName(m): + name = m.group() + if name.startswith('hmm_'): + # do type replacements + for before, after in typeReplacements: + if before not in name: + continue + name = name.replace(before, after) + else: + # do func replacements + for before, after in funcReplacements: + if before not in name: + continue + name = name.replace(before, after) + + if after == 'LinearCombineV4M4': + printLineWarning('HMM_LinearCombineSSE is now HMM_LinearCombineV4M4, and will now use a fallback method when SSE is not available. You no longer need to check for the availability of SSE.') + if after == 'V' or after == 'M': + # uppercase the modifier, if any + name = re.sub( + r'[VM]\d[ivfd]?', + lambda m: m.group().upper(), + name + ) + # and also nuke the integer constructors + vecIntMatch = re.search(r'(V\d)I', name) + if vecIntMatch: + name = name.replace(vecIntMatch.group(), vecIntMatch.group(1)) + + # add handedness / NDC modifiers + if not any(x in name for x in ['RH', 'LH', 'NO', 'ZO']): + for handedFunc in handedFuncs: + suffixed = handedFunc + '_RH' + if handedFunc in projectionFuncs: + suffixed += '_NO' + name = name.replace(handedFunc, suffixed) + return name + + def wrapDegrees(m): + name = m.group('name') + arg = m.group('arg') + if '(' in arg: + # all bets are off, don't wrap the argument + printLineWarning('{} now takes radians, but we were unable to automatically wrap the first argument with HMM_AngleDeg().'.format(name)) + return m.group() + return '{}(HMM_AngleDeg({}),'.format(name, arg) + + updatedLine = re.sub(r'(hmm_|HMM_)\w+', replaceName, updatedLine) + updatedLine = re.sub(r'(?PHMM_Perspective_RH_NO|HMM_Rotate_RH)\((?P.*?),', wrapDegrees, updatedLine) + + result += updatedLine + + with open(filename, 'w', newline='') as f: + f.write(result) + + +parser = argparse.ArgumentParser( + prog = 'update_hmm', + description = 'Updates C and C++ source code to use Handmade Math 2.0.', +) +parser.add_argument( + 'filename', nargs='+', + help='A file or directory to update to HMM 2.0. If a directory, all files with extensions from --exts will be processed.', +) +parser.add_argument( + '--exts', nargs='+', default=['.c', '.cpp', '.h', '.hpp'], + help='File extensions to run the script on, when targeting a directory. Default: .c, .cpp, .h, .hpp.', + metavar='.foo', +) + +args = parser.parse_args() + +for path in args.filename: + filenames = [] + if os.path.isfile(path): + filenames = [path] + else: + for root, dirs, files in os.walk(path): + for file in files: + if file == 'HandmadeMath.h': + printWarning('HandmadeMath.h will not be replaced by this script.') + elif file.endswith(tuple(args.exts)): + filenames.append(os.path.join(root, file)) + + for filename in filenames: + try: + updateFile(filename) + except UnicodeDecodeError: + pass + + print('Updated {} files with {} warnings.'.format(numFiles, numWarnings)) diff --git a/update/update_hmm_all.bat b/update/update_hmm_all.bat deleted file mode 100644 index cb9e0ce..0000000 --- a/update/update_hmm_all.bat +++ /dev/null @@ -1,12 +0,0 @@ -@REM Batch script to run update_hmm.exe on all your code files. -@REM Example: -@REM "update_hmm_all.bat Code\Project\" -> Recursively update all files/folders in .\Code\Project\ - -for /r %1 %%v in (*.c) do update_hmm.exe "%%v" -for /r %1 %%v in (*.h) do update_hmm.exe "%%v" -for /r %1 %%v in (*.cpp) do update_hmm.exe "%%v" -for /r %1 %%v in (*.hpp) do update_hmm.exe "%%v" - -@REM @REM Uncomment for sokol-samples -@REM for /r %1 %%v in (*.glsl) do update_hmm.exe "%%v" -@REM for /r %1 %%v in (*.hlsl) do update_hmm.exe "%%v" diff --git a/update/update_hmm_all.sh b/update/update_hmm_all.sh deleted file mode 100644 index 497ab69..0000000 --- a/update/update_hmm_all.sh +++ /dev/null @@ -1,12 +0,0 @@ -# Bash script to run update_hmm on all your code files. -# Example: -# "update_hmm_all Code/Project/" -> Recursively update all files/folders in ./Code/Project/ -echo $1 -for file in "$1"/*.{c,h,cpp,hpp} "$1"/**/*.{c,h,cpp,hpp} ; do - ./update_hmm "$file" -done - -# # Uncomment for sokol-samples -# for file in "$1"/*.{glsl,hlsl} "$1"/**/*.{glsl,hlsl} ; do - # ./update_hmm "$file" -# done