Skip to content

Commit 88bcc61

Browse files
committed
Added hot reloading of shaders.
1 parent 8dc3685 commit 88bcc61

File tree

9 files changed

+110
-51
lines changed

9 files changed

+110
-51
lines changed

FallingGame/Drawer.cpp

Lines changed: 70 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
Drawer::Drawer(Game& g)
1414
{
15-
1615
// standard rect EBO
1716
{
1817
unsigned int indices[] = {
@@ -28,8 +27,11 @@ Drawer::Drawer(Game& g)
2827
glBufferData(GL_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
2928
}
3029

31-
// font stuff with freetype
30+
// load all programs
31+
this->load_all_programs(g.l);
32+
3233

34+
// font stuff with freetype
3335
{
3436
FT_Library ft;
3537
if (FT_Init_FreeType(&ft)) {
@@ -76,20 +78,17 @@ Drawer::Drawer(Game& g)
7678

7779
unsigned int width = 0, height = 0;
7880

79-
static constexpr int PIX_OFFSET = 10;
81+
// the offset between characters in the texture
82+
static constexpr int PIX_OFFSET = 1;
8083

8184
for (unsigned char c = CHARACTERS_START_AT; c < CHARACTERS; c++)
8285
{
83-
// load character glyph
86+
// load character glyph
8487
if (FT_Load_Char(face, c, FT_LOAD_RENDER))
8588
{
8689
std::cout << "ERROR::FREETYTPE: Failed to load Glyph:" << c << std::endl;
8790
continue;
8891
}
89-
// generate texture
90-
//glTexImage2D(GL_TEXTURE_2D,0, GL_RED, face->glyph->bitmap.width,
91-
// face->glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE, face->glyph->bitmap.buffer
92-
//);
9392
width += face->glyph->bitmap.width + PIX_OFFSET;
9493
height = std::max(height, face->glyph->bitmap.rows);
9594
// now store character for later use
@@ -108,8 +107,6 @@ Drawer::Drawer(Game& g)
108107
glGenTextures(1, &m_main_font_tex);
109108
glBindTexture(GL_TEXTURE_2D, m_main_font_tex); // all upcoming GL_TEXTURE_2D operations now have effect on this texture object
110109

111-
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
112-
113110
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
114111
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
115112
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -168,13 +165,13 @@ Drawer::Drawer(Game& g)
168165
// make it the correct amount of data
169166
float data[CHARACTERS][U_TEXT_ATTRIBUTES_PER]; // store the width,height,bearingx,bearingy
170167
for (int i = CHARACTERS_START_AT; i < CHARACTERS; ++i) {
171-
data[i][0] = m_characters[i].width; // width
172-
data[i][1] = m_characters[i].height; // height
173-
data[i][2] = m_characters[i].bearing_x; // bearing X
174-
data[i][3] = m_characters[i].bearing_y; // bearing Y
168+
data[i][0] = (float)m_characters[i].width; // width
169+
data[i][1] = (float)m_characters[i].height; // height
170+
data[i][2] = (float)m_characters[i].bearing_x; // bearing X
171+
data[i][3] = (float)m_characters[i].bearing_y; // bearing Y
175172
}
176173

177-
glUniform4fv(glGetUniformLocation(m_text_program, "u_text"), 128, (float*)data);
174+
glUniform4fv(glGetUniformLocation(m_text_program, "u_text"), CHARACTERS, (float*)data);
178175
}
179176

180177
{
@@ -185,14 +182,16 @@ Drawer::Drawer(Game& g)
185182
x += m_characters[i].width + PIX_OFFSET;
186183
}
187184

188-
glUniform1fv(glGetUniformLocation(m_text_program, "u_char_x_offsets"), 128, (float*)char_x_offset_data);
185+
glUniform1fv(glGetUniformLocation(m_text_program, "u_char_x_offsets"), CHARACTERS, (float*)char_x_offset_data);
186+
}
187+
188+
{
189+
m_text_u_color = glGetUniformLocation(m_text_program, "u_color");
189190
}
190191
}
191192

192193
// rectangle shader
193194
{
194-
rectangle_program = g.l.compile_shader_program("f/shaders/rectangle.vert", "f/shaders/rectangle.frag", "rectangle shader");
195-
196195
float vertices[] = {
197196
-0.5f, -0.5f,
198197
-0.5f, 0.5f,
@@ -219,7 +218,7 @@ Drawer::Drawer(Game& g)
219218

220219
// image shader
221220
{
222-
image_program = g.l.compile_shader_program("f/shaders/image.vert", "f/shaders/image.frag", "image shader");
221+
223222
float vertices[] = { // changed later
224223
// position texture coordinates
225224
-0.5f, -0.5f, 0.f, 0.f,
@@ -248,8 +247,6 @@ Drawer::Drawer(Game& g)
248247

249248
// sky shader
250249
{
251-
sky_program = g.l.compile_shader_program("f/shaders/sky.vert", "f/shaders/sky.frag", "sky shader");
252-
253250
const float y_imgs = 4.f * g.l.HEIGHT;
254251
const float x_imgs = 4.f * g.l.WIDTH;
255252

@@ -284,8 +281,7 @@ Drawer::Drawer(Game& g)
284281
}
285282

286283
// sides shader
287-
{
288-
sides_program = g.l.compile_shader_program("f/shaders/sides.vert", "f/shaders/sides.frag", "sides shader");
284+
{
289285
glGenVertexArrays(1, &sides_VAO);
290286
glBindVertexArray(sides_VAO);
291287

@@ -329,8 +325,7 @@ Drawer::Drawer(Game& g)
329325
}
330326

331327
// cloud program
332-
{
333-
cloud_program = g.l.compile_shader_program("f/shaders/cloud.vert", "f/shaders/cloud.frag", "cloud shader");
328+
{
334329
glGenVertexArrays(1, &cloud_VAO);
335330
glBindVertexArray(cloud_VAO);
336331

@@ -354,7 +349,7 @@ Drawer::Drawer(Game& g)
354349

355350
// coin particle program
356351
{
357-
coin_particle_program = g.l.compile_shader_program("f/shaders/coin_particle.vert", "f/shaders/coin_particle.frag", "coin particle shader");
352+
358353
glGenVertexArrays(1, &coin_particle_VAO);
359354
glBindVertexArray(coin_particle_VAO);
360355

@@ -378,7 +373,7 @@ Drawer::Drawer(Game& g)
378373

379374
// bird program
380375
{
381-
bird_program = g.l.compile_shader_program("f/shaders/bird.vert", "f/shaders/bird.frag", "bird shader");
376+
382377
glGenVertexArrays(1, &bird_VAO);
383378
glBindVertexArray(bird_VAO);
384379

@@ -429,7 +424,7 @@ Drawer::Drawer(Game& g)
429424
}
430425

431426
// mess with a texture2D
432-
{
427+
/* {
433428
unsigned char data[100][100][4];
434429
for (int i = 0; i < 100; ++i) {
435430
for (int j = 0; j < 100; ++j) {
@@ -444,7 +439,7 @@ Drawer::Drawer(Game& g)
444439
glBindTexture(GL_TEXTURE_2D, texs[TEX::side_background]);
445440
glTexSubImage2D(GL_TEXTURE_2D, i, 100, 100, 100, 100, GL_RGBA, GL_UNSIGNED_BYTE, data);
446441
}
447-
}
442+
}*/
448443
}
449444

450445
void Drawer::draw_text(const char* text, Color color, float x, float y, float scale)
@@ -474,6 +469,7 @@ void Drawer::draw_text(const char* text, Color color, float x, float y, float sc
474469
glBufferSubData(GL_ARRAY_BUFFER, 0, nr_of_chars * TEXT_BYTES_PER, data);
475470

476471
glUniform3f(m_text_u_offset_scale, x, y, scale);
472+
glUniform4f(m_text_u_color, color.r, color.b, color.g, color.a);
477473

478474
glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL, nr_of_chars);
479475
}
@@ -667,6 +663,51 @@ void Drawer::before_draw(Game& g)
667663
float data[4] = { g.m_death_y, g.c.y, g.m_timer, g.l.WIDTH };
668664
glBufferSubData(GL_UNIFORM_BUFFER, 0, UBO_GLOBAL_SIZE, &data);
669665
}
666+
667+
// hot reloading of shaders
668+
if constexpr (DEV_TOOLS) {
669+
if (g.l.key_just_down(SDL_SCANCODE_R)) {
670+
load_all_programs(g.l);
671+
}
672+
}
673+
}
674+
675+
void Drawer::draw_fps(float dt)
676+
{
677+
static constexpr int SIZE = 10;
678+
char fps_string[SIZE];
679+
snprintf(fps_string, SIZE, "%f", 1.f/dt);
680+
681+
draw_text(fps_string, Color{ 0,0,0,1 }, -Layer::WIDTH + 0.1f, Layer::HEIGHT - 0.1f, 0.001f);
682+
}
683+
684+
685+
void Drawer::load_all_programs(Layer& l)
686+
{
687+
// the uniforms for the text shader are only set once, and they are removed when reloading shader...
688+
//glDeleteProgram(m_text_program);
689+
//m_text_program = l.compile_shader_program("f/shaders/text.vert", "f/shaders/text.frag", "text shader");
690+
691+
glDeleteProgram(rectangle_program);
692+
rectangle_program = l.compile_shader_program("f/shaders/rectangle.vert", "f/shaders/rectangle.frag", "rectangle shader");
693+
694+
glDeleteProgram(image_program);
695+
image_program = l.compile_shader_program("f/shaders/image.vert", "f/shaders/image.frag", "image shader");
696+
697+
glDeleteProgram(sky_program);
698+
sky_program = l.compile_shader_program("f/shaders/sky.vert", "f/shaders/sky.frag", "sky shader");
699+
700+
glDeleteProgram(sides_program);
701+
sides_program = l.compile_shader_program("f/shaders/sides.vert", "f/shaders/sides.frag", "sides shader");
702+
703+
glDeleteProgram(cloud_program);
704+
cloud_program = l.compile_shader_program("f/shaders/cloud.vert", "f/shaders/cloud.frag", "cloud shader");
705+
706+
glDeleteProgram(coin_particle_program);
707+
coin_particle_program = l.compile_shader_program("f/shaders/coin_particle.vert", "f/shaders/coin_particle.frag", "coin particle shader");
708+
709+
glDeleteProgram(bird_program);
710+
bird_program = l.compile_shader_program("f/shaders/bird.vert", "f/shaders/bird.frag", "bird shader");
670711
}
671712

672713
std::array<int, 2> Drawer::load_texture(const char* path, unsigned int* image, int wrapping_x, int wrapping_y)

FallingGame/Drawer.h

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,15 @@ class Drawer
4141

4242
void draw_bird(Camera& c, TEX::_ bird_tex, float x, float y, float rotation, float width, float height, float time_since_coin);
4343

44+
// updates relevant global shader values
4445
void before_draw(Game& g);
4546

47+
void draw_fps(float dt);
48+
4649
protected:
50+
// loads all programs including their source code, including hot reloads
51+
void load_all_programs(Layer& l);
52+
4753
// wrapping to GL_CLAMP_TO_BORDER will make it transparent after border(disables artifacts)
4854
// returns width and height of image
4955
std::array<int, 2> load_texture(const char* path, unsigned int* image, int wrapping_x, int wrapping_y);
@@ -55,10 +61,12 @@ class Drawer
5561
// data for all the characters; how to draw them
5662
std::array<Character, CHARACTERS> m_characters;
5763
// takes in the character and the x offset
58-
unsigned int m_text_program;
64+
unsigned int m_text_program = 0;
5965
unsigned int m_main_font_tex;
6066
unsigned int m_text_VAO, m_text_VBO;
61-
int m_text_u_offset_scale;
67+
// contains x, y and scale
68+
int m_text_u_offset_scale;
69+
int m_text_u_color;
6270
// *IMPORTANT* this is the max buffer of chars allowed to be rendered IN ONE CALL
6371
static constexpr int TEXT_MAX_CHARS_RENDER = 256;
6472
// char and x offset
@@ -84,35 +92,38 @@ class Drawer
8492

8593
unsigned int standard_rect_EBO; // left bottom, left top, right top, right bottom
8694

87-
unsigned int rectangle_program;
95+
96+
// PROGRAMS: INITIALIZE ALL TO ZERO FOR HOT RELOADING, ALLOWING DELETION AT START
97+
98+
unsigned int rectangle_program = 0;
8899
unsigned int rectangle_VAO, rectangle_VBO;
89100
int m_rectangle_u_color;
90101
int m_rectangle_u_offset; // set to camera offset
91102

92-
unsigned int image_program;
103+
unsigned int image_program = 0;
93104
unsigned int image_VAO, image_VBO;
94105
int m_image_u_offset, m_image_u_rotation;
95106

96-
unsigned int sky_program;
107+
unsigned int sky_program = 0;
97108
unsigned int sky_VAO, sky_VBO;
98109
unsigned int sky_u_offset;
99110
float sky_height_per_sky;
100111

101-
unsigned int sides_program;
112+
unsigned int sides_program = 0;
102113
unsigned int sides_VAO, sides_VBO;
103114
int sides_u_offset;
104115
float sides_height_per_image;
105116

106-
unsigned int cloud_program;
117+
unsigned int cloud_program = 0;
107118
static constexpr int FLOATS_PER_CLOUD_POS = 4;
108119
static constexpr int TEX_AND_Z_FLOATS = 2;
109120
unsigned int cloud_VAO, cloud_VBO_pos, cloud_VBO_tex_z;
110121

111-
unsigned int coin_particle_program;
122+
unsigned int coin_particle_program = 0;
112123
unsigned int coin_particle_VAO, coin_particle_VBO;
113124
constexpr static int COIN_PARTICLE_FLOATS_IN_ARRAY = 5;
114125

115-
unsigned int bird_program;
126+
unsigned int bird_program = 0;
116127
unsigned int bird_VAO;
117128
int m_bird_u_offset, m_bird_u_rotation_width_height, m_bird_u_time_since_coin;
118129

FallingGame/FallingGame.vcxproj.filters

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@
99
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
1010
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
1111
</Filter>
12-
<Filter Include="Resource Files">
13-
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
14-
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
15-
</Filter>
1612
<Filter Include="Shader Files">
1713
<UniqueIdentifier>{501b1730-82d5-4fbb-81e7-032db11d0479}</UniqueIdentifier>
1814
</Filter>
1915
<Filter Include="Misc">
2016
<UniqueIdentifier>{a156821a-d285-4075-ab09-7f804a61edb2}</UniqueIdentifier>
2117
</Filter>
18+
<Filter Include="Resource Files">
19+
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
20+
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
21+
</Filter>
2222
</ItemGroup>
2323
<ItemGroup>
2424
<ClCompile Include="main.cpp">

FallingGame/Game.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ void Game::start()
2727
//death_y -= 1.4f * l.dt * std::max(1.f, 0.05f*std::pow(death_y-p.r.y, 2.f) );
2828

2929
// increase speed of death_y over time
30-
//m_death_y -= 1.01f * l.dt * std::max(1.f, std::log(m_timer/10.f));
30+
m_death_y -= 1.01f * l.dt * std::max(1.f, std::log(m_timer/10.f));
3131
p.logic(*this);
3232

3333
for (auto& e : m_bouncers) {
@@ -119,9 +119,9 @@ void Game::start()
119119
{
120120
d.draw_image(c, TEX::storm, 0.f, m_death_y + l.HEIGHT, l.WIDTH * 2.f, l.HEIGHT * 2.f, 0.f);
121121
}
122-
d.draw_text("This is! A ve@Ry imp^(*%ortant! Text!, So extremely important that it.", Color{ 0,0,0,1 }, -1.5f, 0, 0.001);
123122

124-
//d.draw_image(0, 0, 0, 0);
123+
d.draw_fps(l.dt);
124+
125125
//stuff
126126
l.end_frame();
127127
}

FallingGame/Layer.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ void APIENTRY glDebugOutput(GLenum source,
1313
const void* userParam)
1414
{
1515
// ignore non-significant error/warning codes
16-
if (id == 131169 || id == 131185 || id == 131218 || id == 131204) return;
16+
//if (id == 131169 || id == 131185 || id == 131218 || id == 131204) return;
1717

1818
std::cout << "---------------" << std::endl;
1919
std::cout << "Debug message (" << id << "): " << message << std::endl;
@@ -120,7 +120,7 @@ bool Layer::start_frame()
120120
m_start = SDL_GetPerformanceCounter();
121121

122122
glClearColor(0.0, 1.0, 1.0, 1.0);
123-
glClear(GL_COLOR_BUFFER_BIT/* | GL_DEPTH_BUFFER_BIT */);
123+
//glClear(GL_COLOR_BUFFER_BIT/* | GL_DEPTH_BUFFER_BIT */);
124124

125125
m_keys_just_down = { false }; // reset before getting events
126126
SDL_Event e;
@@ -205,14 +205,14 @@ void Layer::end_frame()
205205
SDL_GL_SwapWindow(m_window);
206206
Uint64 end = SDL_GetPerformanceCounter();
207207

208-
// delay
208+
// delay if framerate going too fast
209209
float milliSecElapsed = ((end - m_start) / (float)SDL_GetPerformanceFrequency()) * 1000.f;
210210

211211
Uint32 delay = static_cast<Uint32>(std::max(0.f, 1000.f / MAX_FPS - milliSecElapsed));
212212
dt = (milliSecElapsed + delay) / 1000.f;
213213
dt = std::min(1.f / MIN_FPS, dt);
214214

215-
SDL_SetWindowTitle(m_window, std::to_string(1000.f / (milliSecElapsed + delay)).c_str());
215+
//SDL_SetWindowTitle(m_window, std::to_string(1000.f / (milliSecElapsed + delay)).c_str());
216216
SDL_Delay(delay);
217217
}
218218

@@ -236,7 +236,6 @@ unsigned int Layer::compile_shader_from_file(int type, const char* path, const c
236236
{
237237
std::ifstream f(path);
238238
if (f) {
239-
//f.getline(shaderSource, 100000, '\0');
240239
std::getline(f, shaderSource, '\0');
241240
}
242241
else {

FallingGame/Layer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ class Layer
2222
float dt = 0.f; // delta time for last frame
2323
constexpr static float WIDTH = 1.6f; // of SCREEN
2424
constexpr static float HEIGHT = 1.0f; // of SCREEN
25+
26+
2527
private:
2628
unsigned int compile_shader_from_file(int type, const char* path, const char* error_msg);
2729

0 commit comments

Comments
 (0)