Extend grogs, better example program
This commit is contained in:
		
							
								
								
									
										183
									
								
								grogs/README.md
									
									
									
									
									
								
							
							
						
						
									
										183
									
								
								grogs/README.md
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| # grogs (Ground graphics) library | ||||
|  | ||||
| This library uses SDL3 to add graphics support to Ground. | ||||
| This library uses SDL3 to add graphics support to Ground, including window management, event handling, and simple 2D drawing. | ||||
|  | ||||
| ## Compiling | ||||
|  | ||||
| @@ -10,50 +10,181 @@ First, ensure SDL3 is installed on your system. Then: | ||||
| g++ -shared -fPIC -lSDL3 -o grogs.so grogs.cpp | ||||
| ``` | ||||
|  | ||||
| Or with pkg-config: | ||||
|  | ||||
| ```bash | ||||
| g++ -shared -fPIC $(pkg-config --cflags --libs sdl3) -o grogs.so grogs.cpp | ||||
| ``` | ||||
|  | ||||
| ## Functions | ||||
|  | ||||
| ### fun -int !initSDL -string &windowTitle -int &width -int &height | ||||
| ### Window Management | ||||
|  | ||||
| This function initialises SDL for use in Grogs. **This must be run before trying to run any other Grogs functions!** | ||||
| #### `fun -int !initSDL -string &windowTitle -int &width -int &height` | ||||
|  | ||||
| First argument is the window title, second and third are width and height of the window, respectively. | ||||
| Initializes SDL and creates a window. **This must be run before any other Grogs functions!** | ||||
|  | ||||
| If everything goes fine, returns 0. | ||||
| **Arguments:** | ||||
| - `windowTitle`: Title of the window | ||||
| - `width`: Window width in pixels | ||||
| - `height`: Window height in pixels | ||||
|  | ||||
| If SDL couldn't create the window, returns 1. If already initialized, returns 2. | ||||
|  | ||||
| Example: | ||||
| **Returns:** | ||||
| - `0`: Success | ||||
| - `1`: SDL initialization or window creation failed | ||||
| - `2`: Already initialized | ||||
|  | ||||
| **Example:** | ||||
| ``` | ||||
| pusharg "My Awesome Window" 640 480 | ||||
| !grogs:initSDL &result | ||||
| pusharg "My Awesome Window" 800 600 | ||||
| call !grogs:initSDL &result | ||||
| ``` | ||||
|  | ||||
| ### fun -int !pollEvent | ||||
| #### `fun -int !getWindowSize -int &dimension` | ||||
|  | ||||
| Returns a code for an event that has been polled. For now, only window closing is supported, which will return 0. Anything else for now will return -1. | ||||
| Gets window dimensions. | ||||
|  | ||||
| ### fun -int !clearRenderer | ||||
| **Arguments:** | ||||
| - `dimension`: `0` for width, `1` for height | ||||
|  | ||||
| Clears the renderer of any pixels to be rendered. Returns 0, unless SDL is not initialized. | ||||
| **Returns:** The requested dimension, or `-1` if not initialized. | ||||
|  | ||||
| ### fun -int !renderFrame | ||||
| #### `fun -int !cleanup` | ||||
|  | ||||
| Renders frame on the screen. Whichever pixels have been set will be displayed. Returns 0, unless SDL is not initialized. | ||||
| Properly cleans up SDL resources. Call this before your program exits. | ||||
|  | ||||
| ### fun -int !setPixel -int &xpos -int &ypos -int &red -int &green -int &blue | ||||
| **Returns:** Always `0` | ||||
|  | ||||
| Sets a pixel at the desired location to the desired colour. Returns 0, unless SDL is not initialized. | ||||
| ### Event Handling | ||||
|  | ||||
| First argument: xpos | ||||
| Second argument: ypos | ||||
| Third argument: red value (0 to 255) | ||||
| Fourth argument: green value (0 to 255) | ||||
| Fifth argument: blue value (0 to 255) | ||||
| #### `fun -int !pollEvent` | ||||
|  | ||||
| This example sets the pixel at (10, 10) to white (RGB(255, 255, 255)): | ||||
| Polls for SDL events and returns event type codes. | ||||
|  | ||||
| **Returns:** | ||||
| - `0`: Quit event (window closed) | ||||
| - `1`: Key pressed down | ||||
| - `2`: Key released | ||||
| - `3`: Mouse button pressed | ||||
| - `4`: Mouse button released | ||||
| - `5`: Mouse moved | ||||
| - `6`: Other event | ||||
| - `-1`: No event | ||||
|  | ||||
| #### `fun -int !getLastKey` | ||||
|  | ||||
| Gets the key code of the last key event (after calling `pollEvent`). | ||||
|  | ||||
| **Returns:** SDL key code, or `-1` if no key event or not initialized. | ||||
|  | ||||
| #### `fun -int !getMousePos -int &coord` | ||||
|  | ||||
| Gets current mouse position. | ||||
|  | ||||
| **Arguments:** | ||||
| - `coord`: `0` for X coordinate, `1` for Y coordinate | ||||
|  | ||||
| **Returns:** Mouse coordinate, or `-1` if not initialized. | ||||
|  | ||||
| ### Rendering | ||||
|  | ||||
| #### `fun -int !clearRenderer [optional: -int &red -int &green -int &blue]` | ||||
|  | ||||
| Clears the renderer. Optionally specify background color. | ||||
|  | ||||
| **Arguments (optional):** | ||||
| - `red`: Red value (0-255) | ||||
| - `green`: Green value (0-255) | ||||
| - `blue`: Blue value (0-255) | ||||
|  | ||||
| **Returns:** `0` on success, `-1` if not initialized. | ||||
|  | ||||
| **Examples:** | ||||
| ``` | ||||
| pusharg 10 10 255 255 255 | ||||
| call !grogs:setPixel &result | ||||
| # Clear to black (default) | ||||
| call !grogs:clearRenderer &result | ||||
|  | ||||
| # Clear to blue background | ||||
| pusharg 0 100 200 | ||||
| call !grogs:clearRenderer &result | ||||
| ``` | ||||
|  | ||||
| #### `fun -int !renderFrame` | ||||
|  | ||||
| Presents the rendered frame to the screen. | ||||
|  | ||||
| **Returns:** `0` on success, `-1` if not initialized. | ||||
|  | ||||
| ### Drawing Functions | ||||
|  | ||||
| #### `fun -int !setPixel -int &x -int &y -int &red -int &green -int &blue` | ||||
|  | ||||
| Sets a single pixel to the specified color. | ||||
|  | ||||
| **Arguments:** | ||||
| - `x`, `y`: Pixel coordinates | ||||
| - `red`, `green`, `blue`: Color values (0-255, automatically clamped) | ||||
|  | ||||
| **Returns:** `0` on success, `-1` if not initialized or out of bounds. | ||||
|  | ||||
| #### `fun -int !drawLine -int &x1 -int &y1 -int &x2 -int &y2 -int &red -int &green -int &blue` | ||||
|  | ||||
| Draws a line between two points. | ||||
|  | ||||
| **Arguments:** | ||||
| - `x1`, `y1`: Start point coordinates | ||||
| - `x2`, `y2`: End point coordinates | ||||
| - `red`, `green`, `blue`: Line color (0-255) | ||||
|  | ||||
| **Returns:** `0` on success, `-1` if not initialized. | ||||
|  | ||||
| #### `fun -int !drawRect -int &x -int &y -int &width -int &height -int &red -int &green -int &blue` | ||||
|  | ||||
| Draws a filled rectangle. | ||||
|  | ||||
| **Arguments:** | ||||
| - `x`, `y`: Top-left corner coordinates | ||||
| - `width`, `height`: Rectangle dimensions | ||||
| - `red`, `green`, `blue`: Fill color (0-255) | ||||
|  | ||||
| **Returns:** `0` on success, `-1` if not initialized or invalid dimensions. | ||||
|  | ||||
| #### `fun -int !drawRectOutline -int &x -int &y -int &width -int &height -int &red -int &green -int &blue` | ||||
|  | ||||
| Draws a rectangle outline (border only). | ||||
|  | ||||
| **Arguments:** Same as `drawRect` | ||||
|  | ||||
| **Returns:** `0` on success, `-1` if not initialized or invalid dimensions. | ||||
|  | ||||
| #### `fun -int !drawCircle -int ¢erX -int ¢erY -int &radius -int &red -int &green -int &blue` | ||||
|  | ||||
| Draws a filled circle. | ||||
|  | ||||
| **Arguments:** | ||||
| - `centerX`, `centerY`: Circle center coordinates | ||||
| - `radius`: Circle radius in pixels | ||||
| - `red`, `green`, `blue`: Fill color (0-255) | ||||
|  | ||||
| **Returns:** `0` on success, `-1` if not initialized or invalid radius. | ||||
|  | ||||
| ### Utility Functions | ||||
|  | ||||
| #### `fun -int !delay -int &milliseconds` | ||||
|  | ||||
| Pauses execution for the specified time. Useful for frame rate control. | ||||
|  | ||||
| **Arguments:** | ||||
| - `milliseconds`: Delay duration | ||||
|  | ||||
| **Returns:** `0` on success, `-1` if negative value provided. | ||||
|  | ||||
| ## Error Handling | ||||
|  | ||||
| All functions return status codes. Always check return values: | ||||
| - `0`: Success | ||||
| - `1`: SDL-specific error | ||||
| - `2`: Already initialized (initSDL only) | ||||
| - `-1`: General error (not initialized, invalid parameters, out of bounds, etc.) | ||||
|  | ||||
| Functions that require SDL to be initialized will print error messages and return `-1` if called before `initSDL`. | ||||
|   | ||||
							
								
								
									
										301
									
								
								grogs/grogs.cpp
									
									
									
									
									
								
							
							
						
						
									
										301
									
								
								grogs/grogs.cpp
									
									
									
									
									
								
							| @@ -2,55 +2,140 @@ | ||||
| #include <SDL3/SDL.h> | ||||
| #include <SDL3/SDL_main.h> | ||||
| #include <SDL3/SDL_render.h> | ||||
| #include <iostream> | ||||
|  | ||||
| SDL_Window* window; | ||||
| SDL_Renderer* renderer; | ||||
| SDL_Window* window = nullptr; | ||||
| SDL_Renderer* renderer = nullptr; | ||||
| SDL_Event event; | ||||
|  | ||||
| int width; | ||||
| int height; | ||||
| int width = 0; | ||||
| int height = 0; | ||||
| bool hasRunInit = false; | ||||
|  | ||||
| bool hasRunInit; | ||||
| // Helper function to clamp values | ||||
| int clamp(int value, int min, int max) { | ||||
|     if (value < min) return min; | ||||
|     if (value > max) return max; | ||||
|     return value; | ||||
| } | ||||
|  | ||||
| // Initialize SDL and create window | ||||
| GroundValue initSDL(GroundValue* args, int arg_count) { | ||||
|     if (hasRunInit) return GROUND_INT_VAL(2); | ||||
|  | ||||
|     // args are window title, width, height | ||||
|     VALIDATE_ARGS_3(GROUND_STRING, GROUND_INT, GROUND_INT); | ||||
|     SDL_Init(SDL_INIT_VIDEO); | ||||
|     width = GET_INT(args[1]); | ||||
|     height = GET_INT(args[2]); | ||||
|     SDL_CreateWindowAndRenderer(GET_STRING(args[0]), width, height, SDL_WINDOW_OPENGL, &window, &renderer); | ||||
|     if (window == NULL) { | ||||
|         std::cout << "Couldn't create SDL window" << std::endl; | ||||
|  | ||||
|     if (SDL_Init(SDL_INIT_VIDEO) < 0) { | ||||
|         std::cout << "SDL could not initialize! SDL Error: " << SDL_GetError() << std::endl; | ||||
|         return GROUND_INT_VAL(1); | ||||
|     } | ||||
|  | ||||
|     width = GET_INT(args[1]); | ||||
|     height = GET_INT(args[2]); | ||||
|  | ||||
|     // Validate dimensions | ||||
|     if (width <= 0 || height <= 0) { | ||||
|         std::cout << "Invalid window dimensions" << std::endl; | ||||
|         SDL_Quit(); | ||||
|         return GROUND_INT_VAL(1); | ||||
|     } | ||||
|  | ||||
|     if (SDL_CreateWindowAndRenderer(GET_STRING(args[0]), width, height, | ||||
|                                    SDL_WINDOW_OPENGL, &window, &renderer) < 0) { | ||||
|         std::cout << "Window could not be created! SDL Error: " << SDL_GetError() << std::endl; | ||||
|         SDL_Quit(); | ||||
|         return GROUND_INT_VAL(1); | ||||
|     } | ||||
|  | ||||
|     hasRunInit = true; | ||||
|     return GROUND_INT_VAL(0); | ||||
| } | ||||
|  | ||||
| // Poll for events (enhanced with more event types) | ||||
| GroundValue pollEvent(GroundValue* args, int arg_count) { | ||||
|     if (!hasRunInit) { | ||||
|         std::cout << "Cannot poll event, please run !grogs:initSDL first" << std::endl; | ||||
|         return GROUND_INT_VAL(-1); | ||||
|     } | ||||
|  | ||||
|     SDL_PollEvent(&event); | ||||
|     if (event.type == SDL_EVENT_QUIT) { | ||||
|         return GROUND_INT_VAL(0); | ||||
|     if (SDL_PollEvent(&event)) { | ||||
|         switch (event.type) { | ||||
|             case SDL_EVENT_QUIT: | ||||
|                 return GROUND_INT_VAL(0); | ||||
|             case SDL_EVENT_KEY_DOWN: | ||||
|                 return GROUND_INT_VAL(1); | ||||
|             case SDL_EVENT_KEY_UP: | ||||
|                 return GROUND_INT_VAL(2); | ||||
|             case SDL_EVENT_MOUSE_BUTTON_DOWN: | ||||
|                 return GROUND_INT_VAL(3); | ||||
|             case SDL_EVENT_MOUSE_BUTTON_UP: | ||||
|                 return GROUND_INT_VAL(4); | ||||
|             case SDL_EVENT_MOUSE_MOTION: | ||||
|                 return GROUND_INT_VAL(5); | ||||
|             default: | ||||
|                 return GROUND_INT_VAL(6); // Other event | ||||
|         } | ||||
|     } | ||||
|     return GROUND_INT_VAL(-1); // No event | ||||
| } | ||||
|  | ||||
| // Get last key pressed (requires polling events first) | ||||
| GroundValue getLastKey(GroundValue* args, int arg_count) { | ||||
|     if (!hasRunInit) { | ||||
|         std::cout << "Cannot get key, please run !grogs:initSDL first" << std::endl; | ||||
|         return GROUND_INT_VAL(-1); | ||||
|     } | ||||
|  | ||||
|     if (event.type == SDL_EVENT_KEY_DOWN || event.type == SDL_EVENT_KEY_UP) { | ||||
|         return GROUND_INT_VAL(event.key.key); | ||||
|     } | ||||
|     return GROUND_INT_VAL(-1); | ||||
| } | ||||
|  | ||||
| // Get mouse position | ||||
| GroundValue getMousePos(GroundValue* args, int arg_count) { | ||||
|     if (!hasRunInit) { | ||||
|         std::cout << "Cannot get mouse position, please run !grogs:initSDL first" << std::endl; | ||||
|         return GROUND_INT_VAL(-1); | ||||
|     } | ||||
|  | ||||
|     VALIDATE_ARGS_1(GROUND_INT); | ||||
|     int coord = GET_INT(args[0]); // 0 for x, 1 for y | ||||
|  | ||||
|     float mouseX, mouseY; | ||||
|     SDL_GetMouseState(&mouseX, &mouseY); | ||||
|  | ||||
|     if (coord == 0) { | ||||
|         return GROUND_INT_VAL((int)mouseX); | ||||
|     } else if (coord == 1) { | ||||
|         return GROUND_INT_VAL((int)mouseY); | ||||
|     } | ||||
|     return GROUND_INT_VAL(-1); | ||||
| } | ||||
|  | ||||
| // Clear renderer with optional color | ||||
| GroundValue clearRenderer(GroundValue* args, int arg_count) { | ||||
|     if (!hasRunInit) { | ||||
|         std::cout << "Cannot clear renderer, please run !grogs:initSDL first" << std::endl; | ||||
|         return GROUND_INT_VAL(-1); | ||||
|     } | ||||
|  | ||||
|     if (arg_count == 3) { | ||||
|         VALIDATE_ARGS_3(GROUND_INT, GROUND_INT, GROUND_INT); | ||||
|         int r = clamp(GET_INT(args[0]), 0, 255); | ||||
|         int g = clamp(GET_INT(args[1]), 0, 255); | ||||
|         int b = clamp(GET_INT(args[2]), 0, 255); | ||||
|         SDL_SetRenderDrawColor(renderer, r, g, b, 255); | ||||
|     } else { | ||||
|         // Default to black | ||||
|         SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); | ||||
|     } | ||||
|  | ||||
|     SDL_RenderClear(renderer); | ||||
|     return GROUND_INT_VAL(0); | ||||
| } | ||||
|  | ||||
| // Render frame to screen | ||||
| GroundValue renderFrame(GroundValue* args, int arg_count) { | ||||
|     if (!hasRunInit) { | ||||
|         std::cout << "Cannot render frame, please run !grogs:initSDL first" << std::endl; | ||||
| @@ -60,21 +145,185 @@ GroundValue renderFrame(GroundValue* args, int arg_count) { | ||||
|     return GROUND_INT_VAL(0); | ||||
| } | ||||
|  | ||||
| // Set a single pixel | ||||
| GroundValue setPixel(GroundValue* args, int arg_count) { | ||||
|     if (!hasRunInit) { | ||||
|         std::cout << "Cannot set pixel, please run !grogs:initSDL first" << std::endl; | ||||
|         return GROUND_INT_VAL(-1); | ||||
|     } | ||||
|     VALIDATE_ARGS_5(GROUND_INT, GROUND_INT, GROUND_INT, GROUND_INT, GROUND_INT); | ||||
|     // xpos, ypos, red, green, blue | ||||
|  | ||||
|     int pixelX = GET_INT(args[0]); | ||||
|     int pixelY = GET_INT(args[1]); | ||||
|     int red = GET_INT(args[2]); | ||||
|     int green = GET_INT(args[3]); | ||||
|     int blue = GET_INT(args[4]); | ||||
|     SDL_SetRenderDrawColor(renderer, red, green, blue, 255); | ||||
|     SDL_RenderPoint(renderer, pixelX, pixelY); | ||||
|     int red = clamp(GET_INT(args[2]), 0, 255); | ||||
|     int green = clamp(GET_INT(args[3]), 0, 255); | ||||
|     int blue = clamp(GET_INT(args[4]), 0, 255); | ||||
|  | ||||
|     // Bounds checking | ||||
|     if (pixelX < 0 || pixelX >= width || pixelY < 0 || pixelY >= height) { | ||||
|         return GROUND_INT_VAL(-1); // Out of bounds | ||||
|     } | ||||
|  | ||||
|     SDL_SetRenderDrawColor(renderer, red, green, blue, 255); | ||||
|     SDL_RenderPoint(renderer, (float)pixelX, (float)pixelY); | ||||
|  | ||||
|     return GROUND_INT_VAL(0); | ||||
| } | ||||
|  | ||||
| // Draw a line | ||||
| GroundValue drawLine(GroundValue* args, int arg_count) { | ||||
|     if (!hasRunInit) { | ||||
|         std::cout << "Cannot draw line, please run !grogs:initSDL first" << std::endl; | ||||
|         return GROUND_INT_VAL(-1); | ||||
|     } | ||||
|     VALIDATE_ARGS_7(GROUND_INT, GROUND_INT, GROUND_INT, GROUND_INT, GROUND_INT, GROUND_INT, GROUND_INT); | ||||
|  | ||||
|     int x1 = GET_INT(args[0]); | ||||
|     int y1 = GET_INT(args[1]); | ||||
|     int x2 = GET_INT(args[2]); | ||||
|     int y2 = GET_INT(args[3]); | ||||
|     int red = clamp(GET_INT(args[4]), 0, 255); | ||||
|     int green = clamp(GET_INT(args[5]), 0, 255); | ||||
|     int blue = clamp(GET_INT(args[6]), 0, 255); | ||||
|  | ||||
|     SDL_SetRenderDrawColor(renderer, red, green, blue, 255); | ||||
|     SDL_RenderLine(renderer, (float)x1, (float)y1, (float)x2, (float)y2); | ||||
|  | ||||
|     return GROUND_INT_VAL(0); | ||||
| } | ||||
|  | ||||
| // Draw a filled rectangle | ||||
| GroundValue drawRect(GroundValue* args, int arg_count) { | ||||
|     if (!hasRunInit) { | ||||
|         std::cout << "Cannot draw rectangle, please run !grogs:initSDL first" << std::endl; | ||||
|         return GROUND_INT_VAL(-1); | ||||
|     } | ||||
|     VALIDATE_ARGS_7(GROUND_INT, GROUND_INT, GROUND_INT, GROUND_INT, GROUND_INT, GROUND_INT, GROUND_INT); | ||||
|  | ||||
|     int x = GET_INT(args[0]); | ||||
|     int y = GET_INT(args[1]); | ||||
|     int w = GET_INT(args[2]); | ||||
|     int h = GET_INT(args[3]); | ||||
|     int red = clamp(GET_INT(args[4]), 0, 255); | ||||
|     int green = clamp(GET_INT(args[5]), 0, 255); | ||||
|     int blue = clamp(GET_INT(args[6]), 0, 255); | ||||
|  | ||||
|     if (w <= 0 || h <= 0) { | ||||
|         return GROUND_INT_VAL(-1); // Invalid dimensions | ||||
|     } | ||||
|  | ||||
|     SDL_FRect rect = {(float)x, (float)y, (float)w, (float)h}; | ||||
|     SDL_SetRenderDrawColor(renderer, red, green, blue, 255); | ||||
|     SDL_RenderFillRect(renderer, &rect); | ||||
|  | ||||
|     return GROUND_INT_VAL(0); | ||||
| } | ||||
|  | ||||
| // Draw a rectangle outline | ||||
| GroundValue drawRectOutline(GroundValue* args, int arg_count) { | ||||
|     if (!hasRunInit) { | ||||
|         std::cout << "Cannot draw rectangle outline, please run !grogs:initSDL first" << std::endl; | ||||
|         return GROUND_INT_VAL(-1); | ||||
|     } | ||||
|     VALIDATE_ARGS_7(GROUND_INT, GROUND_INT, GROUND_INT, GROUND_INT, GROUND_INT, GROUND_INT, GROUND_INT); | ||||
|  | ||||
|     int x = GET_INT(args[0]); | ||||
|     int y = GET_INT(args[1]); | ||||
|     int w = GET_INT(args[2]); | ||||
|     int h = GET_INT(args[3]); | ||||
|     int red = clamp(GET_INT(args[4]), 0, 255); | ||||
|     int green = clamp(GET_INT(args[5]), 0, 255); | ||||
|     int blue = clamp(GET_INT(args[6]), 0, 255); | ||||
|  | ||||
|     if (w <= 0 || h <= 0) { | ||||
|         return GROUND_INT_VAL(-1); // Invalid dimensions | ||||
|     } | ||||
|  | ||||
|     SDL_FRect rect = {(float)x, (float)y, (float)w, (float)h}; | ||||
|     SDL_SetRenderDrawColor(renderer, red, green, blue, 255); | ||||
|     SDL_RenderRect(renderer, &rect); | ||||
|  | ||||
|     return GROUND_INT_VAL(0); | ||||
| } | ||||
|  | ||||
| // Draw a circle (filled) | ||||
| GroundValue drawCircle(GroundValue* args, int arg_count) { | ||||
|     if (!hasRunInit) { | ||||
|         std::cout << "Cannot draw circle, please run !grogs:initSDL first" << std::endl; | ||||
|         return GROUND_INT_VAL(-1); | ||||
|     } | ||||
|     VALIDATE_ARGS_6(GROUND_INT, GROUND_INT, GROUND_INT, GROUND_INT, GROUND_INT, GROUND_INT); | ||||
|  | ||||
|     int centerX = GET_INT(args[0]); | ||||
|     int centerY = GET_INT(args[1]); | ||||
|     int radius = GET_INT(args[2]); | ||||
|     int red = clamp(GET_INT(args[3]), 0, 255); | ||||
|     int green = clamp(GET_INT(args[4]), 0, 255); | ||||
|     int blue = clamp(GET_INT(args[5]), 0, 255); | ||||
|  | ||||
|     if (radius <= 0) { | ||||
|         return GROUND_INT_VAL(-1); // Invalid radius | ||||
|     } | ||||
|  | ||||
|     SDL_SetRenderDrawColor(renderer, red, green, blue, 255); | ||||
|  | ||||
|     // Simple circle drawing using midpoint algorithm | ||||
|     for (int y = -radius; y <= radius; y++) { | ||||
|         for (int x = -radius; x <= radius; x++) { | ||||
|             if (x*x + y*y <= radius*radius) { | ||||
|                 SDL_RenderPoint(renderer, (float)(centerX + x), (float)(centerY + y)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return GROUND_INT_VAL(0); | ||||
| } | ||||
|  | ||||
| // Get window dimensions | ||||
| GroundValue getWindowSize(GroundValue* args, int arg_count) { | ||||
|     if (!hasRunInit) { | ||||
|         std::cout << "Cannot get window size, please run !grogs:initSDL first" << std::endl; | ||||
|         return GROUND_INT_VAL(-1); | ||||
|     } | ||||
|  | ||||
|     VALIDATE_ARGS_1(GROUND_INT); | ||||
|     int dimension = GET_INT(args[0]); // 0 for width, 1 for height | ||||
|  | ||||
|     if (dimension == 0) { | ||||
|         return GROUND_INT_VAL(width); | ||||
|     } else if (dimension == 1) { | ||||
|         return GROUND_INT_VAL(height); | ||||
|     } | ||||
|     return GROUND_INT_VAL(-1); | ||||
| } | ||||
|  | ||||
| // Delay execution (useful for frame rate control) | ||||
| GroundValue delay(GroundValue* args, int arg_count) { | ||||
|     VALIDATE_ARGS_1(GROUND_INT); | ||||
|     int milliseconds = GET_INT(args[0]); | ||||
|  | ||||
|     if (milliseconds < 0) { | ||||
|         return GROUND_INT_VAL(-1); | ||||
|     } | ||||
|  | ||||
|     SDL_Delay(milliseconds); | ||||
|     return GROUND_INT_VAL(0); | ||||
| } | ||||
|  | ||||
| // Cleanup SDL resources | ||||
| GroundValue cleanup(GroundValue* args, int arg_count) { | ||||
|     if (hasRunInit) { | ||||
|         if (renderer) { | ||||
|             SDL_DestroyRenderer(renderer); | ||||
|             renderer = nullptr; | ||||
|         } | ||||
|         if (window) { | ||||
|             SDL_DestroyWindow(window); | ||||
|             window = nullptr; | ||||
|         } | ||||
|         SDL_Quit(); | ||||
|         hasRunInit = false; | ||||
|     } | ||||
|     return GROUND_INT_VAL(0); | ||||
| } | ||||
|  | ||||
| @@ -84,9 +333,19 @@ GROUND_LIBRARY_INIT() | ||||
|     REGISTER_GROUND_FUNCTION(initSDL); | ||||
|     REGISTER_GROUND_FUNCTION(renderFrame); | ||||
|     REGISTER_GROUND_FUNCTION(pollEvent); | ||||
|     REGISTER_GROUND_FUNCTION(getLastKey); | ||||
|     REGISTER_GROUND_FUNCTION(getMousePos); | ||||
|     REGISTER_GROUND_FUNCTION(clearRenderer); | ||||
|     REGISTER_GROUND_FUNCTION(setPixel); | ||||
|     REGISTER_GROUND_FUNCTION(drawLine); | ||||
|     REGISTER_GROUND_FUNCTION(drawRect); | ||||
|     REGISTER_GROUND_FUNCTION(drawRectOutline); | ||||
|     REGISTER_GROUND_FUNCTION(drawCircle); | ||||
|     REGISTER_GROUND_FUNCTION(getWindowSize); | ||||
|     REGISTER_GROUND_FUNCTION(delay); | ||||
|     REGISTER_GROUND_FUNCTION(cleanup); | ||||
| GROUND_LIBRARY_INIT_END() | ||||
|  | ||||
| GROUND_LIBRARY_CLEANUP() | ||||
|     cleanup(nullptr, 0); | ||||
| GROUND_LIBRARY_CLEANUP_END() | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								grogs/grogs.so
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								grogs/grogs.so
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -108,6 +108,25 @@ inline GroundValue ground_cstring_val(const char* str) { | ||||
|     REQUIRE_TYPE(3, type4); \ | ||||
|     REQUIRE_TYPE(4, type5); | ||||
|  | ||||
| #define VALIDATE_ARGS_6(type1, type2, type3, type4, type5, type6) \ | ||||
|     REQUIRE_ARGS(5); \ | ||||
|     REQUIRE_TYPE(0, type1); \ | ||||
|     REQUIRE_TYPE(1, type2); \ | ||||
|     REQUIRE_TYPE(2, type3); \ | ||||
|     REQUIRE_TYPE(3, type4); \ | ||||
|     REQUIRE_TYPE(4, type5); \ | ||||
|     REQUIRE_TYPE(5, type6); | ||||
|  | ||||
| #define VALIDATE_ARGS_7(type1, type2, type3, type4, type5, type6, type7) \ | ||||
|     REQUIRE_ARGS(5); \ | ||||
|     REQUIRE_TYPE(0, type1); \ | ||||
|     REQUIRE_TYPE(1, type2); \ | ||||
|     REQUIRE_TYPE(2, type3); \ | ||||
|     REQUIRE_TYPE(3, type4); \ | ||||
|     REQUIRE_TYPE(4, type5); \ | ||||
|     REQUIRE_TYPE(5, type6); \ | ||||
|     REQUIRE_TYPE(6, type7); | ||||
|  | ||||
| // Function registration helpers | ||||
| class GroundLibrary { | ||||
| private: | ||||
|   | ||||
							
								
								
									
										184
									
								
								grogs/test.grnd
									
									
									
									
									
								
							
							
						
						
									
										184
									
								
								grogs/test.grnd
									
									
									
									
									
								
							| @@ -1,52 +1,148 @@ | ||||
| extern "grogs" | ||||
|  | ||||
| struct -rectangle | ||||
|     init &topx -int | ||||
|     init &topy -int | ||||
|     init &bottomx -int | ||||
|     init &bottomy -int | ||||
|     init &red -int | ||||
|     init &green -int | ||||
|     init &blue -int | ||||
| struct -character | ||||
|     init &xpos -int | ||||
|     init &ypos -int | ||||
| endstruct | ||||
|  | ||||
| fun -int !draw -rectangle &r | ||||
|     set &ycount $r.topy | ||||
|     @columnloop | ||||
|     set &xcount $r.topx | ||||
|     add 1 $ycount &ycount | ||||
|     greater $ycount $r.bottomy &cond | ||||
|     if $cond %endloop | ||||
|     @rowloop | ||||
|     pusharg $xcount $ycount $r.red $r.green $r.blue | ||||
|     !grogs:setPixel &out | ||||
|     add 1 $xcount &xcount | ||||
|     greater $xcount $r.bottomx &cond | ||||
|     if $cond %columnloop | ||||
|     jump %rowloop | ||||
|     @endloop | ||||
|     return 0 | ||||
| endfun | ||||
| init &player -character | ||||
| set &player.xpos 100 | ||||
| set &player.ypos 100 | ||||
|  | ||||
| pusharg "Grogs Window" 640 480 | ||||
| !grogs:initSDL &status | ||||
| set &movingUp false | ||||
| set &movingDown false | ||||
| set &movingLeft false | ||||
| set &movingRight false | ||||
|  | ||||
| init &rect -rectangle | ||||
| set &rect.topx 10 | ||||
| set &rect.topy 10 | ||||
| set &rect.bottomx 150 | ||||
| set &rect.bottomy 100 | ||||
| set &rect.red 0 | ||||
| set &rect.blue 255 | ||||
| set &rect.green 255 | ||||
| pusharg "Grogs Window" 800 600 | ||||
| call !grogs:initSDL &result | ||||
|  | ||||
| @mainLoop | ||||
|  | ||||
| !grogs:pollEvent &event | ||||
|  | ||||
| # nothing | ||||
| equal $event -1 &cond | ||||
| if $cond %skipChecks | ||||
|  | ||||
| # exit | ||||
| equal $event 0 &cond | ||||
| if $cond %endMainLoop | ||||
|  | ||||
| # key pressed | ||||
| equal $event 1 &cond | ||||
| if $cond %checkPressedKey | ||||
|  | ||||
| # key unpressed | ||||
| equal $event 2 &cond | ||||
| if $cond %checkUnpressedKey | ||||
|  | ||||
| @checkPressedKey | ||||
| !grogs:getLastKey &key | ||||
|  | ||||
| # up | ||||
| equal $key 1073741906 &cond | ||||
| if $cond %processUpPress | ||||
|  | ||||
| # down | ||||
| equal $key 1073741905 &cond | ||||
| if $cond %processDownPress | ||||
|  | ||||
| # left | ||||
| equal $key 1073741904 &cond | ||||
| if $cond %processLeftPress | ||||
|  | ||||
| #right | ||||
| equal $key 1073741903 &cond | ||||
| if $cond %processRightPress | ||||
|  | ||||
| jump %skipChecks | ||||
|  | ||||
| @processUpPress | ||||
| set &movingUp true | ||||
| jump %skipChecks | ||||
|  | ||||
| @processDownPress | ||||
| set &movingDown true | ||||
| jump %skipChecks | ||||
|  | ||||
| @processLeftPress | ||||
| set &movingLeft true | ||||
| jump %skipChecks | ||||
|  | ||||
| @processRightPress | ||||
| set &movingRight true | ||||
| jump %skipChecks | ||||
|  | ||||
| @checkUnpressedKey | ||||
| !grogs:getLastKey &key | ||||
|  | ||||
| # up | ||||
| equal $key 1073741906 &cond | ||||
| if $cond %processUpUnpress | ||||
|  | ||||
| # down | ||||
| equal $key 1073741905 &cond | ||||
| if $cond %processDownUnpress | ||||
|  | ||||
| # left | ||||
| equal $key 1073741904 &cond | ||||
| if $cond %processLeftUnpress | ||||
|  | ||||
| #right | ||||
| equal $key 1073741903 &cond | ||||
| if $cond %processRightUnpress | ||||
|  | ||||
| jump %skipChecks | ||||
|  | ||||
| @processUpUnpress | ||||
| set &movingUp false | ||||
| jump %skipChecks | ||||
|  | ||||
| @processDownUnpress | ||||
| set &movingDown false | ||||
| jump %skipChecks | ||||
|  | ||||
| @processLeftUnpress | ||||
| set &movingLeft false | ||||
| jump %skipChecks | ||||
|  | ||||
| @processRightUnpress | ||||
| set &movingRight false | ||||
| jump %skipChecks | ||||
| @skipChecks | ||||
|  | ||||
| if $movingUp %processUp | ||||
| jump %checkDown | ||||
| @processUp | ||||
| subtract $player.ypos 10 &player.ypos | ||||
|  | ||||
| @checkDown | ||||
| if $movingDown %processDown | ||||
| jump %checkLeft | ||||
| @processDown | ||||
| add $player.ypos 10 &player.ypos | ||||
|  | ||||
| @checkLeft | ||||
| if $movingLeft %processLeft | ||||
| jump %checkRight | ||||
| @processLeft | ||||
| subtract $player.xpos 10 &player.xpos | ||||
|  | ||||
| @checkRight | ||||
| if $movingRight %processRight | ||||
| jump %endMovement | ||||
| @processRight | ||||
| add $player.xpos 10 &player.xpos | ||||
|  | ||||
| @endMovement | ||||
|  | ||||
| pusharg $player.xpos $player.ypos 20 20 0 255 255 | ||||
| !grogs:drawRect &out | ||||
|  | ||||
| @loop | ||||
| pusharg $rect | ||||
| !draw &out | ||||
| !grogs:renderFrame &out | ||||
| !grogs:pollEvent &out | ||||
| equal $out 0 &cond | ||||
| if $cond %end | ||||
| jump %loop | ||||
|  | ||||
| @end | ||||
| !grogs:clearRenderer &out | ||||
| pusharg 16 | ||||
| !grogs:delay &out | ||||
| jump %mainLoop | ||||
| @endMainLoop | ||||
|   | ||||
		Reference in New Issue
	
	Block a user