Initial commit
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
#ifndef PCH_H
|
||||
#define PCH_H
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_events.h>
|
||||
#include <SDL3_image/SDL_image.h>
|
||||
#include <SDL3_ttf/SDL_ttf.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
|
||||
#endif
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
struct Color {
|
||||
uint8_t r, g, b, a;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Vec2 {
|
||||
T x, y;
|
||||
|
||||
template <typename U>
|
||||
Vec2 operator*(U s) const {
|
||||
return {x * s, y * s};
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
Vec2 operator/(U s) const {
|
||||
return {x / s, y / s};
|
||||
}
|
||||
|
||||
Vec2 operator+(const Vec2 &other) const {
|
||||
return {x + other.x, y + other.y};
|
||||
}
|
||||
|
||||
Vec2 operator-(const Vec2 &other) const {
|
||||
return {x - other.x, y - other.y};
|
||||
}
|
||||
|
||||
Vec2 operator-() const {
|
||||
return {-x, -y};
|
||||
}
|
||||
|
||||
T dot(const Vec2 &o) const {
|
||||
return x * o.x + y * o.y;
|
||||
}
|
||||
|
||||
float dist(const Vec2 &other) const {
|
||||
float dx = other.x - x;
|
||||
float dy = other.y - y;
|
||||
return std::sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
Vec2<float> normalized() const {
|
||||
float length = std::sqrt(x * x + y * y);
|
||||
if (length == 0)
|
||||
return {0, 0};
|
||||
return {x / length, y / length};
|
||||
}
|
||||
|
||||
float angle_to(const Vec2 &other) const {
|
||||
float dx = other.x - x;
|
||||
float dy = other.y - y;
|
||||
return std::atan2(dy, dx);
|
||||
}
|
||||
};
|
||||
|
||||
struct Line {
|
||||
Vec2<float> start;
|
||||
Vec2<float> end;
|
||||
|
||||
Line(Vec2<float> start, Vec2<float> end) : start(start), end(end) {}
|
||||
|
||||
bool intersects(const Line &other) const {
|
||||
float denom = (other.end.y - other.start.y) * (end.x - start.x) -
|
||||
(other.end.x - other.start.x) * (end.y - start.y);
|
||||
|
||||
if (std::abs(denom) < 1e-6f) // Lines are parallel (or very close to it)
|
||||
return false;
|
||||
|
||||
float ua = ((other.end.x - other.start.x) * (start.y - other.start.y) -
|
||||
(other.end.y - other.start.y) * (start.x - other.start.x)) /
|
||||
denom;
|
||||
float ub = ((end.x - start.x) * (start.y - other.start.y) -
|
||||
(end.y - start.y) * (start.x - other.start.x)) /
|
||||
denom;
|
||||
|
||||
return ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1;
|
||||
}
|
||||
};
|
||||
|
||||
struct Rect {
|
||||
Line diagonal; // from top-left to bottom-right
|
||||
|
||||
Rect(Vec2<float> a, Vec2<float> b) : diagonal(a, b) {
|
||||
diagonal.start = {
|
||||
MIN(a.x, b.x),
|
||||
MIN(a.y, b.y)
|
||||
};
|
||||
diagonal.end = {
|
||||
MAX(a.x, b.x),
|
||||
MAX(a.y, b.y)
|
||||
};
|
||||
}
|
||||
|
||||
bool contains(const Vec2<float> &point) const {
|
||||
return point.x >= diagonal.start.x && point.x <= diagonal.end.x &&
|
||||
point.y >= diagonal.start.y && point.y <= diagonal.end.y;
|
||||
}
|
||||
|
||||
bool intersects(const Rect &other) const {
|
||||
return !(diagonal.start.x > other.diagonal.end.x || diagonal.end.x < other.diagonal.start.x || diagonal.start.y > other.diagonal.end.y || diagonal.end.y < other.diagonal.start.y);
|
||||
}
|
||||
|
||||
bool intersects(const Line &line) const {
|
||||
if (contains(line.start) || contains(line.end))
|
||||
return true;
|
||||
|
||||
Vec2<float> rect_points[4] = {
|
||||
diagonal.start,
|
||||
{diagonal.end.x, diagonal.start.y},
|
||||
{diagonal.start.x, diagonal.end.y},
|
||||
diagonal.end
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Vec2<float> edge_start = rect_points[i];
|
||||
Vec2<float> edge_end = rect_points[(i + 1) % 4];
|
||||
if (Line{edge_start, edge_end}.intersects(line))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
float x() const {
|
||||
return diagonal.start.x;
|
||||
}
|
||||
float y() const {
|
||||
return diagonal.start.y;
|
||||
}
|
||||
float w() const {
|
||||
return diagonal.end.x - diagonal.start.x;
|
||||
}
|
||||
float h() const {
|
||||
return diagonal.end.y - diagonal.start.y;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,174 @@
|
||||
#ifndef WINDOW_H
|
||||
#define WINDOW_H
|
||||
|
||||
#include "../pch.h"
|
||||
#include "../utils.h"
|
||||
|
||||
using ImageID = uint32_t;
|
||||
using FontID = uint32_t;
|
||||
using TextID = uint32_t;
|
||||
|
||||
struct Font {
|
||||
TTF_Font *font;
|
||||
bool pixel_art;
|
||||
};
|
||||
|
||||
struct Event {
|
||||
enum Type {
|
||||
NONE,
|
||||
QUIT,
|
||||
KEY_UP,
|
||||
KEY_DOWN,
|
||||
TEXT_INPUT,
|
||||
SCROLL,
|
||||
MOUSE_BUTTON_UP,
|
||||
MOUSE_BUTTON_DOWN,
|
||||
MOUSE_MOVE
|
||||
} type;
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint32_t key;
|
||||
} key;
|
||||
|
||||
struct {
|
||||
char *text;
|
||||
uint32_t length;
|
||||
} text_input;
|
||||
|
||||
struct {
|
||||
float x, y;
|
||||
} scroll;
|
||||
|
||||
struct {
|
||||
uint8_t button;
|
||||
Vec2<float> position;
|
||||
} mouse_button;
|
||||
|
||||
struct {
|
||||
Vec2<float> position;
|
||||
Vec2<float> delta;
|
||||
} mouse_move;
|
||||
};
|
||||
};
|
||||
|
||||
struct Window {
|
||||
public:
|
||||
// title can be free'd by the caller after the window is created, as it's copied internally.
|
||||
Window(Vec2<float> size, const char *title);
|
||||
|
||||
~Window();
|
||||
|
||||
// Rendering functions
|
||||
|
||||
ImageID load_image(const char *path, bool pixel_art = false);
|
||||
void unload_image(ImageID image_id);
|
||||
|
||||
FontID load_font(const char *path, int font_size, bool bold = false, bool italic = false, bool underline = false, bool pixel_art = false);
|
||||
void unload_font(FontID font_id);
|
||||
|
||||
// text is copied internally, so it can be free'd by the caller after the text is created.
|
||||
TextID create_text(FontID font_id, const char *text, uint32_t length, Color color);
|
||||
void unload_text(TextID text_id);
|
||||
|
||||
bool write(TextID text_id, Vec2<float> position, float z, float angle = 0.0f, Vec2<float> scale = {1.0f, 1.0f});
|
||||
|
||||
bool draw(ImageID image_id, Vec2<float> position, float z, float angle = 0.0f, Vec2<float> scale = {1.0f, 1.0f}, float alpha = 1.0f);
|
||||
|
||||
bool draw_rect(Rect rect, Color color, float z, float angle = 0.0f);
|
||||
|
||||
void render(); // the rest of the calls only build the instruction list, this actually renders everything added to the screen (following z order)
|
||||
|
||||
void clear(); // clears the instruction list
|
||||
|
||||
// Event handling
|
||||
|
||||
bool poll(Event &event); // returns true if an event was polled, false otherwise
|
||||
|
||||
// consumes an event, (mostly for text input, to free the text input buffer)
|
||||
// but also so the user can decide when they're done with the event explicitly.
|
||||
void consume(Event &event);
|
||||
|
||||
// Text input
|
||||
// Starts accepting Unicode text input events, and stops acceptong normal key down/up events for those keys.
|
||||
|
||||
void start_text_input();
|
||||
void stop_text_input();
|
||||
|
||||
// Clipboard get
|
||||
|
||||
// To be free'd by the caller after use.
|
||||
const char *paste();
|
||||
|
||||
// Time
|
||||
|
||||
uint64_t get_time(); // returns the time in milliseconds since the window was created
|
||||
uint64_t delta_time(); // returns the time in milliseconds since the last render call
|
||||
|
||||
private:
|
||||
// internal data and functions
|
||||
SDL_Window *window;
|
||||
SDL_Renderer *renderer;
|
||||
|
||||
Vec2<float> real_size;
|
||||
Vec2<float> virtual_size;
|
||||
Vec2<float> offset;
|
||||
float scale;
|
||||
|
||||
// White pixel texture for drawing colored rectangles
|
||||
SDL_Texture *white_tex;
|
||||
|
||||
// Image pool
|
||||
std::vector<SDL_Texture *> images;
|
||||
std::vector<int> free_image_indices;
|
||||
|
||||
// Font pool
|
||||
std::vector<struct Font> fonts;
|
||||
std::vector<int> free_font_indices;
|
||||
|
||||
// Text pool
|
||||
std::vector<SDL_Texture *> texts;
|
||||
std::vector<int> free_text_indices;
|
||||
|
||||
struct RenderInstruction {
|
||||
enum Type {
|
||||
DRAW_IMAGE,
|
||||
DRAW_TEXT,
|
||||
DRAW_RECT
|
||||
} type;
|
||||
|
||||
float z;
|
||||
float angle;
|
||||
Vec2<float> scale;
|
||||
|
||||
union {
|
||||
struct {
|
||||
ImageID image_id;
|
||||
Vec2<float> position;
|
||||
float alpha;
|
||||
} draw_image;
|
||||
|
||||
struct {
|
||||
TextID text_id;
|
||||
Vec2<float> position;
|
||||
} draw_text;
|
||||
|
||||
struct {
|
||||
Rect rect;
|
||||
Color color;
|
||||
} draw_rect;
|
||||
};
|
||||
};
|
||||
|
||||
std::vector<struct RenderInstruction> render_instructions;
|
||||
|
||||
bool text_input_active;
|
||||
|
||||
void compute_transform();
|
||||
|
||||
bool mouse_in_window(const Vec2<float> real_position, Vec2<float> &virtual_position);
|
||||
|
||||
void draw_letterbox();
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user