Files
libraries/grogs/grogs.cpp

352 lines
11 KiB
C++
Raw Normal View History

2025-09-21 15:50:03 +10:00
#include "ground_lib.h"
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <SDL3/SDL_render.h>
2025-09-21 20:41:09 +10:00
#include <iostream>
2025-09-21 15:50:03 +10:00
2025-09-21 20:41:09 +10:00
SDL_Window* window = nullptr;
SDL_Renderer* renderer = nullptr;
2025-09-21 15:50:03 +10:00
SDL_Event event;
2025-09-21 20:41:09 +10:00
int width = 0;
int height = 0;
bool hasRunInit = false;
2025-09-21 15:50:03 +10:00
2025-09-21 20:41:09 +10:00
// 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;
}
2025-09-21 15:50:03 +10:00
2025-09-21 20:41:09 +10:00
// Initialize SDL and create window
2025-09-21 15:50:03 +10:00
GroundValue initSDL(GroundValue* args, int arg_count) {
if (hasRunInit) return GROUND_INT_VAL(2);
VALIDATE_ARGS_3(GROUND_STRING, GROUND_INT, GROUND_INT);
2025-09-21 20:41:09 +10:00
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
std::cout << "SDL could not initialize! SDL Error: " << SDL_GetError() << std::endl;
return GROUND_INT_VAL(1);
}
2025-09-21 15:50:03 +10:00
width = GET_INT(args[1]);
height = GET_INT(args[2]);
2025-09-21 20:41:09 +10:00
// Validate dimensions
if (width <= 0 || height <= 0) {
std::cout << "Invalid window dimensions" << std::endl;
SDL_Quit();
2025-09-21 15:50:03 +10:00
return GROUND_INT_VAL(1);
}
2025-09-21 20:41:09 +10:00
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);
}
2025-09-21 15:50:03 +10:00
hasRunInit = true;
return GROUND_INT_VAL(0);
}
2025-09-21 20:41:09 +10:00
// Poll for events (enhanced with more event types)
2025-09-21 15:50:03 +10:00
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);
}
2025-09-21 20:41:09 +10:00
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);
2025-09-21 15:50:03 +10:00
}
return GROUND_INT_VAL(-1);
}
2025-09-21 20:41:09 +10:00
// 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
2025-09-21 15:50:03 +10:00
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);
}
2025-09-21 20:41:09 +10:00
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);
}
2025-09-21 15:50:03 +10:00
SDL_RenderClear(renderer);
return GROUND_INT_VAL(0);
}
2025-09-21 20:41:09 +10:00
// Render frame to screen
2025-09-21 15:50:03 +10:00
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);
2025-09-21 16:03:19 +10:00
return GROUND_INT_VAL(0);
2025-09-21 15:50:03 +10:00
}
2025-09-21 20:41:09 +10:00
// Set a single pixel
2025-09-21 15:50:03 +10:00
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);
2025-09-21 20:41:09 +10:00
2025-09-21 15:50:03 +10:00
int pixelX = GET_INT(args[0]);
int pixelY = GET_INT(args[1]);
2025-09-21 20:41:09 +10:00
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};
2025-09-21 15:50:03 +10:00
SDL_SetRenderDrawColor(renderer, red, green, blue, 255);
2025-09-21 20:41:09 +10:00
SDL_RenderRect(renderer, &rect);
return GROUND_INT_VAL(0);
}
2025-09-21 15:50:03 +10:00
2025-09-21 20:41:09 +10:00
// 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;
}
2025-09-21 15:50:03 +10:00
return GROUND_INT_VAL(0);
}
GROUND_LIBRARY_INTERFACE()
GROUND_LIBRARY_INIT()
REGISTER_GROUND_FUNCTION(initSDL);
REGISTER_GROUND_FUNCTION(renderFrame);
REGISTER_GROUND_FUNCTION(pollEvent);
2025-09-21 20:41:09 +10:00
REGISTER_GROUND_FUNCTION(getLastKey);
REGISTER_GROUND_FUNCTION(getMousePos);
2025-09-21 15:50:03 +10:00
REGISTER_GROUND_FUNCTION(clearRenderer);
REGISTER_GROUND_FUNCTION(setPixel);
2025-09-21 20:41:09 +10:00
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);
2025-09-21 15:50:03 +10:00
GROUND_LIBRARY_INIT_END()
GROUND_LIBRARY_CLEANUP()
2025-09-21 20:41:09 +10:00
cleanup(nullptr, 0);
2025-09-21 15:50:03 +10:00
GROUND_LIBRARY_CLEANUP_END()