Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
drawing.cpp
Go to the documentation of this file.
1/*
2 Olympe Engine - 2025
3 Nicolas Chereau
4 nchereau@gmail.com
5
6 This file is part of Olympe Engine.
7 Purpose: This file contains functions related to drawing shapes and images on the screen.
8
9
10*/
11#pragma once
12#include "drawing.h"
13#include <SDL3/SDL_render.h>
14#include <cmath>
15#include "GameEngine.h"
16#include "RenderContext.h"
17
18
19// Portable pi definition for C++14 (avoids M_PI reliance)
20static const float PI = static_cast<float>(std::acos(-1.0));
21
22// Pre-calculated hexagon vertices (unit circle) for performance optimization
23// These are the normalized positions for a regular hexagon
24static const float HEXAGON_COS_ANGLES[6] = {
25 1.0f, // 0°
26 0.5f, // 60°
27 -0.5f, // 120°
28 -1.0f, // 180°
29 -0.5f, // 240°
30 0.5f // 300°
31};
32
33static const float HEXAGON_SIN_ANGLES[6] = {
34 0.0f, // 0°
35 0.866025404f, // 60° (sqrt(3)/2)
36 0.866025404f, // 120°
37 0.0f, // 180°
38 -0.866025404f, // 240°
39 -0.866025404f // 300°
40};
41
42// Color conversion helpers
43static inline SDL_FColor ToFColor(const SDL_Color& c)
44{
45 return SDL_FColor{
46 c.r / 255.0f,
47 c.g / 255.0f,
48 c.b / 255.0f,
49 c.a / 255.0f
50 };
51}
52
53static inline SDL_Color ToColor(const SDL_FColor& f)
54{
55 auto clamp01 = [](float v) {
56 if (v < 0.0f) return 0.0f;
57 if (v > 1.0f) return 1.0f;
58 return v;
59 };
60 return SDL_Color{
61 static_cast<Uint8>(std::round(clamp01(f.r) * 255.0f)),
62 static_cast<Uint8>(std::round(clamp01(f.g) * 255.0f)),
63 static_cast<Uint8>(std::round(clamp01(f.b) * 255.0f)),
64 static_cast<Uint8>(std::round(clamp01(f.a) * 255.0f))
65 };
66}
67//----------------------------------------------------------
68// Draws a circle using the Midpoint Circle Algorithm
69void Draw_Circle(int cx, int cy, int radius)
70{
72
73 if (!cam.isActive) {
74 // Legacy screen-space rendering (no camera active)
75 int x = radius;
76 int y = 0;
77 int err = 0;
78
79 while (x >= y)
80 {
81 SDL_RenderPoint(GameEngine::renderer, (float)cx + x, (float)cy + y);
82 SDL_RenderPoint(GameEngine::renderer, (float)cx + y, (float)cy + x);
83 SDL_RenderPoint(GameEngine::renderer, (float)cx - y, (float)cy + x);
84 SDL_RenderPoint(GameEngine::renderer, (float)cx - x, (float)cy + y);
85 SDL_RenderPoint(GameEngine::renderer, (float)cx - x, (float)cy - y);
86 SDL_RenderPoint(GameEngine::renderer, (float)cx - y, (float)cy - x);
87 SDL_RenderPoint(GameEngine::renderer, (float)cx + y, (float)cy - x);
88 SDL_RenderPoint(GameEngine::renderer, (float)cx + x, (float)cy - y);
89
90 if (err <= 0)
91 {
92 y += 1;
93 err += 2 * y + 1;
94 }
95 if (err > 0)
96 {
97 x -= 1;
98 err -= 2 * x + 1;
99 }
100 }
101 return;
102 }
103
104 // Camera active: transform world coordinates to screen
105 // Note: Circles are rotationally symmetric, so camera rotation has no effect
106 Vector worldCenter((float)cx, (float)cy, 0.0f);
107 Vector screenCenter = cam.WorldToScreen(worldCenter);
108 float screenRadius = radius * cam.zoom;
109
110 int sCx = static_cast<int>(screenCenter.x);
111 int sCy = static_cast<int>(screenCenter.y);
112 int sRadius = static_cast<int>(screenRadius);
113
114 int x = sRadius;
115 int y = 0;
116 int err = 0;
117
118 while (x >= y) {
119 SDL_RenderPoint(GameEngine::renderer, (float)sCx + x, (float)sCy + y);
120 SDL_RenderPoint(GameEngine::renderer, (float)sCx + y, (float)sCy + x);
121 SDL_RenderPoint(GameEngine::renderer, (float)sCx - y, (float)sCy + x);
122 SDL_RenderPoint(GameEngine::renderer, (float)sCx - x, (float)sCy + y);
123 SDL_RenderPoint(GameEngine::renderer, (float)sCx - x, (float)sCy - y);
124 SDL_RenderPoint(GameEngine::renderer, (float)sCx - y, (float)sCy - x);
125 SDL_RenderPoint(GameEngine::renderer, (float)sCx + y, (float)sCy - x);
126 SDL_RenderPoint(GameEngine::renderer, (float)sCx + x, (float)sCy - y);
127
128 if (err <= 0) { y += 1; err += 2 * y + 1; }
129 if (err > 0) { x -= 1; err -= 2 * x + 1; }
130 }
131}
132//----------------------------------------------------------
133// Draws a filled circle using horizontal scanlines
134// Optimized: use integer arithmetic to avoid sqrt in loop
135void Draw_FilledCircle(int cx, int cy, int radius)
136{
138
139 if (!cam.isActive) {
140 // Legacy screen-space rendering
141 int r2 = radius * radius;
142 for (int dy = -radius; dy <= radius; ++dy)
143 {
144 // Use integer arithmetic: dx^2 = r^2 - dy^2
145 int dy2 = dy * dy;
146 int dx2 = r2 - dy2;
147 // Only compute sqrt once per scanline
148 int dx = static_cast<int>(std::sqrt(static_cast<float>(dx2)));
149 int x1 = cx - dx;
150 int x2 = cx + dx;
151 SDL_RenderLine(GameEngine::renderer, (float)x1, (float)cy + dy, (float)x2, (float)cy + dy);
152 }
153 return;
154 }
155
156 // Camera active: transform center and scale radius
157 // Note: Filled circles are rotationally symmetric, so camera rotation has no effect
158 Vector worldCenter((float)cx, (float)cy, 0.0f);
159 Vector screenCenter = cam.WorldToScreen(worldCenter);
160 float screenRadius = radius * cam.zoom;
161
162 int sCx = static_cast<int>(screenCenter.x);
163 int sCy = static_cast<int>(screenCenter.y);
164 int sRadius = static_cast<int>(screenRadius);
165
166 int r2 = sRadius * sRadius;
167 for (int dy = -sRadius; dy <= sRadius; ++dy) {
168 int dy2 = dy * dy;
169 int dx2 = r2 - dy2;
170 int dx = static_cast<int>(std::sqrt(static_cast<float>(dx2)));
171 int x1 = sCx - dx;
172 int x2 = sCx + dx;
173 SDL_RenderLine(GameEngine::renderer, (float)x1, (float)sCy + dy, (float)x2, (float)sCy + dy);
174 }
175}
176//----------------------------------------------------------
177// Draws the outline of a triangle
179{
181
182 if (!cam.isActive) {
183 // Legacy screen-space rendering
187 return;
188 }
189
190 // Transform world coordinates to screen
191 Vector s1 = cam.WorldToScreen(p1);
192 Vector s2 = cam.WorldToScreen(p2);
193 Vector s3 = cam.WorldToScreen(p3);
194
198}
199//----------------------------------------------------------
200// Draws a filled triangle using SDL_RenderGeometry
202 const Vector& p1,
203 const Vector& p2,
204 const Vector& p3,
205 SDL_FColor color)
206{
208
209 Vector s1 = cam.isActive ? cam.WorldToScreen(p1) : p1;
210 Vector s2 = cam.isActive ? cam.WorldToScreen(p2) : p2;
211 Vector s3 = cam.isActive ? cam.WorldToScreen(p3) : p3;
212
214
215 vertices[0].position = s1.ToFPoint();
216 vertices[1].position = s2.ToFPoint();
217 vertices[2].position = s3.ToFPoint();
218
219 vertices[0].color = color;
220 vertices[1].color = color;
221 vertices[2].color = color;
222
223 vertices[0].tex_coord = { 0, 0 };
224 vertices[1].tex_coord = { 0, 0 };
225 vertices[2].tex_coord = { 0, 0 };
226
227 SDL_RenderGeometry(GameEngine::renderer, nullptr, vertices, 3, nullptr, 0);
228}
229//----------------------------------------------------------
230// Draws a filled hexagon using SDL_RenderGeometry
233 float radius,
234 SDL_FColor color)
235{
237
238 const int numSides = 6;
240 int indices[numSides * 3];
241
242 // Transform center through camera (applies rotation, zoom, position)
243 Vector screenCenter = cam.isActive ? cam.WorldToScreen(center) : center;
244
245 // Le centre du polygone
246 vertices[0].position = screenCenter.ToFPoint();
247 vertices[0].color = color;
248 vertices[0].tex_coord = { 0, 0 };
249
250 // Calculate vertices in world space, then transform each through camera
251 // This ensures rotation is applied correctly by WorldToScreen
252 for (int i = 0; i < numSides; ++i) {
254 center.x + radius * HEXAGON_COS_ANGLES[i],
255 center.y + radius * HEXAGON_SIN_ANGLES[i],
256 0.0f
257 );
258
259 Vector screenVertex = cam.isActive ? cam.WorldToScreen(worldVertex) : worldVertex;
260
261 vertices[i + 1].position = screenVertex.ToFPoint();
262 vertices[i + 1].color = color;
263 vertices[i + 1].tex_coord = { 0, 0 };
264 }
265
266 // Cr�e 6 triangles reliant le centre et les sommets du bord
267 for (int i = 0; i < numSides; ++i) {
268 int next = (i + 1) % numSides;
269 indices[i * 3 + 0] = 0; // centre
270 indices[i * 3 + 1] = i + 1; // sommet actuel
271 indices[i * 3 + 2] = next + 1; // sommet suivant
272 }
273
274 // Rendu de la g�om�trie
276}
277//----------------------------------------------------------
278// Draw hexagon outline
279void Draw_Hexagon(Vector center, float radius, SDL_Color color)
280{
282
283 const int numSides = 6;
285
286 // Calculate vertices in world space, then transform each through camera
287 // This ensures rotation is applied correctly by WorldToScreen
288 for (int i = 0; i < numSides; ++i) {
290 center.x + radius * HEXAGON_COS_ANGLES[i],
291 center.y + radius * HEXAGON_SIN_ANGLES[i],
292 0.0f
293 );
294
295 verts[i] = cam.isActive ? cam.WorldToScreen(worldVertex) : worldVertex;
296 }
297
298 // Apply color
299 SDL_SetRenderDrawColor(GameEngine::renderer, color.r, color.g, color.b, color.a);
300
301 // Draw lines between consecutive vertices
302 for (int i = 0; i < numSides; ++i) {
303 int next = (i + 1) % numSides;
305 }
306}
307//----------------------------------------------------------
308// Draw rectangle outline with float coordinates
310{
312
313 if (!cam.isActive) {
314 // Legacy screen-space rendering
315 SDL_SetRenderDrawColor(GameEngine::renderer, color.r, color.g, color.b, color.a);
317 SDL_RenderLine(GameEngine::renderer, rect->x + rect->w, rect->y, rect->x + rect->w, rect->y + rect->h);
318 SDL_RenderLine(GameEngine::renderer, rect->x + rect->w, rect->y + rect->h, rect->x, rect->y + rect->h);
320 return;
321 }
322
323 // Transform 4 corners to screen space
324 Vector corners[4] = {
325 Vector(rect->x, rect->y, 0.0f),
326 Vector(rect->x + rect->w, rect->y, 0.0f),
327 Vector(rect->x + rect->w, rect->y + rect->h, 0.0f),
328 Vector(rect->x, rect->y + rect->h, 0.0f)
329 };
330
332 for (int i = 0; i < 4; ++i) {
333 screenCorners[i] = cam.WorldToScreen(corners[i]);
334 }
335
336 SDL_SetRenderDrawColor(GameEngine::renderer, color.r, color.g, color.b, color.a);
337 for (int i = 0; i < 4; ++i) {
338 int next = (i + 1) % 4;
342 }
343}
344//----------------------------------------------------------
345void Draw_Text(const std::string& text, const SDL_FRect* rect, SDL_Color textcolor, SDL_Color backgroundcolor)
346{
348 SDL_FRect dst = *rect;
349
350 if (cam.isActive) {
351 Vector worldTopLeft(rect->x, rect->y, 0.0f);
352 Vector worldBottomRight(rect->x + rect->w, rect->y + rect->h, 0.0f);
353 Vector screenTopLeft = cam.WorldToScreen(worldTopLeft);
355 dst.x = screenTopLeft.x;
356 dst.y = screenTopLeft.y;
359 }
360
361 if (backgroundcolor.a > 0) {
363 SDL_SetRenderDrawColor(GameEngine::renderer, backgroundcolor.r, backgroundcolor.g, backgroundcolor.b, backgroundcolor.a);
365 }
366
368 SDL_RenderDebugText(GameEngine::renderer, dst.x, dst.y, text.c_str());
369}
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
Core game engine class.
static SDL_Renderer * renderer
Main SDL renderer.
Definition GameEngine.h:129
const CameraTransform & GetActiveCamera() const
Get the currently active camera Returns identity transform (no transformation) if none is set.
static RenderContext & Get()
SDL_FPoint ToFPoint() const
Definition vector.h:59
float x
Definition vector.h:27
void Draw_Triangle(Vector p1, Vector p2, Vector p3)
Definition drawing.cpp:178
void Draw_FilledCircle(int cx, int cy, int radius)
Definition drawing.cpp:135
void Draw_Text(const std::string &text, const SDL_FRect *rect, SDL_Color textcolor, SDL_Color backgroundcolor)
Definition drawing.cpp:345
static SDL_Color ToColor(const SDL_FColor &f)
Definition drawing.cpp:53
void Draw_Rectangle(const SDL_FRect *rect, SDL_Color color)
Definition drawing.cpp:309
static const float PI
Definition drawing.cpp:20
static SDL_FColor ToFColor(const SDL_Color &c)
Definition drawing.cpp:43
void Draw_FilledTriangle(const Vector &p1, const Vector &p2, const Vector &p3, SDL_FColor color)
Definition drawing.cpp:201
void Draw_Hexagon(Vector center, float radius, SDL_Color color)
Definition drawing.cpp:279
void Draw_FilledHexagon(Vector center, float radius, SDL_FColor color)
Definition drawing.cpp:231
static const float HEXAGON_COS_ANGLES[6]
Definition drawing.cpp:24
void Draw_Circle(int cx, int cy, int radius)
Definition drawing.cpp:69
static const float HEXAGON_SIN_ANGLES[6]
Definition drawing.cpp:33