├── My_First_Cpp_Game
├── platform_common.cpp
├── utils.cpp
├── My_First_Cpp_Game.vcxproj.filters
├── win32_platform.cpp
├── game.cpp
├── My_First_Cpp_Game.vcxproj
└── renderer.cpp
├── README.md
├── LICENSE
└── My_First_Cpp_Game.sln
/My_First_Cpp_Game/platform_common.cpp:
--------------------------------------------------------------------------------
1 | struct Button_State {
2 | bool is_down;
3 | bool changed;
4 | };
5 |
6 | enum {
7 | BUTTON_UP,
8 | BUTTON_DOWN,
9 | BUTTON_W,
10 | BUTTON_S,
11 | BUTTON_LEFT,
12 | BUTTON_RIGHT,
13 | BUTTON_ENTER,
14 |
15 | BUTTON_COUNT, // Should be the last item
16 | };
17 |
18 | struct Input {
19 | Button_State buttons[BUTTON_COUNT];
20 | };
--------------------------------------------------------------------------------
/My_First_Cpp_Game/utils.cpp:
--------------------------------------------------------------------------------
1 | typedef char s8;
2 | typedef unsigned char u8;
3 | typedef short s16;
4 | typedef unsigned short u16;
5 | typedef int s32;
6 | typedef unsigned int u32;
7 | typedef long long s64;
8 | typedef unsigned long long u64;
9 |
10 | #define global_variable static
11 | #define internal static
12 |
13 | inline int
14 | clamp(int min, int val, int max) {
15 | if (val < min) return min;
16 | if (val > max) return max;
17 | return val;
18 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [Tutorial] How to program a game in C++ (Pong)
2 | Ever wondered how are games programmed? In this series of tutorials, I will teach you how to make a game in C++. Hopefully, you will learn the fundamentals of game programming and be able to make your own games by the end!
3 |
4 | # Step-by-Step, Beginner-Friendly Tutorials
5 | This game was created accompanied by several tutorials that will guide you through the creation of a game an the engine!
6 |
7 | Check out the tutorial series:
8 | https://www.youtube.com/playlist?list=PL7Ej6SUky135IAAR3PFCFyiVwanauRqj3
9 |
10 | This is the first tutorial:
11 | https://www.youtube.com/watch?v=luuyjjOxnUI
12 |
13 | The final result on Itch.io:
14 | https://danzaidan.itch.io/pong-learn-programming
15 |
16 |
17 | I hope you like it!
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | LICENSE:
2 |
3 | This license is supposed to be as permissive as possible. So attribution is not required, but appreciated. A donation is also appreciated :) .
4 |
5 | This software is dual-licensed to the PUBLIC DOMAIN and under the following license: you are granted a perpetual, irrevocable license to copy, modify, publish, and distribute the software and its source code as you see fit.
6 |
7 | The software is provided "as is", without warranty of any kind, express of implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfrigement. In no event shall the author be liable for any claim, damages of other liability, whether in an action of contract, tort of otherwise, arising from, out of or in connection with the software or the use or other dealing in the software.
8 |
--------------------------------------------------------------------------------
/My_First_Cpp_Game/My_First_Cpp_Game.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 | Source Files
23 |
24 |
25 | Source Files
26 |
27 |
28 | Source Files
29 |
30 |
31 | Source Files
32 |
33 |
34 |
--------------------------------------------------------------------------------
/My_First_Cpp_Game.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29123.88
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "My_First_Cpp_Game", "My_First_Cpp_Game\My_First_Cpp_Game.vcxproj", "{F53E6F7F-074B-4374-9FAB-E3D50AD64315}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {F53E6F7F-074B-4374-9FAB-E3D50AD64315}.Debug|x64.ActiveCfg = Debug|x64
17 | {F53E6F7F-074B-4374-9FAB-E3D50AD64315}.Debug|x64.Build.0 = Debug|x64
18 | {F53E6F7F-074B-4374-9FAB-E3D50AD64315}.Debug|x86.ActiveCfg = Debug|Win32
19 | {F53E6F7F-074B-4374-9FAB-E3D50AD64315}.Debug|x86.Build.0 = Debug|Win32
20 | {F53E6F7F-074B-4374-9FAB-E3D50AD64315}.Release|x64.ActiveCfg = Release|x64
21 | {F53E6F7F-074B-4374-9FAB-E3D50AD64315}.Release|x64.Build.0 = Release|x64
22 | {F53E6F7F-074B-4374-9FAB-E3D50AD64315}.Release|x86.ActiveCfg = Release|Win32
23 | {F53E6F7F-074B-4374-9FAB-E3D50AD64315}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {740DDA96-7DCA-4D76-B498-189514B26EEF}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/My_First_Cpp_Game/win32_platform.cpp:
--------------------------------------------------------------------------------
1 | #include "utils.cpp"
2 | #include
3 |
4 | global_variable bool running = true;
5 |
6 | struct Render_State {
7 | int height, width;
8 | void* memory;
9 |
10 | BITMAPINFO bitmap_info;
11 | };
12 |
13 | global_variable Render_State render_state;
14 |
15 | #include "platform_common.cpp"
16 | #include "renderer.cpp"
17 | #include "game.cpp"
18 |
19 | LRESULT CALLBACK window_callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
20 | LRESULT result = 0;
21 |
22 | switch (uMsg) {
23 | case WM_CLOSE:
24 | case WM_DESTROY: {
25 | running = false;
26 | } break;
27 |
28 | case WM_SIZE: {
29 | RECT rect;
30 | GetClientRect(hwnd, &rect);
31 | render_state.width = rect.right - rect.left;
32 | render_state.height = rect.bottom - rect.top;
33 |
34 | int size = render_state.width * render_state.height * sizeof(unsigned int);
35 |
36 | if (render_state.memory) VirtualFree(render_state.memory, 0, MEM_RELEASE);
37 | render_state.memory = VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
38 |
39 | render_state.bitmap_info.bmiHeader.biSize = sizeof(render_state.bitmap_info.bmiHeader);
40 | render_state.bitmap_info.bmiHeader.biWidth = render_state.width;
41 | render_state.bitmap_info.bmiHeader.biHeight = render_state.height;
42 | render_state.bitmap_info.bmiHeader.biPlanes = 1;
43 | render_state.bitmap_info.bmiHeader.biBitCount = 32;
44 | render_state.bitmap_info.bmiHeader.biCompression = BI_RGB;
45 |
46 | } break;
47 |
48 | default: {
49 | result = DefWindowProc(hwnd, uMsg, wParam, lParam);
50 | }
51 | }
52 | return result;
53 | }
54 |
55 | int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
56 |
57 | ShowCursor(FALSE);
58 |
59 | // Create Window Class
60 | WNDCLASS window_class = {};
61 | window_class.style = CS_HREDRAW | CS_VREDRAW;
62 | window_class.lpszClassName = "Game Window Class";
63 | window_class.lpfnWndProc = window_callback;
64 |
65 | // Register Class
66 | RegisterClass(&window_class);
67 |
68 | // Create Window
69 | HWND window = CreateWindow(window_class.lpszClassName, "Pong - Tutorial", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 1280, 720, 0, 0, hInstance, 0);
70 | {
71 | //Fullscreen
72 | SetWindowLong(window, GWL_STYLE, GetWindowLong(window, GWL_STYLE) & ~WS_OVERLAPPEDWINDOW);
73 | MONITORINFO mi = { sizeof(mi) };
74 | GetMonitorInfo(MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY), &mi);
75 | SetWindowPos(window, HWND_TOP, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top, SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
76 | }
77 |
78 | HDC hdc = GetDC(window);
79 |
80 | Input input = {};
81 |
82 | float delta_time = 0.016666f;
83 | LARGE_INTEGER frame_begin_time;
84 | QueryPerformanceCounter(&frame_begin_time);
85 |
86 | float performance_frequency;
87 | {
88 | LARGE_INTEGER perf;
89 | QueryPerformanceFrequency(&perf);
90 | performance_frequency = (float)perf.QuadPart;
91 | }
92 |
93 | while (running) {
94 | // Input
95 | MSG message;
96 |
97 | for (int i = 0; i < BUTTON_COUNT; i++) {
98 | input.buttons[i].changed = false;
99 | }
100 |
101 | while (PeekMessage(&message, window, 0, 0, PM_REMOVE)) {
102 |
103 | switch (message.message) {
104 | case WM_KEYUP:
105 | case WM_KEYDOWN: {
106 | u32 vk_code = (u32)message.wParam;
107 | bool is_down = ((message.lParam & (1 << 31)) == 0);
108 |
109 | #define process_button(b, vk)\
110 | case vk: {\
111 | input.buttons[b].changed = is_down != input.buttons[b].is_down;\
112 | input.buttons[b].is_down = is_down;\
113 | } break;
114 |
115 | switch (vk_code) {
116 | process_button(BUTTON_UP, VK_UP);
117 | process_button(BUTTON_DOWN, VK_DOWN);
118 | process_button(BUTTON_W, 'W');
119 | process_button(BUTTON_S, 'S');
120 | process_button(BUTTON_LEFT, VK_LEFT);
121 | process_button(BUTTON_RIGHT, VK_RIGHT);
122 | process_button(BUTTON_ENTER, VK_RETURN);
123 | }
124 | } break;
125 |
126 | default: {
127 | TranslateMessage(&message);
128 | DispatchMessage(&message);
129 | }
130 | }
131 |
132 | }
133 |
134 | // Simulate
135 | simulate_game(&input, delta_time);
136 |
137 | // Render
138 | StretchDIBits(hdc, 0, 0, render_state.width, render_state.height, 0, 0, render_state.width, render_state.height, render_state.memory, &render_state.bitmap_info, DIB_RGB_COLORS, SRCCOPY);
139 |
140 | LARGE_INTEGER frame_end_time;
141 | QueryPerformanceCounter(&frame_end_time);
142 | delta_time = (float)(frame_end_time.QuadPart - frame_begin_time.QuadPart) / performance_frequency;
143 | frame_begin_time = frame_end_time;
144 | }
145 |
146 | }
--------------------------------------------------------------------------------
/My_First_Cpp_Game/game.cpp:
--------------------------------------------------------------------------------
1 | #define is_down(b) input->buttons[b].is_down
2 | #define pressed(b) (input->buttons[b].is_down && input->buttons[b].changed)
3 | #define released(b) (!input->buttons[b].is_down && input->buttons[b].changed)
4 |
5 | float player_1_p, player_1_dp, player_2_p, player_2_dp;
6 | float arena_half_size_x = 85, arena_half_size_y = 45;
7 | float player_half_size_x = 2.5, player_half_size_y = 12;
8 | float ball_p_x, ball_p_y, ball_dp_x = 130, ball_dp_y, ball_half_size = 1;
9 |
10 | int player_1_score, player_2_score;
11 |
12 | internal void
13 | simulate_player(float *p, float *dp, float ddp, float dt) {
14 | ddp -= *dp * 10.f;
15 |
16 | *p = *p + *dp * dt + ddp * dt * dt * .5f;
17 | *dp = *dp + ddp * dt;
18 |
19 | if (*p + player_half_size_y > arena_half_size_y) {
20 | *p = arena_half_size_y - player_half_size_y;
21 | *dp = 0;
22 | }
23 | else if (*p - player_half_size_y < -arena_half_size_y) {
24 | *p = -arena_half_size_y + player_half_size_y;
25 | *dp = 0;
26 | }
27 | }
28 |
29 | internal bool
30 | aabb_vs_aabb(float p1x, float p1y, float hs1x, float hs1y,
31 | float p2x, float p2y, float hs2x, float hs2y) {
32 | return (p1x + hs1x > p2x - hs2x &&
33 | p1x - hs1x < p2x + hs2x &&
34 | p1y + hs1y > p2y - hs2y &&
35 | p1y + hs1y < p2y + hs2y);
36 | }
37 |
38 | enum Gamemode {
39 | GM_MENU,
40 | GM_GAMEPLAY,
41 | };
42 |
43 | Gamemode current_gamemode;
44 | int hot_button;
45 | bool enemy_is_ai;
46 |
47 | internal void
48 | simulate_game(Input* input, float dt) {
49 | draw_rect(0, 0, arena_half_size_x, arena_half_size_y, 0xffaa33);
50 | draw_arena_borders(arena_half_size_x, arena_half_size_y, 0xff5500);
51 |
52 |
53 | if (current_gamemode == GM_GAMEPLAY) {
54 | float player_1_ddp = 0.f;
55 | if (!enemy_is_ai) {
56 | if (is_down(BUTTON_UP)) player_1_ddp += 2000;
57 | if (is_down(BUTTON_DOWN)) player_1_ddp -= 2000;
58 | } else {
59 | //if (ball_p_y > player_1_p+2.f) player_1_ddp += 1300;
60 | //if (ball_p_y < player_1_p-2.f) player_1_ddp -= 1300;
61 | player_1_ddp = (ball_p_y - player_1_p) * 100;
62 | if (player_1_ddp > 1300) player_1_ddp = 1300;
63 | if (player_1_ddp < -1300) player_1_ddp = -1300;
64 | }
65 |
66 | float player_2_ddp = 0.f;
67 | if (is_down(BUTTON_W)) player_2_ddp += 2000;
68 | if (is_down(BUTTON_S)) player_2_ddp -= 2000;
69 |
70 | simulate_player(&player_1_p, &player_1_dp, player_1_ddp, dt);
71 | simulate_player(&player_2_p, &player_2_dp, player_2_ddp, dt);
72 |
73 |
74 | // Simulate Ball
75 | {
76 | ball_p_x += ball_dp_x * dt;
77 | ball_p_y += ball_dp_y * dt;
78 |
79 | if (aabb_vs_aabb(ball_p_x, ball_p_y, ball_half_size, ball_half_size, 80, player_1_p, player_half_size_x, player_half_size_y)) {
80 | ball_p_x = 80 - player_half_size_x - ball_half_size;
81 | ball_dp_x *= -1;
82 | ball_dp_y = (ball_p_y - player_1_p) * 2 + player_1_dp * .75f;
83 | } else if (aabb_vs_aabb(ball_p_x, ball_p_y, ball_half_size, ball_half_size, -80, player_2_p, player_half_size_x, player_half_size_y)) {
84 | ball_p_x = -80 + player_half_size_x + ball_half_size;
85 | ball_dp_x *= -1;
86 | ball_dp_y = (ball_p_y - player_2_p) * 2 + player_2_dp * .75f;
87 | }
88 |
89 | if (ball_p_y + ball_half_size > arena_half_size_y) {
90 | ball_p_y = arena_half_size_y - ball_half_size;
91 | ball_dp_y *= -1;
92 | } else if (ball_p_y - ball_half_size < -arena_half_size_y) {
93 | ball_p_y = -arena_half_size_y + ball_half_size;
94 | ball_dp_y *= -1;
95 | }
96 |
97 | if (ball_p_x + ball_half_size > arena_half_size_x) {
98 | ball_dp_x *= -1;
99 | ball_dp_y = 0;
100 | ball_p_x = 0;
101 | ball_p_y = 0;
102 | player_1_score++;
103 | } else if (ball_p_x - ball_half_size < -arena_half_size_x) {
104 | ball_dp_x *= -1;
105 | ball_dp_y = 0;
106 | ball_p_x = 0;
107 | ball_p_y = 0;
108 | player_2_score++;
109 | }
110 | }
111 |
112 | draw_number(player_1_score, -10, 40, 1.f, 0xbbffbb);
113 | draw_number(player_2_score, 10, 40, 1.f, 0xbbffbb);
114 |
115 | // Rendering
116 | draw_rect(ball_p_x, ball_p_y, ball_half_size, ball_half_size, 0xffffff);
117 |
118 | draw_rect(80, player_1_p, player_half_size_x, player_half_size_y, 0xff0000);
119 | draw_rect(-80, player_2_p, player_half_size_x, player_half_size_y, 0xff0000);
120 |
121 | } else {
122 |
123 | if (pressed(BUTTON_LEFT) || pressed(BUTTON_RIGHT)) {
124 | hot_button = !hot_button;
125 | }
126 |
127 |
128 |
129 | if (pressed(BUTTON_ENTER)) {
130 | current_gamemode = GM_GAMEPLAY;
131 | enemy_is_ai = hot_button ? 0 : 1;
132 | }
133 |
134 | if (hot_button == 0) {
135 | draw_text("SINGLE PLAYER", -80, -10, 1, 0xff0000);
136 | draw_text("MULTIPLAYER", 20, -10, 1, 0xaaaaaa);
137 | } else {
138 | draw_text("SINGLE PLAYER", -80, -10, 1, 0xaaaaaa);
139 | draw_text("MULTIPLAYER", 20, -10, 1, 0xff0000);
140 | }
141 |
142 | draw_text("PONG TUTORIAL", -73, 40, 2, 0xffffff);
143 | draw_text("WATCH THE STEP BY STEP TUTORIAL ON", -73, 22, .75, 0xffffff);
144 | draw_text("YOUTUBE.COM/DANZAIDAN", -73, 15, 1.22, 0xffffff);
145 |
146 | }
147 | }
--------------------------------------------------------------------------------
/My_First_Cpp_Game/My_First_Cpp_Game.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | {F53E6F7F-074B-4374-9FAB-E3D50AD64315}
24 | MyFirstCppGame
25 | 10.0
26 |
27 |
28 |
29 | Application
30 | true
31 | v142
32 | MultiByte
33 |
34 |
35 | Application
36 | false
37 | v142
38 | true
39 | MultiByte
40 |
41 |
42 | Application
43 | true
44 | v142
45 | MultiByte
46 |
47 |
48 | Application
49 | false
50 | v142
51 | true
52 | MultiByte
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | Level3
76 | Disabled
77 | true
78 | true
79 |
80 |
81 | Windows
82 |
83 |
84 |
85 |
86 | Level3
87 | Disabled
88 | true
89 | true
90 |
91 |
92 | Windows
93 |
94 |
95 |
96 |
97 | Level3
98 | MaxSpeed
99 | true
100 | true
101 | true
102 | true
103 |
104 |
105 | Windows
106 | true
107 | true
108 |
109 |
110 |
111 |
112 | Level3
113 | MaxSpeed
114 | true
115 | true
116 | true
117 | true
118 |
119 |
120 | Windows
121 | true
122 | true
123 |
124 |
125 |
126 |
127 | true
128 | true
129 | true
130 | true
131 |
132 |
133 | true
134 | true
135 | true
136 | true
137 |
138 |
139 | true
140 | true
141 | true
142 | true
143 |
144 |
145 | true
146 | true
147 | true
148 | true
149 |
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/My_First_Cpp_Game/renderer.cpp:
--------------------------------------------------------------------------------
1 | internal void
2 | clear_screen(u32 color) {
3 | unsigned int* pixel = (u32*)render_state.memory;
4 | for (int y = 0; y < render_state.height; y++) {
5 | for (int x = 0; x < render_state.width; x++) {
6 | *pixel++ = color;
7 | }
8 | }
9 | }
10 |
11 | internal void
12 | draw_rect_in_pixels(int x0, int y0, int x1, int y1, u32 color) {
13 |
14 | x0 = clamp(0, x0, render_state.width);
15 | x1 = clamp(0, x1, render_state.width);
16 | y0 = clamp(0, y0, render_state.height);
17 | y1 = clamp(0, y1, render_state.height);
18 |
19 | for (int y = y0; y < y1; y++) {
20 | u32* pixel = (u32*)render_state.memory + x0 + y*render_state.width;
21 | for (int x = x0; x < x1; x++) {
22 | *pixel++ = color;
23 | }
24 | }
25 | }
26 |
27 | global_variable float render_scale = 0.01f;
28 |
29 | internal void
30 | draw_arena_borders(float arena_x, float arena_y, u32 color) {
31 | arena_x *= render_state.height * render_scale;
32 | arena_y *= render_state.height * render_scale;
33 |
34 | int x0 = (int)((float)render_state.width * .5f - arena_x);
35 | int x1 = (int)((float)render_state.width * .5f + arena_x);
36 | int y0 = (int)((float)render_state.height * .5f - arena_y);
37 | int y1 = (int)((float)render_state.height * .5f + arena_y);
38 |
39 | draw_rect_in_pixels(0, 0, render_state.width, y0, color);
40 | draw_rect_in_pixels(0, y1, x1, render_state.height, color);
41 | draw_rect_in_pixels(0, y0, x0, y1, color);
42 | draw_rect_in_pixels(x1, y0, render_state.width, render_state.height, color);
43 | }
44 |
45 | internal void
46 | draw_rect(float x, float y, float half_size_x, float half_size_y, u32 color) {
47 |
48 | x *= render_state.height*render_scale;
49 | y *= render_state.height * render_scale;
50 | half_size_x *= render_state.height * render_scale;
51 | half_size_y *= render_state.height * render_scale;
52 |
53 | x += render_state.width / 2.f;
54 | y += render_state.height / 2.f;
55 |
56 | // Change to pixels
57 | int x0 = x - half_size_x;
58 | int x1 = x + half_size_x;
59 | int y0 = y - half_size_y;
60 | int y1 = y + half_size_y;
61 |
62 | draw_rect_in_pixels(x0, y0, x1, y1, color);
63 | }
64 |
65 | const char* letters[][7] = {
66 | " 00",
67 | "0 0",
68 | "0 0",
69 | "0000",
70 | "0 0",
71 | "0 0",
72 | "0 0",
73 |
74 | "000",
75 | "0 0",
76 | "0 0",
77 | "000",
78 | "0 0",
79 | "0 0",
80 | "000",
81 |
82 | " 000",
83 | "0",
84 | "0",
85 | "0",
86 | "0",
87 | "0",
88 | " 000",
89 |
90 | "000",
91 | "0 0",
92 | "0 0",
93 | "0 0",
94 | "0 0",
95 | "0 0",
96 | "000",
97 |
98 | "0000",
99 | "0",
100 | "0",
101 | "000",
102 | "0",
103 | "0",
104 | "0000",
105 |
106 | "0000",
107 | "0",
108 | "0",
109 | "000",
110 | "0",
111 | "0",
112 | "0",
113 |
114 | " 000",
115 | "0",
116 | "0",
117 | "0 00",
118 | "0 0",
119 | "0 0",
120 | " 000",
121 |
122 | "0 0",
123 | "0 0",
124 | "0 0",
125 | "0000",
126 | "0 0",
127 | "0 0",
128 | "0 0",
129 |
130 | "000",
131 | " 0",
132 | " 0",
133 | " 0",
134 | " 0",
135 | " 0",
136 | "000",
137 |
138 | " 000",
139 | " 0",
140 | " 0",
141 | " 0",
142 | "0 0",
143 | "0 0",
144 | " 000",
145 |
146 | "0 0",
147 | "0 0",
148 | "0 0",
149 | "00",
150 | "0 0",
151 | "0 0",
152 | "0 0",
153 |
154 | "0",
155 | "0",
156 | "0",
157 | "0",
158 | "0",
159 | "0",
160 | "0000",
161 |
162 | "00 00",
163 | "0 0 0",
164 | "0 0 0",
165 | "0 0",
166 | "0 0",
167 | "0 0",
168 | "0 0",
169 |
170 | "00 0",
171 | "0 0 0",
172 | "0 0 0",
173 | "0 0 0",
174 | "0 0 0",
175 | "0 0 0",
176 | "0 00",
177 |
178 | "0000",
179 | "0 0",
180 | "0 0",
181 | "0 0",
182 | "0 0",
183 | "0 0",
184 | "0000",
185 |
186 | " 000",
187 | "0 0",
188 | "0 0",
189 | "000",
190 | "0",
191 | "0",
192 | "0",
193 |
194 | " 000 ",
195 | "0 0",
196 | "0 0",
197 | "0 0",
198 | "0 0 0",
199 | "0 0 ",
200 | " 00 0",
201 |
202 | "000",
203 | "0 0",
204 | "0 0",
205 | "000",
206 | "0 0",
207 | "0 0",
208 | "0 0",
209 |
210 | " 000",
211 | "0",
212 | "0 ",
213 | " 00",
214 | " 0",
215 | " 0",
216 | "000 ",
217 |
218 | "000",
219 | " 0",
220 | " 0",
221 | " 0",
222 | " 0",
223 | " 0",
224 | " 0",
225 |
226 | "0 0",
227 | "0 0",
228 | "0 0",
229 | "0 0",
230 | "0 0",
231 | "0 0",
232 | " 00",
233 |
234 | "0 0",
235 | "0 0",
236 | "0 0",
237 | "0 0",
238 | "0 0",
239 | " 0 0",
240 | " 0",
241 |
242 | "0 0 ",
243 | "0 0",
244 | "0 0",
245 | "0 0 0",
246 | "0 0 0",
247 | "0 0 0",
248 | " 0 0 ",
249 |
250 | "0 0",
251 | "0 0",
252 | " 0 0",
253 | " 0",
254 | " 0 0",
255 | "0 0",
256 | "0 0",
257 |
258 | "0 0",
259 | "0 0",
260 | " 0 0",
261 | " 0",
262 | " 0",
263 | " 0",
264 | " 0",
265 |
266 | "0000",
267 | " 0",
268 | " 0",
269 | " 0",
270 | "0",
271 | "0",
272 | "0000",
273 |
274 | "",
275 | "",
276 | "",
277 | "",
278 | "",
279 | "",
280 | "0",
281 |
282 | " 0",
283 | " 0",
284 | " 0",
285 | " 0",
286 | " 0",
287 | "0",
288 | "0",
289 | };
290 |
291 | internal void
292 | draw_text(const char *text, float x, float y, float size, u32 color) {
293 | float half_size = size * .5f;
294 | float original_y = y;
295 |
296 | while (*text) {
297 | if (*text != 32) {
298 | const char** letter;
299 | if (*text == 47) letter = letters[27];
300 | else if (*text == 46) letter = letters[26];
301 | else letter = letters[*text - 'A'];
302 | float original_x = x;
303 |
304 | for (int i = 0; i < 7; i++) {
305 | const char* row = letter[i];
306 | while (*row) {
307 | if (*row == '0') {
308 | draw_rect(x, y, half_size, half_size, color);
309 | }
310 | x += size;
311 | row++;
312 | }
313 | y -= size;
314 | x = original_x;
315 | }
316 | }
317 | text++;
318 | x += size * 6.f;
319 | y = original_y;
320 | }
321 | }
322 |
323 | internal void
324 | draw_number(int number, float x, float y, float size, u32 color) {
325 | float half_size = size * .5f;
326 |
327 | bool drew_number = false;
328 | while (number || !drew_number) {
329 | drew_number = true;
330 |
331 | int digit = number % 10;
332 | number = number / 10;
333 |
334 | switch (digit) {
335 | case 0: {
336 | draw_rect(x - size, y, half_size, 2.5f * size, color);
337 | draw_rect(x + size, y, half_size, 2.5f * size, color);
338 | draw_rect(x, y + size * 2.f, half_size, half_size, color);
339 | draw_rect(x, y - size * 2.f, half_size, half_size, color);
340 | x -= size * 4.f;
341 | } break;
342 |
343 | case 1: {
344 | draw_rect(x + size, y, half_size, 2.5f * size, color);
345 | x -= size * 2.f;
346 | } break;
347 |
348 | case 2: {
349 | draw_rect(x, y + size * 2.f, 1.5f * size, half_size, color);
350 | draw_rect(x, y, 1.5f * size, half_size, color);
351 | draw_rect(x, y - size * 2.f, 1.5f * size, half_size, color);
352 | draw_rect(x + size, y + size, half_size, half_size, color);
353 | draw_rect(x - size, y - size, half_size, half_size, color);
354 | x -= size * 4.f;
355 | } break;
356 |
357 | case 3: {
358 | draw_rect(x - half_size, y + size * 2.f, size, half_size, color);
359 | draw_rect(x - half_size, y, size, half_size, color);
360 | draw_rect(x - half_size, y - size * 2.f, size, half_size, color);
361 | draw_rect(x + size, y, half_size, 2.5f * size, color);
362 | x -= size * 4.f;
363 | } break;
364 |
365 | case 4: {
366 | draw_rect(x + size, y, half_size, 2.5f * size, color);
367 | draw_rect(x - size, y + size, half_size, 1.5f * size, color);
368 | draw_rect(x, y, half_size, half_size, color);
369 | x -= size * 4.f;
370 | } break;
371 |
372 | case 5: {
373 | draw_rect(x, y + size * 2.f, 1.5f * size, half_size, color);
374 | draw_rect(x, y, 1.5f * size, half_size, color);
375 | draw_rect(x, y - size * 2.f, 1.5f * size, half_size, color);
376 | draw_rect(x - size, y + size, half_size, half_size, color);
377 | draw_rect(x + size, y - size, half_size, half_size, color);
378 | x -= size * 4.f;
379 | } break;
380 |
381 | case 6: {
382 | draw_rect(x + half_size, y + size * 2.f, size, half_size, color);
383 | draw_rect(x + half_size, y, size, half_size, color);
384 | draw_rect(x + half_size, y - size * 2.f, size, half_size, color);
385 | draw_rect(x - size, y, half_size, 2.5f * size, color);
386 | draw_rect(x + size, y - size, half_size, half_size, color);
387 | x -= size * 4.f;
388 | } break;
389 |
390 | case 7: {
391 | draw_rect(x + size, y, half_size, 2.5f * size, color);
392 | draw_rect(x - half_size, y + size * 2.f, size, half_size, color);
393 | x -= size * 4.f;
394 | } break;
395 |
396 | case 8: {
397 | draw_rect(x - size, y, half_size, 2.5f * size, color);
398 | draw_rect(x + size, y, half_size, 2.5f * size, color);
399 | draw_rect(x, y + size * 2.f, half_size, half_size, color);
400 | draw_rect(x, y - size * 2.f, half_size, half_size, color);
401 | draw_rect(x, y, half_size, half_size, color);
402 | x -= size * 4.f;
403 | } break;
404 |
405 | case 9: {
406 | draw_rect(x - half_size, y + size * 2.f, size, half_size, color);
407 | draw_rect(x - half_size, y, size, half_size, color);
408 | draw_rect(x - half_size, y - size * 2.f, size, half_size, color);
409 | draw_rect(x + size, y, half_size, 2.5f * size, color);
410 | draw_rect(x - size, y + size, half_size, half_size, color);
411 | x -= size * 4.f;
412 | } break;
413 | }
414 |
415 | }
416 | }
--------------------------------------------------------------------------------