#include "../core/const.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../core/color.h" #include "core/config.hpp" #include "draw.hpp" #include "hal/hal.hpp" #include #include #include #include #include #include #include struct sdl_session { SDL_Window *window; SDL_Renderer *renderer; }; sdl_session main_sdl_session; const SDL_DisplayMode *mode; CURL *curl; namespace hal { int init() { #ifdef CONFIG_SDL_TARGET_KMSDRM if (!SDL_SetHint(SDL_HINT_KMSDRM_DEVICE_INDEX, "-1")) { SDL_Log("hint failed: %s", SDL_GetError()); } if (!SDL_SetHint(SDL_HINT_KMSDRM_REQUIRE_DRM_MASTER, "1")) { SDL_Log("hint failed: %s", SDL_GetError()); } if (!SDL_SetHint(SDL_HINT_VIDEO_DRIVER, "kmsdrm")) { SDL_Log("hint failed: %s", SDL_GetError()); } if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, CONFIG_SDL_DRIVERS)) { SDL_Log("hint failed: %s", SDL_GetError()); } #endif if (!SDL_Init(SDL_INIT_VIDEO)) { SDL_Log("init failed: %s", SDL_GetError()); return 1; } // DEBUG std::clog << "active driver: " << SDL_GetCurrentVideoDriver() << "\n"; mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay()); if (!mode) { SDL_Log("failed to get display mode: %s", SDL_GetError()); return 1; } main_sdl_session.window = SDL_CreateWindow(program_name, mode->w, mode->h, SDL_WINDOW_FULLSCREEN); if (!main_sdl_session.window) { SDL_Log("window failed: %s", SDL_GetError()); return 1; } main_sdl_session.renderer = SDL_CreateRenderer(main_sdl_session.window, #ifndef CONFIG_SDL_TARGET_KMSDRM CONFIG_SDL_DRIVERS #else NULL #endif ); if (!main_sdl_session.renderer) { SDL_Log("renderer failed: %s", SDL_GetError()); return 1; } curl = curl_easy_init(); return 0; } std::tuple get_screen_size() { return {mode->w, mode->h}; } uint64_t frame_start; void start_frame() { frame_start = SDL_GetTicksNS(); SDL_SetRenderDrawColor(main_sdl_session.renderer, 0, 0, 0, 255); SDL_RenderClear(main_sdl_session.renderer); } constexpr Uint64 frame_delay_ns = 1000000000ULL / 1; void end_frame() { SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { // Handles Window close (the 'X' button), Alt+F4, or SIGINT (Ctrl+C) // Handles keyboard key presses case SDL_EVENT_KEY_DOWN: // Check if the pressed key is 'Q' if (event.key.key != SDLK_Q) { break; } [[fallthrough]]; case SDL_EVENT_QUIT: SDL_Quit(); std::exit(0); break; default: break; } } SDL_RenderPresent(main_sdl_session.renderer); uint64_t frame_time = SDL_GetTicksNS() - frame_start; if (frame_time < frame_delay_ns) { SDL_DelayNS(frame_delay_ns - frame_time); } } } // namespace hal namespace draw { void pixel(const uint16_t x, const uint16_t y, const color_t color) { SDL_SetRenderDrawColor(main_sdl_session.renderer, color.r, color.g, color.b, 0xff); SDL_RenderPoint(main_sdl_session.renderer, x, y); } void filled_rect(const rect_t *rect, const color_t color) { SDL_SetRenderDrawColor(main_sdl_session.renderer, color.r, color.g, color.b, 0xff); const SDL_FRect frect = { static_cast(rect->x), static_cast(rect->y), static_cast(rect->w), static_cast(rect->h)}; SDL_RenderFillRect(main_sdl_session.renderer, &frect); } void circle(const uint16_t x_center, const uint16_t y_center, const uint16_t radius, const color_t color) { SDL_SetRenderDrawColor(main_sdl_session.renderer, color.r, color.g, color.b, 0xff); // based on // https://www.geeksforgeeks.org/dsa/mid-point-circle-drawing-algorithm/ int x = radius, y = 0; // Printing the initial point on the axes // after translation SDL_RenderPoint(main_sdl_session.renderer, x + x_center, y + y_center); // When radius is zero only a single // point will be printed if (radius > 0) { SDL_RenderPoint(main_sdl_session.renderer, x + x_center, -y + y_center); SDL_RenderPoint(main_sdl_session.renderer, y + x_center, x + y_center); SDL_RenderPoint(main_sdl_session.renderer, -y + x_center, x + y_center); } // Initialising the value of P int P = 1 - radius; while (x > y) { y++; // Mid-point is inside or on the perimeter if (P <= 0) P = P + 2 * y + 1; // Mid-point is outside the perimeter else { x--; P = P + 2 * y - 2 * x + 1; } // All the perimeter points have already been printed if (x < y) break; // Printing the generated point and its reflection // in the other octants after translation SDL_RenderPoint(main_sdl_session.renderer, x + x_center, y + y_center); SDL_RenderPoint(main_sdl_session.renderer, -x + x_center, y + y_center); SDL_RenderPoint(main_sdl_session.renderer, x + x_center, -y + y_center); SDL_RenderPoint(main_sdl_session.renderer, -x + x_center, -y + y_center); // If the generated point is on the line x = y then // the perimeter points have already been printed if (x != y) { SDL_RenderPoint(main_sdl_session.renderer, y + x_center, x + y_center); SDL_RenderPoint(main_sdl_session.renderer, -y + x_center, x + y_center); SDL_RenderPoint(main_sdl_session.renderer, y + x_center, -x + y_center); SDL_RenderPoint(main_sdl_session.renderer, -y + x_center, -x + y_center); } } } void rhombus(const uint16_t x_center, const uint16_t y_center, const uint16_t radius, const color_t color) { SDL_SetRenderDrawColor(main_sdl_session.renderer, color.r, color.g, color.b, 0xff); const SDL_FPoint points[] = { {static_cast(x_center + radius), static_cast(y_center)}, {static_cast(x_center), static_cast(y_center + radius)}, {static_cast(x_center - radius), static_cast(y_center)}, {static_cast(x_center), static_cast(y_center - radius)}, {static_cast(x_center + radius), static_cast(y_center)}}; SDL_RenderLines(main_sdl_session.renderer, points, ARRAY_LENGHT(points)); } void line(const uint16_t x1, const uint16_t y1, const uint16_t x2, const uint16_t y2, const color_t color) { SDL_SetRenderDrawColor(main_sdl_session.renderer, color.r, color.g, color.b, 0xff); SDL_RenderLine(main_sdl_session.renderer, x1, y1, x2, y2); } #ifdef CONFIG_VECTOR_FOLLOW_TRACK_RATE void arc(uint16_t start_x, uint16_t start_y, float start_angle_rad, float speed /*in pps*/,float angular_speed_rads, uint16_t duration, color_t color) { SDL_SetRenderDrawColor(main_sdl_session.renderer, color.r, color.g, color.b, 0xff); if (speed == 0) { SDL_RenderPoint(main_sdl_session.renderer, start_x, start_y); return; } // Handle straight line case if (std::fabs(angular_speed_rads) < 1e-6f) { uint16_t steps = static_cast(speed * duration); for (uint16_t i = 0; i <= steps; ++i) { float t = i / speed; float x = start_x + std::cos(start_angle_rad) * speed * t; float y = start_y + std::sin(start_angle_rad) * speed * t; SDL_RenderPoint(main_sdl_session.renderer,static_cast(std::round(x)), static_cast(std::round(y))); } return; } float r = speed / angular_speed_rads; // Center of circle: perpendicular to heading float center_x = start_x - r * std::sin(start_angle_rad); float center_y = start_y + r * std::cos(start_angle_rad); // Angle from center to start point float radius_angle = std::atan2(start_y - center_y, start_x - center_x); // Step size in time — approx 1 pixel arc-length per step float dt = 1.0f / std::max(std::fabs(speed), 1.0f); uint16_t steps = static_cast(duration / dt); for (uint16_t i = 0; i <= steps; ++i) { float t = i * dt; float a = radius_angle + angular_speed_rads * t; float x = center_x + std::fabs(r) * std::cos(a); float y = center_y + std::fabs(r) * std::sin(a); SDL_RenderPoint(main_sdl_session.renderer,static_cast(std::round(x)), static_cast(std::round(y))); } } #endif } // namespace draw namespace net { // Callback function to write data into a std::string size_t WriteCallback_to_string(void *contents, size_t size, size_t nmemb, void *userp) { size_t totalSize = size * nmemb; static_cast(userp)->append((char *)contents, totalSize); return totalSize; } nlohmann::json http_get_json(const std::string &url) { std::string response; if (curl) { curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &WriteCallback_to_string); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "gzip, deflate"); curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent); curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); CURLcode curl_return_code = curl_easy_perform(curl); if (curl_return_code != CURLE_OK) { std::cerr << RED "[ERROR] " << RESET << "curl_easy_perform() failed: " << curl_easy_strerror(curl_return_code) << "\n"; exit(21); } int http_code = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); if (http_code < 200 || http_code >= 300) { return nullptr; } return nlohmann::json::parse(response); } return nullptr; } } // namespace net