diff --git a/resources/format_conversions.txt b/resources/format_conversions.txt new file mode 100644 index 00000000..b2c24190 --- /dev/null +++ b/resources/format_conversions.txt @@ -0,0 +1,51 @@ +# The worlds worst programming language! +# +# The final result needs to be moved to the "r" variable. The input sample is "x". +# +# Instructions +# ============ +# add [output] [a] [b] -> output = a + b +# sub [output] [a] [b] -> output = a - b +# mul [output] [a] [b] -> output = a * b +# div [output] [a] [b] -> output = a / b +# shl [output] [a] [b] -> output = a << b +# shr [output] [a] [b] -> output = a >> b +# sig [output] [b] -> output = (sign bit in "a" is set) ? 1 : 0 +# mov [output] [a] -> output = a; +# +# int [name] -> Declare an uninitialized 32-bit integer +# flt [name] -> Declare an uninitialized 32-bit float + +# r = (x - 128) << 8 +u8->s16 { + sub r x 128; + shl r r 8; +} + +# r = (x - 128) << 16 +u8->s24 { + sub r x 128; + shl r r 16; +} + +# r = (x - 128) << 24 +u8->s32 { + sub r x 128; + shl r r 24; +} + +# r = (x / 255) * 2 - 1 +u8->f32 { + div r x 255.0; + mul r r 2; + sub r r 1; +} + + +# r = x / (2147483647 + sign(x)) +u32->f32 { + int s; + sig s x; + add s s 2147483647; + div r x (flt)s; +} \ No newline at end of file diff --git a/tools/malgen/source/malgen.cpp b/tools/malgen/source/malgen.cpp new file mode 100644 index 00000000..6416153e --- /dev/null +++ b/tools/malgen/source/malgen.cpp @@ -0,0 +1,357 @@ + +#define DR_IMPLEMENTATION +#include "../../../../../dr_libs/dr.h" + +#include + +typedef struct +{ + const char* name; + const char* params[4]; + int paramCount; +} malgen_instruction; + +typedef struct +{ + const char* formatInStr; + const char* formatOutStr; + std::vector instructions; +} malgen_conversion_desc; + +typedef struct +{ + char* pFormatsFileData; + std::vector conversions; +} malgen_context; + +void u8_to_s16(const unsigned char* px, short* pr, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + int x = px[i]; + + r = x - 128; + r = x << 8; + pr[i] = r; + } +} + +void u8_to_s24(const unsigned char* px, unsigned char* pr, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + int x = px[i]; + + r = x - 128; + r = x << 16; + memcpy(&pr[i*3], &r, 3); + } +} + +void u8_to_s32(const unsigned char* px, int* pr, unsigned int count) +{ + int r; + for (unsigned int i = 0; i < count; ++i) { + int x = px[i]; + + r = x - 128; + r = x << 24; + pr[i] = r; + } +} + +void u8_to_f32(const unsigned char* pIn, float* pOut, unsigned int count) +{ + float r; + int x; + unsigned int i = 0; + + switch ((uintptr_t)pIn & 0x3) + { + case 3: + x = pIn[i]; + r = x / 255.0f; + r = r * 2; + r = r - 1; + pOut[i++] = r; + case 2: + x = pIn[i]; + r = x / 255.0f; + r = r * 2; + r = r - 1; + pOut[i++] = r; + case 1: + x = pIn[i]; + r = x / 255.0f; + r = r * 2; + r = r - 1; + pOut[i++] = r; + } + + while (i+3 < count) { + float r[4]; + int x[4]; + + x[0] = pIn[i+0]; + x[1] = pIn[i+1]; + x[2] = pIn[i+2]; + x[3] = pIn[i+3]; + + r[0] = x[0] / 255.0f; + r[1] = x[1] / 255.0f; + r[2] = x[2] / 255.0f; + r[3] = x[3] / 255.0f; + + r[0] = r[0] * 2; + r[1] = r[1] * 2; + r[2] = r[2] * 2; + r[3] = r[3] * 2; + + r[0] = r[0] - 1; + r[1] = r[1] - 1; + r[2] = r[2] - 1; + r[3] = r[3] - 1; + + pOut[i+0] = r[0]; + pOut[i+1] = r[1]; + pOut[i+2] = r[2]; + pOut[i+3] = r[3]; + + i += 4; + } + + switch (count - i) + { + case 3: + x = pIn[i]; + r = x / 255.0f; + r = r * 2; + r = r - 1; + pOut[i++] = r; + case 2: + x = pIn[i]; + r = x / 255.0f; + r = r * 2; + r = r - 1; + pOut[i++] = r; + case 1: + x = pIn[i]; + r = x / 255.0f; + r = r * 2; + r = r - 1; + pOut[i++] = r; + } +} + +int malgen_compile(malgen_context* pContext) +{ + size_t formatsFileData; + pContext->pFormatsFileData = dr_open_and_read_text_file("../../../resources/format_conversions.txt", &formatsFileData); + if (pContext->pFormatsFileData == NULL) { + printf("Failed to open sample format conversion definitions.\n"); + return -1; + } + + // The first part is going to blank out comments. It just makes the actual parsing soooo much simpler. + char* pRunningStr = pContext->pFormatsFileData; + for (;;) { + if (pRunningStr[0] == '\0') break; + if (pRunningStr[0] == '#') { + while (pRunningStr[0] != '\n') { + if (pRunningStr[0] == '\0') { + break; + } + + pRunningStr[0] = ' '; + pRunningStr += 1; + } + } + pRunningStr += 1; + } + + + malgen_conversion_desc currentFunc; + malgen_instruction currentInst; + memset(¤tInst, 0, sizeof(currentInst)); + int currentParam = 0; + + // Level 0 = not inside a conversion function. + // Level 1 = inside a conversion function. + // Level 2 = inside an instruction (parsing parameters). + int level = 0; + + pRunningStr = pContext->pFormatsFileData; + for (;;) { + if (pRunningStr[0] == '\0') + return 0; + + if (level == 0) { + // Find the first non-whitespace. + for (;;) { + if (pRunningStr[0] == '\0') return 0; + if (!dr_is_whitespace(pRunningStr[0])) { + break; + } + + pRunningStr += 1; + } + + // Find the end of the conversion name. + char* pConversionNameBeg = pRunningStr; + char* pConversionNameEnd = pConversionNameBeg; + for (;;) { + if (pConversionNameEnd[0] == '\0') return -1; + if (dr_is_whitespace(pConversionNameEnd[0])) { + break; + } + + pConversionNameEnd += 1; + } + + pConversionNameEnd[0] = '\0'; + pRunningStr = pConversionNameEnd; + pRunningStr += 1; + + // Find the opening bracket. + for (;;) { + if (pRunningStr[0] == '\0') return -1; + if (pRunningStr[0] == '{') { + currentFunc.formatInStr = pConversionNameBeg; + char* formatInStrEnd = strstr((char*const)currentFunc.formatInStr, "->"); + formatInStrEnd[0] = '\0'; + currentFunc.formatOutStr = formatInStrEnd += 2; + + level += 1; + break; + } + + pRunningStr += 1; + } + } else if (level == 1) { + // Inside a function. + + // Find the first non-whitespace which is where the first instruction should be located. + for (;;) { + if (pRunningStr[0] == '\0') return -1; + if (!dr_is_whitespace(pRunningStr[0])) { + break; + } + + pRunningStr += 1; + } + + // Should be sitting at the name of the next instruction or the closing bracket. + if (pRunningStr[0] == '}') { + pContext->conversions.push_back(currentFunc); + currentFunc.formatInStr = NULL; + currentFunc.formatOutStr = NULL; + currentFunc.instructions.clear(); + pRunningStr += 1; + level -= 1; + continue; + } + + currentInst.name = pRunningStr; + + // Get to the end of the name and null terminate it. + for (;;) { + if (pRunningStr[0] == '\0') return -1; + if (dr_is_whitespace(pRunningStr[0])) { + break; + } + pRunningStr += 1; + } + + pRunningStr[0] = '\0'; + level += 1; + } else if (level == 2) { + // Inside an instruction. + + // Find the first non-whitespace which is where the next parameter should be located. + for (;;) { + if (pRunningStr[0] == '\0') return -1; + if (!dr_is_whitespace(pRunningStr[0])) { + break; + } + pRunningStr += 1; + } + + currentInst.params[currentParam++] = pRunningStr; + currentInst.paramCount += 1; + + // Should be sitting at the next parameter or the semi-colon. + if (pRunningStr[0] == ';') { + currentFunc.instructions.push_back(currentInst); + memset(¤tInst, 0, sizeof(currentInst)); + currentParam = 0; + pRunningStr[0] = '\0'; + pRunningStr += 1; + level -= 1; + continue; + } + + // Get to the end of the name and null terminate it. + for (;;) { + if (pRunningStr[0] == '\0') return -1; + if (dr_is_whitespace(pRunningStr[0])) { + break; + } + + if (pRunningStr[0] == ';') { + currentFunc.instructions.push_back(currentInst); + memset(¤tInst, 0, sizeof(currentInst)); + currentParam = 0; + pRunningStr[0] = '\0'; + pRunningStr += 1; + level -= 1; + break; + } + + pRunningStr += 1; + } + + pRunningStr[0] = '\0'; + } + + pRunningStr += 1; + } + + return 0; +} + +int main(int argc, char** argv) +{ + (void)argc; + (void)argv; + + malgen_context context; + int result = malgen_compile(&context); + if (result != 0) { + return result; + } + + FILE* pOutputFile = dr_fopen("malgen_test0.c", "w"); + if (pOutputFile == NULL) { + printf("Failed to open output file.\n"); + return -2; + } + + + // We need conversion routines for each different combination of formats. + + + + // TESTING + for (size_t i = 0; i < context.conversions.size(); ++i) { + printf("%s to %s\n", context.conversions[i].formatInStr, context.conversions[i].formatOutStr); + for (size_t j = 0; j < context.conversions[i].instructions.size(); ++j) { + printf(" %s", context.conversions[i].instructions[j].name); + for (int k = 0; k < context.conversions[i].instructions[j].paramCount; ++k) { + printf(" %s", context.conversions[i].instructions[j].params[k]); + } + printf("\n"); + } + } + + return 0; +} \ No newline at end of file