4coder/code/opengl/4ed_opengl_render.cpp

362 lines
12 KiB
C++
Raw Normal View History

2017-11-10 18:27:39 +00:00
/*
* Mr. 4th Dimention - Allen Webster
*
* 10.11.2017
*
* OpenGL render implementation
*
*/
// TOP
internal void
gl__bind_texture(Render_Target *t, i32 texid){
if (t->bound_texture != texid){
glBindTexture(GL_TEXTURE_2D_ARRAY, texid);
t->bound_texture = texid;
}
}
2019-07-25 07:17:01 +00:00
internal void
gl__bind_any_texture(Render_Target *t){
if (t->bound_texture == 0){
Assert(t->fallback_texture_id != 0);
glBindTexture(GL_TEXTURE_2D_ARRAY, t->fallback_texture_id);
t->bound_texture = t->fallback_texture_id;
}
}
internal u32
gl__get_texture(Vec3_i32 dim, Texture_Kind texture_kind){
2019-07-21 18:31:17 +00:00
u32 tex = 0;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_R8, dim.x, dim.y, dim.z, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0);
return(tex);
}
2019-07-21 18:31:17 +00:00
internal b32
gl__fill_texture(Texture_Kind texture_kind, u32 texture, Vec3_i32 p, Vec3_i32 dim, void *data){
2019-07-21 18:31:17 +00:00
b32 result = false;
if (texture != 0){
glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
2017-11-10 18:27:39 +00:00
}
if (dim.x > 0 && dim.y > 0 && dim.z > 0){
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, p.x, p.y, p.z, dim.x, dim.y, dim.z, GL_RED, GL_UNSIGNED_BYTE, data);
}
return(result);
2017-11-10 18:27:39 +00:00
}
A user reported on the handmade network discord an issue where when you change the font size (e.g. ctrl + scroll up/down) 4coder was crashing. They were using the D3D11 renderer. The crash is caused by dereferencing a invalid pointer to a texture. The D3D11 renderer as a arbitrary limit of 32 textures (there is normally no reason to have more than 2 or 3 textures in 4coder) because it needs to keep track of a few pointer in its state, while OpenGL doesn't (it just uses the id returned by `glGenTexture`). The code that recreate the texture atlas when changing the font size, never frees the previous texture, so both DirectX and OpenGL are leaking texture. So this fix just frees the previous texture after 4coder successfully creates a new one. If for some reason the new texture can't be created, we continue using the last one. This is better than crashing as we can still use 4coder, but since we can't change font size anymore the editor might be stuck with a uncomfortable font size. Unfortunately 4coder doesn't expose a way to delete texture outside the platform layer, and the font size code is not in the platform layer. So I had to expose a `free texture` function, which lead me to understand how 4coder generates API in the `generated` folder. I updated the README to keep that information somewhere since it's not clear from the get go. The basic idea is that there are a few files that you can compile as a small standalone program and run to generate the files. For the graphics api, you need to compile `4ed_graphics_api.cpp`. I took some time to also modify a little the generator so that the generated file contains the name of the file that generated them, and added a bit of indentation to make the file a bit more readable (even if we're not supposed to modify them).
2025-01-06 17:37:44 +00:00
internal void
gl__free_texture(u32 texture){
glDeleteTextures(1, &texture);
}
internal void
2020-02-02 15:50:18 +00:00
gl__error_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char *message, const void *userParam){
2020-03-03 20:25:04 +00:00
switch (id){
case 131218:
{
// NOTE(allen): performance warning, do nothing.
}break;
default:
{
InvalidPath;
}break;
2020-02-20 06:41:11 +00:00
}
2020-03-03 20:25:04 +00:00
}
char *gl__header = R"foo(#version 130
2020-02-20 06:41:11 +00:00
)foo";
2020-03-03 20:25:04 +00:00
char *gl__vertex = R"foo(
2020-02-20 06:41:11 +00:00
uniform vec2 view_t;
uniform mat2x2 view_m;
in vec2 vertex_p;
in vec3 vertex_t;
in uint vertex_c;
in float vertex_ht;
smooth out vec4 fragment_color;
smooth out vec3 uvw;
smooth out vec2 xy;
smooth out vec2 adjusted_half_dim;
smooth out float half_thickness;
void main(void)
{
2020-02-20 06:41:11 +00:00
gl_Position = vec4(view_m*(vertex_p - view_t), 0.0, 1.0);
fragment_color.b = (float((vertex_c )&0xFFu))/255.0;
fragment_color.g = (float((vertex_c>> 8u)&0xFFu))/255.0;
fragment_color.r = (float((vertex_c>>16u)&0xFFu))/255.0;
fragment_color.a = (float((vertex_c>>24u)&0xFFu))/255.0;
uvw = vertex_t;
vec2 center = vertex_t.xy;
vec2 half_dim = abs(vertex_p - center);
adjusted_half_dim = half_dim - vertex_t.zz + vec2(0.5, 0.5);
half_thickness = vertex_ht;
xy = vertex_p;
}
)foo";
2020-03-03 20:25:04 +00:00
char *gl__fragment = R"foo(
2020-02-20 06:41:11 +00:00
smooth in vec4 fragment_color;
smooth in vec3 uvw;
smooth in vec2 xy;
smooth in vec2 adjusted_half_dim;
smooth in float half_thickness;
uniform sampler2DArray sampler;
out vec4 out_color;
A user reported on the handmade network discord an issue where when you change the font size (e.g. ctrl + scroll up/down) 4coder was crashing. They were using the D3D11 renderer. The crash is caused by dereferencing a invalid pointer to a texture. The D3D11 renderer as a arbitrary limit of 32 textures (there is normally no reason to have more than 2 or 3 textures in 4coder) because it needs to keep track of a few pointer in its state, while OpenGL doesn't (it just uses the id returned by `glGenTexture`). The code that recreate the texture atlas when changing the font size, never frees the previous texture, so both DirectX and OpenGL are leaking texture. So this fix just frees the previous texture after 4coder successfully creates a new one. If for some reason the new texture can't be created, we continue using the last one. This is better than crashing as we can still use 4coder, but since we can't change font size anymore the editor might be stuck with a uncomfortable font size. Unfortunately 4coder doesn't expose a way to delete texture outside the platform layer, and the font size code is not in the platform layer. So I had to expose a `free texture` function, which lead me to understand how 4coder generates API in the `generated` folder. I updated the README to keep that information somewhere since it's not clear from the get go. The basic idea is that there are a few files that you can compile as a small standalone program and run to generate the files. For the graphics api, you need to compile `4ed_graphics_api.cpp`. I took some time to also modify a little the generator so that the generated file contains the name of the file that generated them, and added a bit of indentation to make the file a bit more readable (even if we're not supposed to modify them).
2025-01-06 17:37:44 +00:00
2020-02-20 06:41:11 +00:00
float rectangle_sd(vec2 p, vec2 b){
vec2 d = abs(p) - b;
return(length(max(d, vec2(0.0, 0.0))) + min(max(d.x, d.y), 0.0));
}
A user reported on the handmade network discord an issue where when you change the font size (e.g. ctrl + scroll up/down) 4coder was crashing. They were using the D3D11 renderer. The crash is caused by dereferencing a invalid pointer to a texture. The D3D11 renderer as a arbitrary limit of 32 textures (there is normally no reason to have more than 2 or 3 textures in 4coder) because it needs to keep track of a few pointer in its state, while OpenGL doesn't (it just uses the id returned by `glGenTexture`). The code that recreate the texture atlas when changing the font size, never frees the previous texture, so both DirectX and OpenGL are leaking texture. So this fix just frees the previous texture after 4coder successfully creates a new one. If for some reason the new texture can't be created, we continue using the last one. This is better than crashing as we can still use 4coder, but since we can't change font size anymore the editor might be stuck with a uncomfortable font size. Unfortunately 4coder doesn't expose a way to delete texture outside the platform layer, and the font size code is not in the platform layer. So I had to expose a `free texture` function, which lead me to understand how 4coder generates API in the `generated` folder. I updated the README to keep that information somewhere since it's not clear from the get go. The basic idea is that there are a few files that you can compile as a small standalone program and run to generate the files. For the graphics api, you need to compile `4ed_graphics_api.cpp`. I took some time to also modify a little the generator so that the generated file contains the name of the file that generated them, and added a bit of indentation to make the file a bit more readable (even if we're not supposed to modify them).
2025-01-06 17:37:44 +00:00
2020-02-20 06:41:11 +00:00
void main(void)
{
2020-02-20 06:41:11 +00:00
float has_thickness = (step(0.49, half_thickness));
float does_not_have_thickness = 1.0 - has_thickness;
A user reported on the handmade network discord an issue where when you change the font size (e.g. ctrl + scroll up/down) 4coder was crashing. They were using the D3D11 renderer. The crash is caused by dereferencing a invalid pointer to a texture. The D3D11 renderer as a arbitrary limit of 32 textures (there is normally no reason to have more than 2 or 3 textures in 4coder) because it needs to keep track of a few pointer in its state, while OpenGL doesn't (it just uses the id returned by `glGenTexture`). The code that recreate the texture atlas when changing the font size, never frees the previous texture, so both DirectX and OpenGL are leaking texture. So this fix just frees the previous texture after 4coder successfully creates a new one. If for some reason the new texture can't be created, we continue using the last one. This is better than crashing as we can still use 4coder, but since we can't change font size anymore the editor might be stuck with a uncomfortable font size. Unfortunately 4coder doesn't expose a way to delete texture outside the platform layer, and the font size code is not in the platform layer. So I had to expose a `free texture` function, which lead me to understand how 4coder generates API in the `generated` folder. I updated the README to keep that information somewhere since it's not clear from the get go. The basic idea is that there are a few files that you can compile as a small standalone program and run to generate the files. For the graphics api, you need to compile `4ed_graphics_api.cpp`. I took some time to also modify a little the generator so that the generated file contains the name of the file that generated them, and added a bit of indentation to make the file a bit more readable (even if we're not supposed to modify them).
2025-01-06 17:37:44 +00:00
2020-02-20 06:41:11 +00:00
float sample_value = texture(sampler, uvw).r;
sample_value *= does_not_have_thickness;
A user reported on the handmade network discord an issue where when you change the font size (e.g. ctrl + scroll up/down) 4coder was crashing. They were using the D3D11 renderer. The crash is caused by dereferencing a invalid pointer to a texture. The D3D11 renderer as a arbitrary limit of 32 textures (there is normally no reason to have more than 2 or 3 textures in 4coder) because it needs to keep track of a few pointer in its state, while OpenGL doesn't (it just uses the id returned by `glGenTexture`). The code that recreate the texture atlas when changing the font size, never frees the previous texture, so both DirectX and OpenGL are leaking texture. So this fix just frees the previous texture after 4coder successfully creates a new one. If for some reason the new texture can't be created, we continue using the last one. This is better than crashing as we can still use 4coder, but since we can't change font size anymore the editor might be stuck with a uncomfortable font size. Unfortunately 4coder doesn't expose a way to delete texture outside the platform layer, and the font size code is not in the platform layer. So I had to expose a `free texture` function, which lead me to understand how 4coder generates API in the `generated` folder. I updated the README to keep that information somewhere since it's not clear from the get go. The basic idea is that there are a few files that you can compile as a small standalone program and run to generate the files. For the graphics api, you need to compile `4ed_graphics_api.cpp`. I took some time to also modify a little the generator so that the generated file contains the name of the file that generated them, and added a bit of indentation to make the file a bit more readable (even if we're not supposed to modify them).
2025-01-06 17:37:44 +00:00
2020-02-20 06:41:11 +00:00
vec2 center = uvw.xy;
float roundness = uvw.z;
float sd = rectangle_sd(xy - center, adjusted_half_dim);
sd = sd - roundness;
sd = abs(sd + half_thickness) - half_thickness;
float shape_value = 1.0 - smoothstep(-1.0, 0.0, sd);
shape_value *= has_thickness;
A user reported on the handmade network discord an issue where when you change the font size (e.g. ctrl + scroll up/down) 4coder was crashing. They were using the D3D11 renderer. The crash is caused by dereferencing a invalid pointer to a texture. The D3D11 renderer as a arbitrary limit of 32 textures (there is normally no reason to have more than 2 or 3 textures in 4coder) because it needs to keep track of a few pointer in its state, while OpenGL doesn't (it just uses the id returned by `glGenTexture`). The code that recreate the texture atlas when changing the font size, never frees the previous texture, so both DirectX and OpenGL are leaking texture. So this fix just frees the previous texture after 4coder successfully creates a new one. If for some reason the new texture can't be created, we continue using the last one. This is better than crashing as we can still use 4coder, but since we can't change font size anymore the editor might be stuck with a uncomfortable font size. Unfortunately 4coder doesn't expose a way to delete texture outside the platform layer, and the font size code is not in the platform layer. So I had to expose a `free texture` function, which lead me to understand how 4coder generates API in the `generated` folder. I updated the README to keep that information somewhere since it's not clear from the get go. The basic idea is that there are a few files that you can compile as a small standalone program and run to generate the files. For the graphics api, you need to compile `4ed_graphics_api.cpp`. I took some time to also modify a little the generator so that the generated file contains the name of the file that generated them, and added a bit of indentation to make the file a bit more readable (even if we're not supposed to modify them).
2025-01-06 17:37:44 +00:00
2020-02-20 06:41:11 +00:00
out_color = vec4(fragment_color.xyz, fragment_color.a*(sample_value + shape_value));
}
)foo";
2020-03-03 20:25:04 +00:00
#define AttributeList(X) \
2020-03-03 20:25:04 +00:00
X(vertex_p) \
X(vertex_t) \
X(vertex_c) \
X(vertex_ht)
#define UniformList(X) \
2020-03-03 20:25:04 +00:00
X(view_t) \
X(view_m) \
X(sampler)
struct GL_Program{
u32 program;
#define GetAttributeLocation(N) i32 N;
2020-03-03 20:25:04 +00:00
AttributeList(GetAttributeLocation)
#undef GetAttributeLocation
#define GetUniformLocation(N) i32 N;
2020-03-03 20:25:04 +00:00
UniformList(GetUniformLocation)
#undef GetUniformLocation
2020-03-03 20:25:04 +00:00
};
internal GL_Program
gl__make_program(char *header, char *vertex, char *fragment){
if (header == 0){
header = "";
}
2020-03-03 20:25:04 +00:00
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
GLchar *vertex_source_array[] = { header, vertex };
glShaderSource(vertex_shader, ArrayCount(vertex_source_array), vertex_source_array, 0);
glCompileShader(vertex_shader);
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
GLchar *fragment_source_array[] = { header, fragment };
glShaderSource(fragment_shader, ArrayCount(fragment_source_array), fragment_source_array, 0);
glCompileShader(fragment_shader);
GLuint program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
glValidateProgram(program);
GLint success = false;
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success){
GLsizei ignore = 0;
char vertex_errors[KB(4)];
char fragment_errors[KB(4)];
char program_errors[KB(4)];
glGetShaderInfoLog(vertex_shader, sizeof(vertex_errors), &ignore, vertex_errors);
glGetShaderInfoLog(fragment_shader, sizeof(fragment_errors), &ignore, fragment_errors);
glGetProgramInfoLog(program, sizeof(program_errors), &ignore, program_errors);
#if SHIP_MODE
2020-03-03 20:25:04 +00:00
os_popup_error("Error", "Shader compilation failed.");
#endif
2020-03-03 20:25:04 +00:00
InvalidPath;
}
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
GL_Program result = {};
result.program = program;
#define GetAttributeLocation(N) result.N = glGetAttribLocation(program, #N);
2020-03-03 20:25:04 +00:00
AttributeList(GetAttributeLocation)
#undef GetAttributeLocation
#define GetUniformLocation(N) result.N = glGetUniformLocation(program, #N);
2020-03-03 20:25:04 +00:00
UniformList(GetUniformLocation)
#undef GetUniformLocation
2020-03-03 20:25:04 +00:00
return(result);
}
2019-07-25 07:17:01 +00:00
#define GLOffsetStruct(p,m) ((void*)(OffsetOfMemberStruct(p,m)))
#define GLOffset(S,m) ((void*)(OffsetOfMember(S,m)))
2020-03-03 20:25:04 +00:00
internal void
gl_render(Render_Target *t){
Font_Set *font_set = (Font_Set*)t->font_set;
2020-03-03 20:25:04 +00:00
local_persist b32 first_opengl_call = true;
local_persist u32 attribute_buffer = 0;
local_persist GL_Program gpu_program = {};
if (first_opengl_call){
first_opengl_call = false;
2020-02-20 06:41:11 +00:00
#if !SHIP_MODE
2020-03-03 20:25:04 +00:00
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
if (glDebugMessageControl){
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, 0, false);
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0, 0, false);
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, 0, true);
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, 0, true);
}
if (glDebugMessageCallback){
glDebugMessageCallback(gl__error_callback, 0);
2020-02-20 06:41:11 +00:00
}
2020-03-03 20:25:04 +00:00
#endif
////////////////////////////////
GLuint dummy_vao = 0;
glGenVertexArrays(1, &dummy_vao);
glBindVertexArray(dummy_vao);
////////////////////////////////
glGenBuffers(1, &attribute_buffer);
glBindBuffer(GL_ARRAY_BUFFER, attribute_buffer);
2017-11-10 21:13:02 +00:00
2020-03-03 20:25:04 +00:00
////////////////////////////////
2020-03-03 20:25:04 +00:00
glEnable(GL_SCISSOR_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2019-07-25 07:17:01 +00:00
2020-03-03 20:25:04 +00:00
////////////////////////////////
2019-07-25 07:17:01 +00:00
2020-03-03 20:25:04 +00:00
gpu_program = gl__make_program(gl__header, gl__vertex, gl__fragment);
glUseProgram(gpu_program.program);
////////////////////////////////
{
t->fallback_texture_id = gl__get_texture(V3i32(2, 2, 1), TextureKind_Mono);
u8 white_block[] = { 0xFF, 0xFF, 0xFF, 0xFF, };
gl__fill_texture(TextureKind_Mono, 0, V3i32(0, 0, 0), V3i32(2, 2, 1), white_block);
2019-07-25 07:17:01 +00:00
}
2020-03-03 20:25:04 +00:00
}
i32 width = t->width;
i32 height = t->height;
glViewport(0, 0, width, height);
glScissor(0, 0, width, height);
glClearColor(1.f, 0.f, 1.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, 0);
t->bound_texture = 0;
for (Render_Free_Texture *free_texture = t->free_texture_first;
free_texture != 0;
free_texture = free_texture->next){
glDeleteTextures(1, &free_texture->tex_id);
}
t->free_texture_first = 0;
t->free_texture_last = 0;
for (Render_Group *group = t->group_first;
group != 0;
group = group->next){
Rect_i32 box = Ri32(group->clip_box);
Rect_i32 scissor_box = {
box.x0, height - box.y1, box.x1 - box.x0, box.y1 - box.y0,
};
scissor_box.x0 = clamp_bot(0, scissor_box.x0);
scissor_box.y0 = clamp_bot(0, scissor_box.y0);
scissor_box.x1 = clamp_bot(0, scissor_box.x1);
scissor_box.y1 = clamp_bot(0, scissor_box.y1);
glScissor(scissor_box.x0, scissor_box.y0, scissor_box.x1, scissor_box.y1);
2020-01-19 02:44:52 +00:00
2020-03-03 20:25:04 +00:00
i32 vertex_count = group->vertex_list.vertex_count;
if (vertex_count > 0){
Face *face = font_set_face_from_id(font_set, group->face_id);
if (face != 0){
gl__bind_texture(t, face->texture);
}
else{
gl__bind_any_texture(t);
}
glBufferData(GL_ARRAY_BUFFER, vertex_count*sizeof(Render_Vertex), 0, GL_STREAM_DRAW);
i32 cursor = 0;
for (Render_Vertex_Array_Node *node = group->vertex_list.first;
node != 0;
node = node->next){
i32 size = node->vertex_count*sizeof(*node->vertices);
glBufferSubData(GL_ARRAY_BUFFER, cursor, size, node->vertices);
cursor += size;
}
2019-07-25 07:17:01 +00:00
2020-03-03 20:25:04 +00:00
glEnableVertexAttribArray(gpu_program.vertex_p);
glEnableVertexAttribArray(gpu_program.vertex_t);
glEnableVertexAttribArray(gpu_program.vertex_c);
glEnableVertexAttribArray(gpu_program.vertex_ht);
glVertexAttribPointer(gpu_program.vertex_p, 2, GL_FLOAT, true, sizeof(Render_Vertex),
GLOffset(Render_Vertex, xy));
glVertexAttribPointer(gpu_program.vertex_t, 3, GL_FLOAT, true, sizeof(Render_Vertex),
GLOffset(Render_Vertex, uvw));
glVertexAttribIPointer(gpu_program.vertex_c, 1, GL_UNSIGNED_INT, sizeof(Render_Vertex),
GLOffset(Render_Vertex, color));
glVertexAttribPointer(gpu_program.vertex_ht, 1, GL_FLOAT, true, sizeof(Render_Vertex),
GLOffset(Render_Vertex, half_thickness));
glUniform2f(gpu_program.view_t, width/2.f, height/2.f);
f32 m[4] = {
2.f/width, 0.f,
0.f, -2.f/height,
2019-07-25 07:17:01 +00:00
};
2020-03-03 20:25:04 +00:00
glUniformMatrix2fv(gpu_program.view_m, 1, GL_FALSE, m);
glUniform1i(gpu_program.sampler, 0);
2019-07-25 07:17:01 +00:00
2020-03-03 20:25:04 +00:00
glDrawArrays(GL_TRIANGLES, 0, vertex_count);
glDisableVertexAttribArray(gpu_program.vertex_p);
glDisableVertexAttribArray(gpu_program.vertex_t);
glDisableVertexAttribArray(gpu_program.vertex_c);
glDisableVertexAttribArray(gpu_program.vertex_ht);
2019-07-25 07:17:01 +00:00
}
2019-02-25 23:42:13 +00:00
}
2020-03-03 20:25:04 +00:00
glFlush();
}
// BOTTOM