Olympe Engine
2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
Source
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)
20
static
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
24
static
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
33
static
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
43
static
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
53
static
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
69
void
Draw_Circle
(
int
cx
,
int
cy
,
int
radius)
70
{
71
const
CameraTransform
&
cam
=
RenderContext::Get
().
GetActiveCamera
();
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
135
void
Draw_FilledCircle
(
int
cx
,
int
cy
,
int
radius)
136
{
137
const
CameraTransform
&
cam
=
RenderContext::Get
().
GetActiveCamera
();
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
178
void
Draw_Triangle
(
Vector
p1
,
Vector
p2
,
Vector
p3
)
179
{
180
const
CameraTransform
&
cam
=
RenderContext::Get
().
GetActiveCamera
();
181
182
if
(!
cam
.isActive) {
183
// Legacy screen-space rendering
184
SDL_RenderLine
(
GameEngine::renderer
,
p1
.x,
p1
.y,
p2
.x,
p2
.y);
185
SDL_RenderLine
(
GameEngine::renderer
,
p2
.x,
p2
.y,
p3
.x,
p3
.y);
186
SDL_RenderLine
(
GameEngine::renderer
,
p3
.x,
p3
.y,
p1
.x,
p1
.y);
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
195
SDL_RenderLine
(
GameEngine::renderer
,
s1
.x,
s1
.y,
s2
.x,
s2
.y);
196
SDL_RenderLine
(
GameEngine::renderer
,
s2
.x,
s2
.y,
s3
.x,
s3
.y);
197
SDL_RenderLine
(
GameEngine::renderer
,
s3
.x,
s3
.y,
s1
.x,
s1
.y);
198
}
199
//----------------------------------------------------------
200
// Draws a filled triangle using SDL_RenderGeometry
201
void
Draw_FilledTriangle
(
202
const
Vector
&
p1
,
203
const
Vector
&
p2
,
204
const
Vector
&
p3
,
205
SDL_FColor
color)
206
{
207
const
CameraTransform
&
cam
=
RenderContext::Get
().
GetActiveCamera
();
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
213
SDL_Vertex
vertices
[3];
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
231
void
Draw_FilledHexagon
(
232
Vector
center
,
233
float
radius,
234
SDL_FColor
color)
235
{
236
const
CameraTransform
&
cam
=
RenderContext::Get
().
GetActiveCamera
();
237
238
const
int
numSides
= 6;
239
SDL_Vertex
vertices
[
numSides
+ 1];
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
) {
253
Vector
worldVertex
(
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
275
SDL_RenderGeometry
(
GameEngine::renderer
,
nullptr
,
vertices
,
numSides
+ 1,
indices
,
numSides
* 3);
276
}
277
//----------------------------------------------------------
278
// Draw hexagon outline
279
void
Draw_Hexagon
(
Vector
center
,
float
radius,
SDL_Color
color)
280
{
281
const
CameraTransform
&
cam
=
RenderContext::Get
().
GetActiveCamera
();
282
283
const
int
numSides
= 6;
284
Vector
verts
[
numSides
];
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
) {
289
Vector
worldVertex
(
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
;
304
SDL_RenderLine
(
GameEngine::renderer
,
verts
[
i
].x,
verts
[
i
].y,
verts
[
next
].x,
verts
[
next
].y);
305
}
306
}
307
//----------------------------------------------------------
308
// Draw rectangle outline with float coordinates
309
void
Draw_Rectangle
(
const
SDL_FRect
*
rect
,
SDL_Color
color)
310
{
311
const
CameraTransform
&
cam
=
RenderContext::Get
().
GetActiveCamera
();
312
313
if
(!
cam
.isActive) {
314
// Legacy screen-space rendering
315
SDL_SetRenderDrawColor
(
GameEngine::renderer
, color.r, color.g, color.b, color.a);
316
SDL_RenderLine
(
GameEngine::renderer
,
rect
->x,
rect
->y,
rect
->x +
rect
->w,
rect
->y);
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);
319
SDL_RenderLine
(
GameEngine::renderer
,
rect
->x,
rect
->y +
rect
->h,
rect
->x,
rect
->y);
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
331
Vector
screenCorners
[4];
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;
339
SDL_RenderLine
(
GameEngine::renderer
,
340
screenCorners
[
i
].x,
screenCorners
[
i
].y,
341
screenCorners
[
next
].x,
screenCorners
[
next
].y);
342
}
343
}
344
//----------------------------------------------------------
345
void
Draw_Text
(
const
std::string& text,
const
SDL_FRect
*
rect
,
SDL_Color
textcolor
,
SDL_Color
backgroundcolor)
346
{
347
const
CameraTransform
&
cam
=
RenderContext::Get
().
GetActiveCamera
();
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
);
354
Vector
screenBottomRight
=
cam
.WorldToScreen(
worldBottomRight
);
355
dst
.
x
=
screenTopLeft
.x;
356
dst
.y =
screenTopLeft
.y;
357
dst
.w =
screenBottomRight
.x -
screenTopLeft
.x;
358
dst
.h =
screenBottomRight
.y -
screenTopLeft
.y;
359
}
360
361
if
(backgroundcolor.a > 0) {
362
SDL_SetRenderDrawBlendMode
(
GameEngine::renderer
,
SDL_BLENDMODE_BLEND
);
363
SDL_SetRenderDrawColor
(
GameEngine::renderer
, backgroundcolor.r, backgroundcolor.g, backgroundcolor.b, backgroundcolor.a);
364
SDL_RenderFillRect
(
GameEngine::renderer
, &
dst
);
365
}
366
367
SDL_SetRenderDrawColor
(
GameEngine::renderer
,
textcolor
.r,
textcolor
.g,
textcolor
.b,
textcolor
.a);
368
SDL_RenderDebugText
(
GameEngine::renderer
,
dst
.x,
dst
.y, text.c_str());
369
}
GetComponentTypeID_Static
ComponentTypeID GetComponentTypeID_Static()
Definition
ECS_Entity.h:56
GameEngine.h
Core game engine class.
RenderContext.h
GameEngine::renderer
static SDL_Renderer * renderer
Main SDL renderer.
Definition
GameEngine.h:129
RenderContext::GetActiveCamera
const CameraTransform & GetActiveCamera() const
Get the currently active camera Returns identity transform (no transformation) if none is set.
Definition
RenderContext.h:36
RenderContext::Get
static RenderContext & Get()
Definition
RenderContext.h:22
Vector
Definition
vector.h:24
Vector::ToFPoint
SDL_FPoint ToFPoint() const
Definition
vector.h:59
Vector::x
float x
Definition
vector.h:27
Draw_Triangle
void Draw_Triangle(Vector p1, Vector p2, Vector p3)
Definition
drawing.cpp:178
Draw_FilledCircle
void Draw_FilledCircle(int cx, int cy, int radius)
Definition
drawing.cpp:135
Draw_Text
void Draw_Text(const std::string &text, const SDL_FRect *rect, SDL_Color textcolor, SDL_Color backgroundcolor)
Definition
drawing.cpp:345
ToColor
static SDL_Color ToColor(const SDL_FColor &f)
Definition
drawing.cpp:53
Draw_Rectangle
void Draw_Rectangle(const SDL_FRect *rect, SDL_Color color)
Definition
drawing.cpp:309
PI
static const float PI
Definition
drawing.cpp:20
ToFColor
static SDL_FColor ToFColor(const SDL_Color &c)
Definition
drawing.cpp:43
Draw_FilledTriangle
void Draw_FilledTriangle(const Vector &p1, const Vector &p2, const Vector &p3, SDL_FColor color)
Definition
drawing.cpp:201
Draw_Hexagon
void Draw_Hexagon(Vector center, float radius, SDL_Color color)
Definition
drawing.cpp:279
Draw_FilledHexagon
void Draw_FilledHexagon(Vector center, float radius, SDL_FColor color)
Definition
drawing.cpp:231
HEXAGON_COS_ANGLES
static const float HEXAGON_COS_ANGLES[6]
Definition
drawing.cpp:24
Draw_Circle
void Draw_Circle(int cx, int cy, int radius)
Definition
drawing.cpp:69
HEXAGON_SIN_ANGLES
static const float HEXAGON_SIN_ANGLES[6]
Definition
drawing.cpp:33
drawing.h
CameraTransform
Definition
ECS_Systems.h:310
Generated on Tue Feb 17 2026 13:49:10 for Olympe Engine by
1.9.8