Преглед изворни кода

Map window commands, color commands

Kajetan Johannes Hammerle пре 1 дан
родитељ
комит
7da6089a51
13 измењених фајлова са 371 додато и 66 уклоњено
  1. 73 0
      examples/window.basic
  2. 7 0
      src/Code.c
  3. 1 0
      src/Code.h
  4. 3 0
      src/Compiler.c
  5. 2 16
      src/Main.c
  6. 75 0
      src/SystemFunctions.c
  7. 28 7
      src/Tokenizer.c
  8. 65 43
      src/Window.c
  9. 9 0
      src/Window.h
  10. 13 0
      test/Color.basic
  11. 9 0
      test/Color.basic_result
  12. 44 0
      test/Constants.basic
  13. 42 0
      test/Constants.basic_result

+ 73 - 0
examples/window.basic

@@ -0,0 +1,73 @@
+print("hi\n")
+
+initWindow(300, 400)
+
+function big(x, y)
+    c = color(20, 0, 31)
+    for ax = 0 to 2
+        for ay = 0 to 2
+            setPixel(x + ax, y + ay, c)
+        end
+    end
+end
+x = 0
+y = 0
+while !shouldClose()
+    nextFrame()
+    clearWindow(color(0, 18, 15))
+
+    c = color(20, 0, 31)
+    if isButtonDown(BT_LEFT)
+        x = x - 1
+    end
+    if isButtonDown(BT_RIGHT)
+        x = x + 1
+    end
+    if isButtonDown(BT_UP)
+        y = y - 1
+    end
+    if isButtonDown(BT_DOWN)
+        y = y + 1
+    end
+    if isButtonDown(BT_START)
+        big(100, 80)
+    end
+    if isButtonDown(BT_SELECT)
+        big(100, 90)
+    end
+    if isButtonDown(BT_A)
+        big(100, 100)
+    end
+    if isButtonDown(BT_B)
+        big(100, 110)
+    end
+    if isButtonDown(BT_X)
+        big(100, 120)
+    end
+    if isButtonDown(BT_Y)
+        big(100, 130)
+    end
+    if isButtonDown(BT_L)
+        big(100, 140)
+    end
+    if isButtonDown(BT_R)
+        big(100, 150)
+    end
+
+    if x < 0
+        x = 0
+    end
+    if x > 237
+        x = 237
+    end
+    if y < 0
+        y = 0
+    end
+    if y > 157
+        y = 157
+    end
+
+    big(x, y)
+end
+
+printLine("stop")

+ 7 - 0
src/Code.c

@@ -125,6 +125,11 @@ static bool iNot(Code* c) {
     return iPushValue(c, INT_VALUE(!a.data));
 }
 
+static bool iInvertSign(Code* c) {
+    POP_VALUE(a);
+    return iPushValue(c, INT_VALUE(-a.data));
+}
+
 static bool iEqual(Code* c) {
     POP_VALUE(a);
     POP_VALUE(b);
@@ -405,6 +410,7 @@ static bool execute(Code* c, Instruction command) {
         case AND: return iAnd(c);
         case OR: return iOr(c);
         case NOT: return iNot(c);
+        case INVERT_SIGN: return iInvertSign(c);
         case EQUAL: return iEqual(c);
         case NOT_EQUAL: return iNotEqual(c);
         case GREATER: return iGreater(c);
@@ -480,6 +486,7 @@ void codeDump(const Code* code) {
             DUMP(AND);
             DUMP(OR);
             DUMP(NOT);
+            DUMP(INVERT_SIGN);
             DUMP(EQUAL);
             DUMP(NOT_EQUAL);
             DUMP(GREATER);

+ 1 - 0
src/Code.h

@@ -46,6 +46,7 @@ typedef enum : u8 {
     AND,
     OR,
     NOT,
+    INVERT_SIGN,
     EQUAL,
     NOT_EQUAL,
     GREATER,

+ 3 - 0
src/Compiler.c

@@ -298,6 +298,9 @@ static void compileUnary(Context* c) {
     if(consumeTokenIf(c, TT_NOT)) {
         compileUnary(c);
         codePushInstruction(c, NOT);
+    } else if(consumeTokenIf(c, TT_SUBTRACT)) {
+        compileUnary(c);
+        codePushInstruction(c, INVERT_SIGN);
     } else {
         compileConstant(c);
     }

+ 2 - 16
src/Main.c

@@ -1,6 +1,5 @@
 #include <stdint.h>
 #include <stdio.h>
-#include <string.h>
 
 #include "Code.h"
 #include "Compiler.h"
@@ -12,22 +11,8 @@
 int main(int argCount, const char** args) {
     if(argCount < 2) {
         return 0;
-    } else if(strcmp(args[1], "w") == 0) {
-        WindowSettings ws = {.width = 400, .height = 300, .title = "Example"};
-        Error e = windowInit(&ws);
-        if(hasError(&e)) {
-            puts(e.text);
-            return 0;
-        }
-        while(!windowShouldClose()) {
-            windowNextFrame();
-        }
-        puts("Stop window");
-        windowDestroy();
-        return 0;
     }
-
-    static char heap[2500];
+    static char heap[4 * 1024 * 1024];
     memoryInit(heap, sizeof(heap));
     // memoryDump();
 
@@ -56,6 +41,7 @@ int main(int argCount, const char** args) {
             puts(codeGetRunError(&code));
         }
         // memoryDump();
+        windowDestroy();
     }
     codeDestroy(&code);
     // memoryDump();

+ 75 - 0
src/SystemFunctions.c

@@ -9,6 +9,7 @@
 
 #include "Memory.h"
 #include "Utils.h"
+#include "Window.h"
 
 #define RETURN_INT(value)  \
     *r = INT_VALUE(value); \
@@ -223,6 +224,69 @@ static bool sfFlush(Code*, Value* r, Value*, i32) {
     RETURN_INT(0);
 }
 
+static bool sfWindowInit(Code* c, Value* r, Value* vs, i32) {
+    WindowSettings ws = {
+        .width = vs[0].data, .height = vs[1].data, .title = "Dummy"};
+    c->error = windowInit(&ws);
+    *r = INT_VALUE(0);
+    return hasError(&c->error);
+}
+
+#define WINDOW_CHECK()                     \
+    do {                                   \
+        if(!windowExists()) {              \
+            SET_ERROR("No window exists"); \
+            return true;                   \
+        }                                  \
+    } while(false)
+
+static bool sfWindowShouldClose(Code* c, Value* r, Value*, i32) {
+    WINDOW_CHECK();
+    RETURN_INT(windowShouldClose());
+}
+
+static bool sfWindowNextFrame(Code* c, Value* r, Value*, i32) {
+    WINDOW_CHECK();
+    windowNextFrame();
+    RETURN_INT(0);
+}
+
+static bool sfWindowClear(Code* c, Value* r, Value* vs, i32) {
+    WINDOW_CHECK();
+    windowClear((Color)vs[0].data);
+    RETURN_INT(0);
+}
+
+static bool sfWindowSetPixel(Code* c, Value* r, Value* vs, i32) {
+    WINDOW_CHECK();
+    windowSetPixel(vs[0].data, vs[1].data, (Color)vs[2].data);
+    RETURN_INT(0);
+}
+
+static bool sfColor(Code*, Value* r, Value* vs, i32) {
+    RETURN_INT(COLOR(vs[0].data, vs[1].data, vs[2].data));
+}
+
+static bool sfGetRed(Code*, Value* r, Value* vs, i32) {
+    RETURN_INT((vs[0].data & 0b1111100000000000) >> 11);
+}
+
+static bool sfGetGreen(Code*, Value* r, Value* vs, i32) {
+    RETURN_INT((vs[0].data & 0b11111000000) >> 6);
+}
+
+static bool sfGetBlue(Code*, Value* r, Value* vs, i32) {
+    RETURN_INT((vs[0].data & 0b111110) >> 1);
+}
+
+static bool sfIsButtonDown(Code*, Value* r, Value* vs, i32) {
+    RETURN_INT(isButtonDown((Button)vs[0].data));
+}
+
+static bool sfGetButtonDownTime(Code*, Value* r, Value* vs, i32) {
+    RETURN_INT(getButtonDownTime((Button)vs[0].data));
+}
+
 typedef struct {
     SystemFunction function;
     i32 arguments;
@@ -251,6 +315,17 @@ static FunctionEntry systemFunctions[] = {
     {sfLeaveRawTerminal, 0, "leaveRawTerminal"},
     {sfReadChar, 0, "readChar"},
     {sfFlush, 0, "flush"},
+    {sfWindowInit, 2, "initWindow"},
+    {sfWindowShouldClose, 0, "shouldClose"},
+    {sfWindowNextFrame, 0, "nextFrame"},
+    {sfWindowClear, 1, "clearWindow"},
+    {sfWindowSetPixel, 3, "setPixel"},
+    {sfColor, 3, "color"},
+    {sfGetRed, 1, "getRed"},
+    {sfGetGreen, 1, "getGreen"},
+    {sfGetBlue, 1, "getBlue"},
+    {sfIsButtonDown, 1, "isButtonDown"},
+    {sfGetButtonDownTime, 1, "getButtonDownTime"},
 };
 static constexpr i32 amount = sizeof(systemFunctions) / sizeof(FunctionEntry);
 

+ 28 - 7
src/Tokenizer.c

@@ -19,6 +19,18 @@ typedef struct {
     Tokenizer* tokenizer;
 } TState;
 
+typedef struct {
+    const char* name;
+    i32 value;
+} Constant;
+
+static const Constant CONSTANTS[] = {
+    {"BT_LEFT", 0},   {"BT_RIGHT", 1}, {"BT_UP", 2}, {"BT_DOWN", 3},
+    {"BT_SELECT", 4}, {"BT_START", 5}, {"BT_A", 6},  {"BT_B", 7},
+    {"BT_X", 8},      {"BT_Y", 9},     {"BT_L", 10}, {"BT_R", 11}};
+static const Constant* CONSTANTS_END =
+    CONSTANTS + sizeof(CONSTANTS) / sizeof(Constant);
+
 #define THROW_ERROR(format, ...)                                   \
     snprintf(                                                      \
         t->error.text, sizeof(t->error.text), "Line %d | " format, \
@@ -43,8 +55,14 @@ static void tAddToken(TState* t, TokenType type) {
     }
 }
 
+static void tAddInt32(TState* t, i32 i) {
+    if(bufferWriteI32(&t->tokenizer->buffer, i)) {
+        tTooMuchTokens(t);
+    }
+}
+
 static bool isLetter(char c) {
-    return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+    return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
 }
 
 static bool isNumber(char c) {
@@ -89,6 +107,13 @@ static const char* tokenizerAddLiteral(TState* t, const char* s) {
     } else if(strcmp(buffer, "continue") == 0) {
         tAddToken(t, TT_CONTINUE);
     } else {
+        for(const Constant* c = CONSTANTS; c != CONSTANTS_END; c++) {
+            if(strcmp(buffer, c->name) == 0) {
+                tAddToken(t, TT_INT32);
+                tAddInt32(t, c->value);
+                return s;
+            }
+        }
         tAddToken(t, TT_LITERAL);
         if(bufferWriteString(&t->tokenizer->buffer, buffer)) {
             tTooMuchTokens(t);
@@ -117,9 +142,7 @@ static const char* tokenizerAddNumber(TState* t, const char* s) {
         tInvalidNumber(t);
     }
     tAddToken(t, TT_INT32);
-    if(bufferWriteI32(&t->tokenizer->buffer, (i32)i)) {
-        tTooMuchTokens(t);
-    }
+    tAddInt32(t, (i32)i);
     return s;
 }
 
@@ -181,9 +204,7 @@ static const char* tokenizerAddChar(TState* t, const char* s) {
     }
     i32 i = convertUTF8toUnicode(buffer);
     tAddToken(t, TT_INT32);
-    if(bufferWriteI32(&t->tokenizer->buffer, i)) {
-        tTooMuchTokens(t);
-    }
+    tAddInt32(t, (i32)i);
     return s;
 }
 

+ 65 - 43
src/Window.c

@@ -14,6 +14,9 @@
 #define STR(x) STR2(x)
 #define STR2(x) #x
 
+#define COLOR(r, g, b)                                           \
+    (((r) & 0x1F) << 11 | ((g) & 0x1F) << 6 | ((b) & 0x1F) << 1)
+
 typedef struct {
     i32 key;
     i32 downTime;
@@ -32,15 +35,21 @@ static GLuint vba = 0;
 static GLuint texture = 0;
 static int width = 0;
 static int height = 0;
-static u8 pixels[HEIGHT][WIDTH][3] = {};
+static u16 pixels[HEIGHT][WIDTH] = {};
 
 static ButtonData buttons[] = {
-    [LEFT] = {0, 0, 0, "Left"},     [RIGHT] = {0, 0, 0, "Right"},
-    [UP] = {0, 0, 0, "Up"},         [DOWN] = {0, 0, 0, "Down"},
-    [SELECT] = {0, 0, 0, "Select"}, [START] = {0, 0, 0, "Start"},
-    [A] = {0, 0, 0, "A"},           [B] = {0, 0, 0, "B"},
-    [X] = {0, 0, 0, "X"},           [Y] = {0, 0, 0, "Y"},
-    [L] = {0, 0, 0, "L"},           [R] = {0, 0, 0, "R"}};
+    [LEFT] = {GLFW_KEY_LEFT, 0, 0, "Left"},
+    [RIGHT] = {GLFW_KEY_RIGHT, 0, 0, "Right"},
+    [UP] = {GLFW_KEY_UP, 0, 0, "Up"},
+    [DOWN] = {GLFW_KEY_DOWN, 0, 0, "Down"},
+    [SELECT] = {GLFW_KEY_Z, 0, 0, "Select"},
+    [START] = {GLFW_KEY_X, 0, 0, "Start"},
+    [A] = {GLFW_KEY_A, 0, 0, "A"},
+    [B] = {GLFW_KEY_S, 0, 0, "B"},
+    [X] = {GLFW_KEY_Q, 0, 0, "X"},
+    [Y] = {GLFW_KEY_W, 0, 0, "Y"},
+    [L] = {GLFW_KEY_1, 0, 0, "L"},
+    [R] = {GLFW_KEY_2, 0, 0, "R"}};
 static constexpr size_t BUTTONS = sizeof(buttons) / sizeof(ButtonData);
 
 // clang-format off
@@ -51,11 +60,12 @@ static const GLchar* VERTEX_SHADER_CODE =
     "out vec2 tex;\n"
     "void main(void) {\n"
     "    tex = pos;\n"
-    "    vec2 w = vec2(" STR(WIDTH) ", " STR(HEIGHT) ");\n"
-    "    ivec2 f = ivec2(size / w);\n"
-    "    f = ivec2(min(f.x, f.y), min(f.x, f.y));\n"
-    "    vec2 f2 = (f * w) / size;\n"
-    "    gl_Position = vec4(pos * f2, 0.0, 1.0);\n"
+    //"    vec2 w = vec2(" STR(WIDTH) ", " STR(HEIGHT) ");\n"
+    //"    ivec2 f = ivec2(size / w);\n"
+    //"    f = ivec2(min(f.x, f.y), min(f.x, f.y));\n"
+    //"    vec2 f2 = (f * w) / size;\n"
+    //"    gl_Position = vec4(pos * f2, 0.0, 1.0);\n"
+    "    gl_Position = vec4(pos, 0.0, 1.0);\n"
     "}\n";
 // clang-format on
 
@@ -65,8 +75,8 @@ static const GLchar* FRAGMENT_SHADER_CODE =
     "in vec2 tex;\n"
     "out vec4 color;\n"
     "void main(void) {\n"
-    "   vec2 c = (tex + vec2(1)) * 0.5;\n"
-    "   color = texture(image, vec2(c.x, 1 - c.y));\n"
+    "   vec2 c = (tex + vec2(1.0)) * 0.5;\n"
+    "   color = texture(image, vec2(c.x, 1.0 - c.y));\n"
     "}\n";
 
 static void onKeyEvent(GLFWwindow*, int key, int, int action, int) {
@@ -101,11 +111,11 @@ static void tickButtons() {
 }
 
 i32 isButtonDown(Button b) {
-    return buttons[b].isDown;
+    return b >= 0 && b < BUTTONS ? buttons[b].isDown : false;
 }
 
 i32 getButtonDownTime(Button b) {
-    return buttons[b].downTime;
+    return b >= 0 && b < BUTTONS ? buttons[b].downTime : 0;
 }
 
 static Error checkShaderErrors(const char* name, GLuint shader) {
@@ -202,48 +212,46 @@ Error windowInit(const WindowSettings* ws) {
 
     glGenTextures(1, &texture);
     glBindTexture(GL_TEXTURE_2D, texture);
-    glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, WIDTH, HEIGHT);
+    glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB5_A1, WIDTH, HEIGHT);
     glTextureParameteri(texture, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     return e;
 }
 
 void windowDestroy() {
-    glDeleteBuffers(1, &vbo);
-    glDeleteVertexArrays(1, &vba);
-    glDeleteShader(vShader);
-    glDeleteShader(fShader);
-    glDeleteProgram(program);
+    if(vbo != 0) {
+        glDeleteBuffers(1, &vbo);
+    }
+    if(vba != 0) {
+        glDeleteVertexArrays(1, &vba);
+    }
+    if(vShader != 0) {
+        glDeleteShader(vShader);
+    }
+    if(fShader != 0) {
+        glDeleteShader(fShader);
+    }
+    if(program != 0) {
+        glDeleteProgram(program);
+    }
     glfwDestroyWindow(window);
     glfwTerminate();
 }
 
+bool windowExists() {
+    return window != nullptr;
+}
+
 void windowNextFrame() {
     glClear(GL_COLOR_BUFFER_BIT);
     glViewport(0, 0, width, height);
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, texture);
-    pixels[5][5][0] = 255;
-    pixels[5][5][1] = 255;
-    pixels[5][5][2] = 255;
-    for(int x = 0; x < WIDTH; x++) {
-        for(int y = 0; y < HEIGHT; y++) {
-            pixels[y][x][0] = 255;
-            pixels[y][x][1] = 255;
-            pixels[y][x][2] = 255;
-        }
-    }
-    for(int y = 0; y < HEIGHT; y++) {
-        pixels[y][WIDTH / 2][0] = 128;
-        pixels[y][WIDTH / 2][1] = 0;
-        pixels[y][WIDTH / 2][2] = 255;
-    }
-    pixels[0][0][0] = 0;
-    pixels[0][0][1] = 0;
-    pixels[0][0][2] = 255;
 
-    glTexSubImage2D(
-        GL_TEXTURE_2D, 0, 0, 0, WIDTH, HEIGHT, GL_RGB, GL_UNSIGNED_BYTE,
+    glTextureSubImage2D(
+        texture, 0, 0, 0, WIDTH, HEIGHT, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1,
         pixels);
 
     GLint size = glGetUniformLocation(program, "size");
@@ -258,10 +266,24 @@ void windowNextFrame() {
 
     auto i = glGetError();
     if(i != 0) {
-        printf("GL-Error: %u\n", i);
+        fprintf(stderr, "GL-Error: %u\n", i);
     }
 }
 
 bool windowShouldClose() {
     return glfwWindowShouldClose(window);
 }
+
+void windowClear(Color c) {
+    for(int x = 0; x < WIDTH; x++) {
+        for(int y = 0; y < HEIGHT; y++) {
+            pixels[y][x] = c;
+        }
+    }
+}
+
+void windowSetPixel(i32 x, i32 y, Color c) {
+    if(y >= 0 && x >= 0 && y < HEIGHT && x < WIDTH) {
+        pixels[y][x] = c;
+    }
+}

+ 9 - 0
src/Window.h

@@ -14,6 +14,7 @@ typedef enum { LEFT, RIGHT, UP, DOWN, SELECT, START, A, B, X, Y, L, R } Button;
 
 Error windowInit(const WindowSettings* ws);
 void windowDestroy();
+bool windowExists();
 
 void windowNextFrame();
 bool windowShouldClose();
@@ -21,4 +22,12 @@ bool windowShouldClose();
 i32 isButtonDown(Button b);
 i32 getButtonDownTime(Button b);
 
+typedef u16 Color;
+
+#define COLOR(r, g, b)                                           \
+    (((r) & 0x1F) << 11 | ((g) & 0x1F) << 6 | ((b) & 0x1F) << 1)
+
+void windowClear(Color c);
+void windowSetPixel(i32 x, i32 y, Color c);
+
 #endif

+ 13 - 0
test/Color.basic

@@ -0,0 +1,13 @@
+a = color(31, 0, 6)
+b = color(20, 3, 8)
+c = color(5, 23, 21)
+
+printLine(getRed(a))
+printLine(getRed(b))
+printLine(getRed(c))
+printLine(getGreen(a))
+printLine(getGreen(b))
+printLine(getGreen(c))
+printLine(getBlue(a))
+printLine(getBlue(b))
+printLine(getBlue(c))

+ 9 - 0
test/Color.basic_result

@@ -0,0 +1,9 @@
+31
+20
+5
+0
+3
+23
+6
+8
+21

+ 44 - 0
test/Constants.basic

@@ -0,0 +1,44 @@
+printLine(BT_LEFT)
+printLine(BT_RIGHT)
+printLine(BT_UP)
+printLine(BT_DOWN)
+printLine(BT_SELECT)
+printLine(BT_START)
+printLine(BT_A)
+printLine(BT_B)
+printLine(BT_X)
+printLine(BT_Y)
+printLine(BT_L)
+printLine(BT_R)
+
+printLine(isButtonDown(-100))
+printLine(isButtonDown(BT_LEFT))
+printLine(isButtonDown(BT_RIGHT))
+printLine(isButtonDown(BT_UP))
+printLine(isButtonDown(BT_DOWN))
+printLine(isButtonDown(BT_SELECT))
+printLine(isButtonDown(BT_START))
+printLine(isButtonDown(BT_A))
+printLine(isButtonDown(BT_B))
+printLine(isButtonDown(BT_X))
+printLine(isButtonDown(BT_Y))
+printLine(isButtonDown(BT_L))
+printLine(isButtonDown(BT_R))
+printLine(isButtonDown(BT_R + 1))
+printLine(isButtonDown(100))
+
+printLine(getButtonDownTime(-100))
+printLine(getButtonDownTime(BT_LEFT))
+printLine(getButtonDownTime(BT_RIGHT))
+printLine(getButtonDownTime(BT_UP))
+printLine(getButtonDownTime(BT_DOWN))
+printLine(getButtonDownTime(BT_SELECT))
+printLine(getButtonDownTime(BT_START))
+printLine(getButtonDownTime(BT_A))
+printLine(getButtonDownTime(BT_B))
+printLine(getButtonDownTime(BT_X))
+printLine(getButtonDownTime(BT_Y))
+printLine(getButtonDownTime(BT_L))
+printLine(getButtonDownTime(BT_R))
+printLine(getButtonDownTime(BT_R + 1))
+printLine(getButtonDownTime(100))

+ 42 - 0
test/Constants.basic_result

@@ -0,0 +1,42 @@
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0