|
@@ -0,0 +1,225 @@
|
|
|
+/*
|
|
|
+ * 2D Physic Engine
|
|
|
+ * graphics.cpp: utilities to display stuff.
|
|
|
+ * Based on pikuma.com Learn Game Physics Engine Programming course.
|
|
|
+ * Copyright (c) 2022 986-Studio. All rights reserved.
|
|
|
+ *
|
|
|
+ * Created by Manoël Trapier on 07/06/2022.
|
|
|
+ */
|
|
|
+
|
|
|
+#include <cstdarg>
|
|
|
+
|
|
|
+#include <SDL.h>
|
|
|
+#include <SDL_image.h>
|
|
|
+#include <SDL_ttf.h>
|
|
|
+#include <SDL2_gfxPrimitives.h>
|
|
|
+
|
|
|
+#include <logger.h>
|
|
|
+
|
|
|
+#include <graphics.h>
|
|
|
+
|
|
|
+SDL_Window* graphics::window = nullptr;
|
|
|
+SDL_Renderer* graphics::renderer = nullptr;
|
|
|
+int graphics::windowWidth = 0;
|
|
|
+int graphics::windowHeight = 0;
|
|
|
+TTF_Font *graphics::font = nullptr;
|
|
|
+
|
|
|
+bool graphics::openWindow()
|
|
|
+{
|
|
|
+ if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
|
|
|
+ {
|
|
|
+ logger::critical("Error initializing SDL: %s", SDL_GetError());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (TTF_Init())
|
|
|
+ {
|
|
|
+ logger::critical("SDL_ttf Initialisation error: %s", SDL_GetError());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ SDL_DisplayMode display_mode;
|
|
|
+ SDL_GetCurrentDisplayMode(0, &display_mode);
|
|
|
+
|
|
|
+ graphics::windowWidth = display_mode.w;
|
|
|
+ graphics::windowHeight = display_mode.h;
|
|
|
+
|
|
|
+ graphics::window = SDL_CreateWindow(nullptr, 0, 0,
|
|
|
+ windowWidth, windowHeight, SDL_WINDOW_BORDERLESS);
|
|
|
+ if (!graphics::window)
|
|
|
+ {
|
|
|
+ logger::critical("Error creating SDL window: %s", SDL_GetError());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ graphics::renderer = SDL_CreateRenderer(window, -1,
|
|
|
+ SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
|
|
+ if (!graphics::renderer)
|
|
|
+ {
|
|
|
+ logger::critical("Error creating SDL renderer: %s", SDL_GetError());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ graphics::font = TTF_OpenFont("assets/pico8.ttf", 8);
|
|
|
+ if (graphics::font == nullptr)
|
|
|
+ {
|
|
|
+ logger::critical("Cannot open the font for printing...: %s", SDL_GetError());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ SDL_SetWindowFullscreen(graphics::window, SDL_WINDOW_FULLSCREEN);
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+void graphics::closeWindow()
|
|
|
+{
|
|
|
+ SDL_DestroyRenderer(graphics::renderer);
|
|
|
+ SDL_DestroyWindow(graphics::window);
|
|
|
+ SDL_Quit();
|
|
|
+}
|
|
|
+
|
|
|
+SDL_Texture *graphics::loadTexture(const char *filename)
|
|
|
+{
|
|
|
+ SDL_Surface *surface = IMG_Load(filename);
|
|
|
+ if (!surface)
|
|
|
+ {
|
|
|
+ logger::error("Error opening texture file '%s'!", filename);
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
|
|
|
+ SDL_FreeSurface(surface);
|
|
|
+
|
|
|
+ logger::info("Loaded texture %s", filename);
|
|
|
+
|
|
|
+ return texture;
|
|
|
+}
|
|
|
+
|
|
|
+void graphics::renderFrame()
|
|
|
+{
|
|
|
+ SDL_RenderPresent(graphics::renderer);
|
|
|
+}
|
|
|
+
|
|
|
+void graphics::clearScreen(uint32_t color)
|
|
|
+{
|
|
|
+ SDL_SetRenderDrawColor(graphics::renderer, color >> 16, color >> 8, color, 255);
|
|
|
+ SDL_RenderClear(graphics::renderer);
|
|
|
+}
|
|
|
+
|
|
|
+void graphics::draw::line(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint32_t color)
|
|
|
+{
|
|
|
+ lineColor(graphics::renderer, x0, y0, x1, y1, color);
|
|
|
+}
|
|
|
+
|
|
|
+void graphics::draw::circle(int16_t x, int16_t y, int16_t radius, double angle, uint32_t color)
|
|
|
+{
|
|
|
+ circleColor(graphics::renderer, x, y, radius, color);
|
|
|
+ lineColor(graphics::renderer,
|
|
|
+ x, y,
|
|
|
+ floor(x + cos(angle) * radius), floor(y + sin(angle) * radius),
|
|
|
+ color);
|
|
|
+}
|
|
|
+
|
|
|
+void graphics::draw::fillCircle(int16_t x, int16_t y, int16_t radius, uint32_t color)
|
|
|
+{
|
|
|
+ filledCircleColor(graphics::renderer, x, y, radius, color);
|
|
|
+}
|
|
|
+
|
|
|
+void graphics::draw::rect(int16_t x, int16_t y, int16_t width, int16_t height, uint32_t color)
|
|
|
+{
|
|
|
+ lineColor(graphics::renderer,
|
|
|
+ floor(x - width / 2.0), floor(y - height / 2.0),
|
|
|
+ floor(x + width / 2.0), floor(y - height / 2.0), color);
|
|
|
+ lineColor(graphics::renderer,
|
|
|
+ floor(x + width / 2.0), floor(y - height / 2.0),
|
|
|
+ floor(x + width / 2.0), floor(y + height / 2.0), color);
|
|
|
+ lineColor(graphics::renderer,
|
|
|
+ floor(x + width / 2.0), floor(y + height / 2.0),
|
|
|
+ floor(x - width / 2.0), floor(y + height / 2.0), color);
|
|
|
+ lineColor(graphics::renderer,
|
|
|
+ floor(x - width / 2.0), floor(y + height / 2.0),
|
|
|
+ floor(x - width / 2.0), floor(y - height / 2.0), color);
|
|
|
+}
|
|
|
+
|
|
|
+void graphics::draw::fillRect(int16_t x, int16_t y, int16_t width, int16_t height, uint32_t color)
|
|
|
+{
|
|
|
+ boxColor(graphics::renderer,
|
|
|
+ floor(x - width / 2.0), floor(y - height / 2.0),
|
|
|
+ floor(x + width / 2.0), floor(y + height / 2.0), color);
|
|
|
+}
|
|
|
+
|
|
|
+void graphics::draw::polygon(int16_t x, int16_t y, const std::vector<vec2> &vertices, uint32_t color)
|
|
|
+{
|
|
|
+ for (uint32_t i = 0; i < vertices.size(); i++)
|
|
|
+ {
|
|
|
+ uint32_t currIndex = i;
|
|
|
+ uint32_t nextIndex = (i + 1) % vertices.size();
|
|
|
+
|
|
|
+ lineColor(graphics::renderer,
|
|
|
+ floor(vertices[currIndex].x), floor(vertices[currIndex].y),
|
|
|
+ floor(vertices[nextIndex].x), floor(vertices[nextIndex].y),
|
|
|
+ color);
|
|
|
+ }
|
|
|
+ filledCircleColor(graphics::renderer, x, y, 1, color);
|
|
|
+}
|
|
|
+
|
|
|
+void graphics::draw::fillPolygon(int16_t x, int16_t y, const std::vector<vec2> &vertices, uint32_t color)
|
|
|
+{
|
|
|
+ std::vector<short> vx;
|
|
|
+ std::vector<short> vy;
|
|
|
+
|
|
|
+ for (const auto & vertice : vertices)
|
|
|
+ {
|
|
|
+ vx.push_back(static_cast<short>(vertice.x));
|
|
|
+ }
|
|
|
+
|
|
|
+ for (const auto & vertice : vertices)
|
|
|
+ {
|
|
|
+ vy.push_back(static_cast<short>(vertice.y));
|
|
|
+ }
|
|
|
+
|
|
|
+ filledPolygonColor(graphics::renderer, &vx[0], &vy[0], vertices.size(), color);
|
|
|
+ filledCircleColor(graphics::renderer, x, y, 1, 0xFF000000);
|
|
|
+}
|
|
|
+
|
|
|
+void graphics::draw::texture(int16_t x, int16_t y, int16_t width, int16_t height,
|
|
|
+ double rotation, SDL_Texture *texture)
|
|
|
+{
|
|
|
+ SDL_Rect dstRect = {x - (width / 2), y - (height / 2), width, height};
|
|
|
+
|
|
|
+ double rotationDeg = rotation * 57.2958;
|
|
|
+
|
|
|
+ SDL_RenderCopyEx(graphics::renderer, texture, nullptr, &dstRect, rotationDeg,
|
|
|
+ nullptr, SDL_FLIP_NONE);
|
|
|
+}
|
|
|
+
|
|
|
+void graphics::draw::text(int16_t x, int16_t y, uint32_t colour, const char *format, ...)
|
|
|
+{
|
|
|
+ va_list va;
|
|
|
+ uint8_t r = ((colour >> 16) & 0xFF);
|
|
|
+ uint8_t g = ((colour >> 8) & 0xFF);
|
|
|
+ uint8_t b = ((colour ) & 0xFF);
|
|
|
+ SDL_Color c = { r, g, b , 255};
|
|
|
+ char buffer[512];
|
|
|
+
|
|
|
+ va_start(va, format);
|
|
|
+ vsnprintf(buffer, 512, format, va);
|
|
|
+ va_end(va);
|
|
|
+
|
|
|
+ SDL_Surface *surface = TTF_RenderText_Blended(font, buffer, c);
|
|
|
+ SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
|
|
|
+
|
|
|
+ int labelWidth, labelHeight;
|
|
|
+
|
|
|
+ SDL_QueryTexture(texture, nullptr, nullptr, &labelWidth, &labelHeight);
|
|
|
+
|
|
|
+ SDL_Rect destRect =
|
|
|
+ {
|
|
|
+ x, y, labelWidth, labelHeight
|
|
|
+ };
|
|
|
+ SDL_RenderCopyEx(renderer, texture, nullptr, &destRect,0,
|
|
|
+ nullptr, SDL_FLIP_NONE);
|
|
|
+
|
|
|
+ SDL_FreeSurface(surface);
|
|
|
+ SDL_DestroyTexture(texture);
|
|
|
+}
|