#include "ground_lib.h" #include #include #include #include SDL_Window* window = nullptr; SDL_Renderer* renderer = nullptr; SDL_Event event; int width = 0; int height = 0; bool hasRunInit = false; // 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); VALIDATE_ARGS_3(GROUND_STRING, GROUND_INT, GROUND_INT); 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); } 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; return GROUND_INT_VAL(-1); } SDL_RenderPresent(renderer); 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); int pixelX = GET_INT(args[0]); int pixelY = GET_INT(args[1]); 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); } GROUND_LIBRARY_INTERFACE() 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()