mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-12 23:31:38 -07:00
opengl render backend
This commit is contained in:
@@ -40,6 +40,7 @@ if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `raddbg` build] &&
|
||||
set auto_compile_flags=
|
||||
if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled]
|
||||
if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled]
|
||||
if "%opengl%"=="1" set auto_compile_flags=%auto_compile_flags% -DR_BACKEND=R_BACKEND_OPENGL && echo [opengl render backend]
|
||||
|
||||
:: --- Compile/Link Line Definitions ------------------------------------------
|
||||
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ load_paths =
|
||||
commands =
|
||||
{
|
||||
//- rjf: [raddbg]
|
||||
.f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
.f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry opengl", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
|
||||
//- rjf: [textperf]
|
||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build no_meta telemetry textperf && raddbg_stable --ipc bring_to_front && raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
|
||||
@@ -386,6 +386,21 @@ derotate_4x4f32(Mat4x4F32 mat)
|
||||
return mat;
|
||||
}
|
||||
|
||||
internal Mat4x4F32
|
||||
transpose_4x4f32(Mat4x4F32 mat)
|
||||
{
|
||||
Mat4x4F32 result =
|
||||
{
|
||||
{
|
||||
mat.v[0][0], mat.v[1][0], mat.v[2][0], mat.v[3][0],
|
||||
mat.v[0][1], mat.v[1][1], mat.v[2][1], mat.v[3][1],
|
||||
mat.v[0][2], mat.v[1][2], mat.v[2][2], mat.v[3][2],
|
||||
mat.v[0][3], mat.v[1][3], mat.v[2][3], mat.v[3][3],
|
||||
}
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Range Ops
|
||||
|
||||
|
||||
@@ -545,6 +545,7 @@ internal Mat4x4F32 mul_4x4f32(Mat4x4F32 a, Mat4x4F32 b);
|
||||
internal Mat4x4F32 scale_4x4f32(Mat4x4F32 m, F32 scale);
|
||||
internal Mat4x4F32 inverse_4x4f32(Mat4x4F32 m);
|
||||
internal Mat4x4F32 derotate_4x4f32(Mat4x4F32 mat);
|
||||
internal Mat4x4F32 transpose_4x4f32(Mat4x4F32 mat);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Range Ops
|
||||
|
||||
@@ -279,8 +279,7 @@ str8_lit_comp(
|
||||
" corner_radii_px.w,\n"
|
||||
" corner_radii_px.z,\n"
|
||||
" };\n"
|
||||
" float2 cornercoords__pct = float2(\n"
|
||||
" (c2v.vertex_id >> 1) ? 1.f : 0.f,\n"
|
||||
" float2 cornercoords__pct = float2((c2v.vertex_id >> 1) ? 1.f : 0.f,\n"
|
||||
" (c2v.vertex_id & 1) ? 0.f : 1.f);\n"
|
||||
" \n"
|
||||
" float2 vertex_position__pct = vertex_positions__scrn[c2v.vertex_id] / viewport_size;\n"
|
||||
|
||||
@@ -669,11 +669,11 @@ r_tex2d_release(R_Handle handle)
|
||||
ProfBeginFunction();
|
||||
OS_MutexScopeW(r_d3d11_state->device_rw_mutex)
|
||||
{
|
||||
R_D3D11_Tex2D *texture = r_d3d11_tex2d_from_handle(handle);
|
||||
if(texture != &r_d3d11_tex2d_nil)
|
||||
{
|
||||
SLLStackPush(r_d3d11_state->first_to_free_tex2d, texture);
|
||||
}
|
||||
R_D3D11_Tex2D *texture = r_d3d11_tex2d_from_handle(handle);
|
||||
if(texture != &r_d3d11_tex2d_nil)
|
||||
{
|
||||
SLLStackPush(r_d3d11_state->first_to_free_tex2d, texture);
|
||||
}
|
||||
}
|
||||
ProfEnd();
|
||||
}
|
||||
@@ -705,19 +705,19 @@ r_fill_tex2d_region(R_Handle handle, Rng2S32 subrect, void *data)
|
||||
ProfBeginFunction();
|
||||
OS_MutexScopeW(r_d3d11_state->device_rw_mutex)
|
||||
{
|
||||
R_D3D11_Tex2D *texture = r_d3d11_tex2d_from_handle(handle);
|
||||
if(texture != &r_d3d11_tex2d_nil)
|
||||
{
|
||||
R_D3D11_Tex2D *texture = r_d3d11_tex2d_from_handle(handle);
|
||||
if(texture != &r_d3d11_tex2d_nil)
|
||||
{
|
||||
Assert(texture->kind == R_ResourceKind_Dynamic && "only dynamic texture can update region");
|
||||
U64 bytes_per_pixel = r_tex2d_format_bytes_per_pixel_table[texture->format];
|
||||
Vec2S32 dim = v2s32(subrect.x1 - subrect.x0, subrect.y1 - subrect.y0);
|
||||
Vec2S32 dim = v2s32(subrect.x1 - subrect.x0, subrect.y1 - subrect.y0);
|
||||
D3D11_BOX dst_box =
|
||||
{
|
||||
(UINT)subrect.x0, (UINT)subrect.y0, 0,
|
||||
(UINT)subrect.x1, (UINT)subrect.y1, 1,
|
||||
};
|
||||
r_d3d11_state->device_ctx->lpVtbl->UpdateSubresource(r_d3d11_state->device_ctx, (ID3D11Resource *)texture->texture, 0, &dst_box, data, dim.x*bytes_per_pixel, 0);
|
||||
}
|
||||
r_d3d11_state->device_ctx->lpVtbl->UpdateSubresource(r_d3d11_state->device_ctx, (ID3D11Resource *)texture->texture, 0, &dst_box, data, dim.x*bytes_per_pixel, 0);
|
||||
}
|
||||
}
|
||||
ProfEnd();
|
||||
}
|
||||
@@ -823,10 +823,10 @@ r_end_frame(void)
|
||||
tex = next)
|
||||
{
|
||||
next = tex->next;
|
||||
tex->view->lpVtbl->Release(tex->view);
|
||||
tex->texture->lpVtbl->Release(tex->texture);
|
||||
tex->view = 0;
|
||||
tex->texture = 0;
|
||||
tex->view->lpVtbl->Release(tex->view);
|
||||
tex->texture->lpVtbl->Release(tex->texture);
|
||||
tex->view = 0;
|
||||
tex->texture = 0;
|
||||
tex->generation += 1;
|
||||
SLLStackPush(r_d3d11_state->first_free_tex2d, tex);
|
||||
}
|
||||
@@ -1119,29 +1119,14 @@ r_window_submit(OS_Handle window, R_Handle window_equip, R_PassList *passes)
|
||||
R_D3D11_Tex2D *texture = r_d3d11_tex2d_from_handle(texture_handle);
|
||||
|
||||
// rjf: get texture sample map matrix, based on format
|
||||
Vec4F32 texture_sample_channel_map[] =
|
||||
{
|
||||
{1, 0, 0, 0},
|
||||
{0, 1, 0, 0},
|
||||
{0, 0, 1, 0},
|
||||
{0, 0, 0, 1},
|
||||
};
|
||||
switch(texture->format)
|
||||
{
|
||||
default: break;
|
||||
case R_Tex2DFormat_R8:
|
||||
{
|
||||
MemoryZeroArray(texture_sample_channel_map);
|
||||
texture_sample_channel_map[0] = v4f32(1, 1, 1, 1);
|
||||
}break;
|
||||
}
|
||||
Mat4x4F32 texture_sample_channel_map = r_sample_channel_map_from_tex2dformat(texture->format);
|
||||
|
||||
// rjf: upload uniforms
|
||||
R_D3D11_Uniforms_Rect uniforms = {0};
|
||||
{
|
||||
uniforms.viewport_size = v2f32(resolution.x, resolution.y);
|
||||
uniforms.opacity = 1-group_params->transparency;
|
||||
MemoryCopyArray(uniforms.texture_sample_channel_map, texture_sample_channel_map);
|
||||
uniforms.texture_sample_channel_map = texture_sample_channel_map;
|
||||
uniforms.texture_t2d_size = v2f32(texture->size.x, texture->size.y);
|
||||
uniforms.xform[0] = v4f32(group_params->xform.v[0][0], group_params->xform.v[1][0], group_params->xform.v[2][0], 0);
|
||||
uniforms.xform[1] = v4f32(group_params->xform.v[0][1], group_params->xform.v[1][1], group_params->xform.v[2][1], 0);
|
||||
|
||||
@@ -29,7 +29,7 @@ struct R_D3D11_Uniforms_Rect
|
||||
Vec2F32 viewport_size;
|
||||
F32 opacity;
|
||||
F32 _padding0_;
|
||||
Vec4F32 texture_sample_channel_map[4];
|
||||
Mat4x4F32 texture_sample_channel_map;
|
||||
Vec2F32 texture_t2d_size;
|
||||
Vec2F32 translate;
|
||||
Vec4F32 xform[3];
|
||||
|
||||
@@ -277,8 +277,7 @@ vs_main(CPU2Vertex c2v)
|
||||
corner_radii_px.w,
|
||||
corner_radii_px.z,
|
||||
};
|
||||
float2 cornercoords__pct = float2(
|
||||
(c2v.vertex_id >> 1) ? 1.f : 0.f,
|
||||
float2 cornercoords__pct = float2((c2v.vertex_id >> 1) ? 1.f : 0.f,
|
||||
(c2v.vertex_id & 1) ? 0.f : 1.f);
|
||||
|
||||
float2 vertex_position__pct = vertex_positions__scrn[c2v.vertex_id] / viewport_size;
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
//- GENERATED CODE
|
||||
|
||||
C_LINKAGE_BEGIN
|
||||
String8 r_ogl_shader_kind_name_table[2] =
|
||||
{
|
||||
str8_lit_comp("rect"),
|
||||
str8_lit_comp("blur"),
|
||||
};
|
||||
|
||||
String8 * r_ogl_shader_kind_vshad_src_table[2] =
|
||||
{
|
||||
&r_ogl_rect_vshad_src,
|
||||
&r_ogl_blur_vshad_src,
|
||||
};
|
||||
|
||||
String8 * r_ogl_shader_kind_pshad_src_table[2] =
|
||||
{
|
||||
&r_ogl_rect_pshad_src,
|
||||
&r_ogl_blur_pshad_src,
|
||||
};
|
||||
|
||||
R_OGL_AttributeArray r_ogl_shader_kind_input_attributes_table[2] =
|
||||
{
|
||||
{ r_ogl_rect_input_attributes, ArrayCount(r_ogl_rect_input_attributes) },
|
||||
{ 0, },
|
||||
};
|
||||
|
||||
R_OGL_AttributeArray r_ogl_shader_kind_output_attributes_table[2] =
|
||||
{
|
||||
{ r_ogl_single_color_output_attributes, ArrayCount(r_ogl_single_color_output_attributes) },
|
||||
{ r_ogl_single_color_output_attributes, ArrayCount(r_ogl_single_color_output_attributes) },
|
||||
};
|
||||
|
||||
C_LINKAGE_END
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
//- GENERATED CODE
|
||||
|
||||
#ifndef RENDER_OPENGL_META_H
|
||||
#define RENDER_OPENGL_META_H
|
||||
|
||||
typedef enum R_OGL_ShaderKind
|
||||
{
|
||||
R_OGL_ShaderKind_Rect,
|
||||
R_OGL_ShaderKind_Blur,
|
||||
R_OGL_ShaderKind_COUNT,
|
||||
} R_OGL_ShaderKind;
|
||||
|
||||
C_LINKAGE_BEGIN
|
||||
extern String8 r_ogl_shader_kind_name_table[2];
|
||||
extern String8 * r_ogl_shader_kind_vshad_src_table[2];
|
||||
extern String8 * r_ogl_shader_kind_pshad_src_table[2];
|
||||
extern R_OGL_AttributeArray r_ogl_shader_kind_input_attributes_table[2];
|
||||
extern R_OGL_AttributeArray r_ogl_shader_kind_output_attributes_table[2];
|
||||
read_only global String8 r_ogl_rect_vshad_src =
|
||||
str8_lit_comp(
|
||||
""
|
||||
"\n"
|
||||
"#version 330 core\n"
|
||||
"\n"
|
||||
"in vec4 c2v_dst_rect;\n"
|
||||
"in vec4 c2v_src_rect;\n"
|
||||
"in vec4 c2v_colors_0;\n"
|
||||
"in vec4 c2v_colors_1;\n"
|
||||
"in vec4 c2v_colors_2;\n"
|
||||
"in vec4 c2v_colors_3;\n"
|
||||
"in vec4 c2v_corner_radii;\n"
|
||||
"in vec4 c2v_style; // x: border_thickness_px, y: softness_px, z: omit_texture, w: unused\n"
|
||||
"\n"
|
||||
"out vec2 v2p_sdf_sample_pos;\n"
|
||||
"out vec2 v2p_texcoord_pct;\n"
|
||||
"out vec2 v2p_rect_half_size_px;\n"
|
||||
"out vec4 v2p_tint;\n"
|
||||
"out float v2p_corner_radius;\n"
|
||||
"out float v2p_border_thickness;\n"
|
||||
"out float v2p_softness;\n"
|
||||
"out float v2p_omit_texture;\n"
|
||||
"\n"
|
||||
"uniform sampler2D u_tex_color;\n"
|
||||
"uniform vec2 u_viewport_size_px;\n"
|
||||
"\n"
|
||||
"void main(void)\n"
|
||||
"{\n"
|
||||
" // rjf: constants\n"
|
||||
" vec2 vertices[] = vec2[](vec2(-1, -1), vec2(-1, +1), vec2(+1, -1), vec2(+1, +1));\n"
|
||||
" \n"
|
||||
" // rjf: find dst position\n"
|
||||
" vec2 dst_half_size = (c2v_dst_rect.zw - c2v_dst_rect.xy) / 2;\n"
|
||||
" vec2 dst_center = (c2v_dst_rect.zw + c2v_dst_rect.xy) / 2;\n"
|
||||
" vec2 dst_position = vertices[gl_VertexID] * dst_half_size + dst_center;\n"
|
||||
" \n"
|
||||
" // rjf: find src position\n"
|
||||
" vec2 src_half_size = (c2v_src_rect.zw - c2v_src_rect.xy) / 2;\n"
|
||||
" vec2 src_center = (c2v_src_rect.zw + c2v_src_rect.xy) / 2;\n"
|
||||
" vec2 src_position = vertices[gl_VertexID] * src_half_size + src_center;\n"
|
||||
" \n"
|
||||
" // rjf: find color\n"
|
||||
" vec4 colors[] = vec4[](c2v_colors_0, c2v_colors_1, c2v_colors_2, c2v_colors_3);\n"
|
||||
" vec4 color = colors[gl_VertexID];\n"
|
||||
" \n"
|
||||
" // rjf: find corner radius\n"
|
||||
" float corner_radii[] = float[](c2v_corner_radii.x, c2v_corner_radii.y, c2v_corner_radii.z, c2v_corner_radii.w);\n"
|
||||
" float corner_radius = corner_radii[gl_VertexID];\n"
|
||||
" \n"
|
||||
" // rjf: fill outputs\n"
|
||||
" vec2 dst_verts_pct = vec2(((gl_VertexID >> 1) != 1) ? 1.f : 0.f,\n"
|
||||
" ((gl_VertexID & 1) != 0) ? 0.f : 1.f);\n"
|
||||
" ivec2 u_tex_color_size_i = textureSize(u_tex_color, 0);\n"
|
||||
" vec2 u_tex_color_size = vec2(float(u_tex_color_size_i.x), float(u_tex_color_size_i.y));\n"
|
||||
" {\n"
|
||||
" gl_Position = vec4(2 * dst_position.x / u_viewport_size_px.x - 1,\n"
|
||||
" 2 * (1 - dst_position.y / u_viewport_size_px.y) - 1,\n"
|
||||
" 0.0, 1.0);\n"
|
||||
" v2p_sdf_sample_pos = (2.f * dst_verts_pct - 1.f) * dst_half_size;\n"
|
||||
" v2p_texcoord_pct = src_position / u_tex_color_size;\n"
|
||||
" v2p_rect_half_size_px = dst_half_size;\n"
|
||||
" v2p_tint = color;\n"
|
||||
" v2p_corner_radius = corner_radius;\n"
|
||||
" v2p_border_thickness = c2v_style.x;\n"
|
||||
" v2p_softness = c2v_style.y;\n"
|
||||
" v2p_omit_texture = c2v_style.z;\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
""
|
||||
);
|
||||
|
||||
read_only global String8 r_ogl_rect_pshad_src =
|
||||
str8_lit_comp(
|
||||
""
|
||||
"\n"
|
||||
"#version 330 core\n"
|
||||
"\n"
|
||||
"in vec2 v2p_sdf_sample_pos;\n"
|
||||
"in vec2 v2p_texcoord_pct;\n"
|
||||
"in vec2 v2p_rect_half_size_px;\n"
|
||||
"in vec4 v2p_tint;\n"
|
||||
"in float v2p_corner_radius;\n"
|
||||
"in float v2p_border_thickness;\n"
|
||||
"in float v2p_softness;\n"
|
||||
"in float v2p_omit_texture;\n"
|
||||
"\n"
|
||||
"out vec4 final_color;\n"
|
||||
"\n"
|
||||
"uniform float u_opacity;\n"
|
||||
"uniform sampler2D u_tex_color;\n"
|
||||
"uniform mat4 u_texture_sample_channel_map;\n"
|
||||
"\n"
|
||||
"float rect_sdf(vec2 sample_pos, vec2 rect_half_size, float r)\n"
|
||||
"{\n"
|
||||
" return length(max(abs(sample_pos) - rect_half_size + r, 0.0)) - r;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"float linear_from_srgb_f32(float x)\n"
|
||||
"{\n"
|
||||
" return x < 0.0404482362771082 ? x / 12.92 : pow((x + 0.055) / 1.055, 2.4);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"vec4 linear_from_srgba(vec4 v)\n"
|
||||
"{\n"
|
||||
" vec4 result = vec4(linear_from_srgb_f32(v.x),\n"
|
||||
" linear_from_srgb_f32(v.y),\n"
|
||||
" linear_from_srgb_f32(v.z),\n"
|
||||
" v.w);\n"
|
||||
" return result;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void main(void)\n"
|
||||
"{\n"
|
||||
" // rjf: sample texture\n"
|
||||
" vec4 albedo_sample = vec4(1, 1, 1, 1);\n"
|
||||
" if(v2p_omit_texture < 1)\n"
|
||||
" {\n"
|
||||
" albedo_sample = u_texture_sample_channel_map * texture(u_tex_color, v2p_texcoord_pct);\n"
|
||||
" albedo_sample = linear_from_srgba(albedo_sample);\n"
|
||||
" }\n"
|
||||
" \n"
|
||||
" // rjf: sample for borders\n"
|
||||
" float border_sdf_t = 1;\n"
|
||||
" if(v2p_border_thickness > 0)\n"
|
||||
" {\n"
|
||||
" float border_sdf_s = rect_sdf(v2p_sdf_sample_pos,\n"
|
||||
" v2p_rect_half_size_px - vec2(v2p_softness*2.f, v2p_softness*2.f) - v2p_border_thickness,\n"
|
||||
" max(v2p_corner_radius-v2p_border_thickness, 0));\n"
|
||||
" border_sdf_t = smoothstep(0, 2*v2p_softness, border_sdf_s);\n"
|
||||
" }\n"
|
||||
" if(border_sdf_t < 0.001f)\n"
|
||||
" {\n"
|
||||
" discard;\n"
|
||||
" }\n"
|
||||
" \n"
|
||||
" // rjf: sample for corners\n"
|
||||
" float corner_sdf_t = 1;\n"
|
||||
" if(v2p_corner_radius > 0 || v2p_softness > 0.75f)\n"
|
||||
" {\n"
|
||||
" float corner_sdf_s = rect_sdf(v2p_sdf_sample_pos,\n"
|
||||
" v2p_rect_half_size_px - vec2(v2p_softness*2.f, v2p_softness*2.f),\n"
|
||||
" v2p_corner_radius);\n"
|
||||
" corner_sdf_t = 1-smoothstep(0, 2*v2p_softness, corner_sdf_s);\n"
|
||||
" }\n"
|
||||
" \n"
|
||||
" // rjf: form+return final color\n"
|
||||
" final_color = albedo_sample;\n"
|
||||
" final_color *= v2p_tint;\n"
|
||||
" final_color.a *= u_opacity;\n"
|
||||
" final_color.a *= corner_sdf_t;\n"
|
||||
" final_color.a *= border_sdf_t;\n"
|
||||
"}\n"
|
||||
""
|
||||
);
|
||||
|
||||
read_only global String8 r_ogl_blur_vshad_src =
|
||||
str8_lit_comp(
|
||||
""
|
||||
"\n"
|
||||
"#version 330 core\n"
|
||||
"\n"
|
||||
"uniform vec4 rect;\n"
|
||||
"uniform vec4 corner_radii_px;\n"
|
||||
"uniform vec2 viewport_size;\n"
|
||||
"uniform uint blur_count;\n"
|
||||
"\n"
|
||||
"out vec2 texcoord;\n"
|
||||
"out vec2 sdf_sample_pos;\n"
|
||||
"out vec2 rect_half_size;\n"
|
||||
"out float corner_radius;\n"
|
||||
"\n"
|
||||
"void main(void)\n"
|
||||
"{\n"
|
||||
" vec2 vertex_positions_scrn[] = vec2[](rect.xw,\n"
|
||||
" rect.xy,\n"
|
||||
" rect.zw,\n"
|
||||
" rect.zy);\n"
|
||||
" float corner_radii_px[] = float[](corner_radii_px.y,\n"
|
||||
" corner_radii_px.x,\n"
|
||||
" corner_radii_px.w,\n"
|
||||
" corner_radii_px.z);\n"
|
||||
" vec2 cornercoords_pct = vec2((gl_VertexID >> 1) != 0 ? 1.f : 0.f,\n"
|
||||
" (gl_VertexID & 1) != 0 ? 0.f : 1.f);\n"
|
||||
" \n"
|
||||
" vec2 vertex_position_pct = vertex_positions_scrn[gl_VertexID] / viewport_size;\n"
|
||||
" vec2 vertex_position_scr = 2.f * vertex_position_pct - 1.f;\n"
|
||||
" \n"
|
||||
" vec2 rect_half_size = vec2((rect.z-rect.x)/2, (rect.w-rect.y)/2);\n"
|
||||
" \n"
|
||||
" gl_Position = vec4(vertex_position_scr.x, -vertex_position_scr.y, 0.f, 1.f);\n"
|
||||
" texcoord = vertex_position_pct;\n"
|
||||
" sdf_sample_pos = (2.f * cornercoords_pct - 1.f) * rect_half_size;\n"
|
||||
" rect_half_size = rect_half_size - 2.f;\n"
|
||||
" corner_radius = corner_radii_px[gl_VertexID];\n"
|
||||
"}\n"
|
||||
""
|
||||
);
|
||||
|
||||
read_only global String8 r_ogl_blur_pshad_src =
|
||||
str8_lit_comp(
|
||||
""
|
||||
"\n"
|
||||
"#version 330 core\n"
|
||||
"\n"
|
||||
"uniform sampler2D tex;\n"
|
||||
"uniform vec4 kernel[32];\n"
|
||||
"uniform int blur_count;\n"
|
||||
"uniform vec2 direction;\n"
|
||||
"\n"
|
||||
"in vec2 texcoord;\n"
|
||||
"in vec2 sdf_sample_pos;\n"
|
||||
"in vec2 rect_half_size;\n"
|
||||
"in float corner_radius;\n"
|
||||
"\n"
|
||||
"out vec4 final_color;\n"
|
||||
"\n"
|
||||
"float rect_sdf(vec2 sample_pos, vec2 rect_half_size, float r)\n"
|
||||
"{\n"
|
||||
" return length(max(abs(sample_pos) - rect_half_size + r, 0.0)) - r;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void main(void)\n"
|
||||
"{\n"
|
||||
" // rjf: blend weighted texture samples into color\n"
|
||||
" vec3 color = kernel[0].x * texture(tex, texcoord).rgb;\n"
|
||||
" \n"
|
||||
" for(int i = 1; i < blur_count; i += 1)\n"
|
||||
" {\n"
|
||||
" float weight = kernel[i].x;\n"
|
||||
" float offset = kernel[i].y;\n"
|
||||
" color += weight * texture(tex, texcoord - offset * direction).rgb;\n"
|
||||
" color += weight * texture(tex, texcoord + offset * direction).rgb;\n"
|
||||
" }\n"
|
||||
" \n"
|
||||
" // rjf: sample for corners\n"
|
||||
" float corner_sdf_s = rect_sdf(sdf_sample_pos, rect_half_size, corner_radius);\n"
|
||||
" float corner_sdf_t = 1-smoothstep(0, 2, corner_sdf_s);\n"
|
||||
" \n"
|
||||
" // rjf: weight output color by sdf\n"
|
||||
" // this is doing alpha testing, leave blurring only where mostly opaque pixels are\n"
|
||||
" if(corner_sdf_t < 0.9f)\n"
|
||||
" {\n"
|
||||
" discard;\n"
|
||||
" }\n"
|
||||
" \n"
|
||||
" final_color = vec4(color, 1.f);\n"
|
||||
"}\n"
|
||||
""
|
||||
);
|
||||
|
||||
|
||||
C_LINKAGE_END
|
||||
|
||||
#endif // RENDER_OPENGL_META_H
|
||||
@@ -0,0 +1,480 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: OS Portion Includes
|
||||
|
||||
#if OS_WINDOWS
|
||||
# include "render/opengl/win32/render_opengl_win32.c"
|
||||
#else
|
||||
# error OS portion of OpenGL rendering backend not defined.
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Attribute Tables
|
||||
|
||||
global read_only R_OGL_Attribute r_ogl_rect_input_attributes[] =
|
||||
{
|
||||
{0, str8_lit_comp("c2v_dst_rect"), GL_FLOAT, 4},
|
||||
{1, str8_lit_comp("c2v_src_rect"), GL_FLOAT, 4},
|
||||
{2, str8_lit_comp("c2v_colors_0"), GL_FLOAT, 4},
|
||||
{3, str8_lit_comp("c2v_colors_1"), GL_FLOAT, 4},
|
||||
{4, str8_lit_comp("c2v_colors_2"), GL_FLOAT, 4},
|
||||
{5, str8_lit_comp("c2v_colors_3"), GL_FLOAT, 4},
|
||||
{6, str8_lit_comp("c2v_corner_radii"), GL_FLOAT, 4},
|
||||
{7, str8_lit_comp("c2v_style"), GL_FLOAT, 4},
|
||||
};
|
||||
|
||||
global read_only R_OGL_Attribute r_ogl_single_color_output_attributes[] =
|
||||
{
|
||||
{0, str8_lit_comp("final_color")},
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generated Code
|
||||
|
||||
#include "render/opengl/generated/render_opengl.meta.c"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal R_Handle
|
||||
r_ogl_handle_from_tex2d(R_OGL_Tex2D *t)
|
||||
{
|
||||
R_Handle h = {(U64)t};
|
||||
return h;
|
||||
}
|
||||
|
||||
internal R_OGL_Tex2D *
|
||||
r_ogl_tex2d_from_handle(R_Handle h)
|
||||
{
|
||||
R_OGL_Tex2D *t = (R_OGL_Tex2D *)h.u64[0];
|
||||
return t;
|
||||
}
|
||||
|
||||
internal R_OGL_FormatInfo
|
||||
r_ogl_format_info_from_tex2dformat(R_Tex2DFormat fmt)
|
||||
{
|
||||
R_OGL_FormatInfo result;
|
||||
result.internal_format = GL_RGBA;
|
||||
result.format = GL_RGBA;
|
||||
result.base_type = GL_UNSIGNED_BYTE;
|
||||
// TODO(rjf)
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
r_ogl_debug_message_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam)
|
||||
{
|
||||
raddbg_log("[OpenGL] %.*s\n", (int)length, message);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Backend Hooks
|
||||
|
||||
//- rjf: top-level layer initialization
|
||||
|
||||
r_hook void
|
||||
r_init(CmdLine *cmdln)
|
||||
{
|
||||
//- rjf: do os-specific portion of work
|
||||
r_ogl_os_init(cmdln);
|
||||
|
||||
//- rjf: top-level initialization
|
||||
Arena *arena = arena_alloc();
|
||||
r_ogl_state = push_array(arena, R_OGL_State, 1);
|
||||
r_ogl_state->arena = arena;
|
||||
|
||||
//- rjf: load gl procedures
|
||||
#define X(name, r, p) name = (name##_FunctionType *)r_ogl_os_load_procedure(#name);
|
||||
R_OGL_ProcedureXList
|
||||
#undef X
|
||||
|
||||
//- rjf: build all shaders
|
||||
for EachEnumVal(R_OGL_ShaderKind, k)
|
||||
{
|
||||
// rjf: compile
|
||||
struct {GLenum type; String8 *src; GLuint out; String8 errors;} stages[] =
|
||||
{
|
||||
{GL_VERTEX_SHADER, r_ogl_shader_kind_vshad_src_table[k]},
|
||||
{GL_FRAGMENT_SHADER, r_ogl_shader_kind_pshad_src_table[k]},
|
||||
};
|
||||
for EachElement(idx, stages)
|
||||
{
|
||||
stages[idx].out = glCreateShader(stages[idx].type);
|
||||
GLint src_size = stages[idx].src->size;
|
||||
glShaderSource(stages[idx].out, 1, &stages[idx].src->str, &src_size);
|
||||
glCompileShader(stages[idx].out);
|
||||
GLint info_log_length = 0;
|
||||
GLint status = 0;
|
||||
glGetShaderiv(stages[idx].out, GL_COMPILE_STATUS, &status);
|
||||
glGetShaderiv(stages[idx].out, GL_INFO_LOG_LENGTH, &info_log_length);
|
||||
if(info_log_length != 0)
|
||||
{
|
||||
stages[idx].errors.str = push_array(r_ogl_state->arena, U8, info_log_length+1);
|
||||
stages[idx].errors.size = info_log_length;
|
||||
glGetShaderInfoLog(stages[idx].out, info_log_length, 0, stages[idx].errors.str);
|
||||
}
|
||||
raddbg_pin(text(stages[idx].errors.str));
|
||||
}
|
||||
|
||||
// rjf: attach compilations to program
|
||||
GLuint program = glCreateProgram();
|
||||
for EachElement(idx, stages)
|
||||
{
|
||||
glAttachShader(program, stages[idx].out);
|
||||
}
|
||||
|
||||
// rjf: bind inputs
|
||||
R_OGL_AttributeArray inputs = r_ogl_shader_kind_input_attributes_table[k];
|
||||
for EachIndex(idx, inputs.count)
|
||||
{
|
||||
glBindAttribLocation(program, inputs.v[idx].index, inputs.v[idx].name.str);
|
||||
}
|
||||
|
||||
// rjf: bind outputs
|
||||
R_OGL_AttributeArray outputs = r_ogl_shader_kind_output_attributes_table[k];
|
||||
for EachIndex(idx, outputs.count)
|
||||
{
|
||||
glBindFragDataLocation(program, outputs.v[idx].index, outputs.v[idx].name.str);
|
||||
}
|
||||
|
||||
// rjf: link / validate / store
|
||||
glLinkProgram(program);
|
||||
glValidateProgram(program);
|
||||
r_ogl_state->shaders[k] = program;
|
||||
}
|
||||
|
||||
//- rjf: set up built-in resources
|
||||
glGenVertexArrays(1, &r_ogl_state->all_purpose_vao);
|
||||
glGenBuffers(1, &r_ogl_state->scratch_buffer_2mb);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, r_ogl_state->scratch_buffer_2mb);
|
||||
glBufferData(GL_ARRAY_BUFFER, MB(2), 0, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glGenTextures(1, &r_ogl_state->white_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, r_ogl_state->white_texture);
|
||||
U32 white_pixel = 0xffffffff;
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &white_pixel);
|
||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
|
||||
//- rjf: set up debug callback
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
glDebugMessageCallback(r_ogl_debug_message_callback, 0);
|
||||
}
|
||||
|
||||
//- rjf: window setup/teardown
|
||||
|
||||
r_hook R_Handle
|
||||
r_window_equip(OS_Handle window)
|
||||
{
|
||||
R_Handle result = r_ogl_os_window_equip(window);
|
||||
return result;
|
||||
}
|
||||
|
||||
r_hook void
|
||||
r_window_unequip(OS_Handle window, R_Handle window_equip)
|
||||
{
|
||||
r_ogl_os_window_unequip(window, window_equip);
|
||||
}
|
||||
|
||||
//- rjf: textures
|
||||
|
||||
r_hook R_Handle
|
||||
r_tex2d_alloc(R_ResourceKind kind, Vec2S32 size, R_Tex2DFormat format, void *data)
|
||||
{
|
||||
//- rjf: allocate texture record
|
||||
R_OGL_Tex2D *tex2d = r_ogl_state->free_tex2d;
|
||||
if(tex2d)
|
||||
{
|
||||
SLLStackPop(r_ogl_state->free_tex2d);
|
||||
}
|
||||
else
|
||||
{
|
||||
tex2d = push_array(r_ogl_state->arena, R_OGL_Tex2D, 1);
|
||||
}
|
||||
|
||||
//- rjf: map kind/format -> gl counterparts
|
||||
R_OGL_FormatInfo gl_fmt_info = r_ogl_format_info_from_tex2dformat(format);
|
||||
|
||||
//- rjf: allocate GL texture
|
||||
{
|
||||
glGenTextures(1, &tex2d->id);
|
||||
glBindTexture(GL_TEXTURE_2D, tex2d->id);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, gl_fmt_info.internal_format, size.x, size.y, 0, gl_fmt_info.format, gl_fmt_info.base_type, data);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
//- rjf: fill
|
||||
tex2d->resource_kind = kind;
|
||||
tex2d->fmt = format;
|
||||
tex2d->size = size;
|
||||
|
||||
//- rjf: bundle & return
|
||||
R_Handle result = r_ogl_handle_from_tex2d(tex2d);
|
||||
return result;
|
||||
}
|
||||
|
||||
r_hook void
|
||||
r_tex2d_release(R_Handle texture)
|
||||
{
|
||||
R_OGL_Tex2D *t = r_ogl_tex2d_from_handle(texture);
|
||||
if(t != 0)
|
||||
{
|
||||
glDeleteTextures(1, &t->id);
|
||||
SLLStackPush(r_ogl_state->free_tex2d, t);
|
||||
}
|
||||
}
|
||||
|
||||
r_hook R_ResourceKind
|
||||
r_kind_from_tex2d(R_Handle texture)
|
||||
{
|
||||
R_ResourceKind result = R_ResourceKind_Static;
|
||||
R_OGL_Tex2D *t = r_ogl_tex2d_from_handle(texture);
|
||||
if(t)
|
||||
{
|
||||
result = t->resource_kind;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
r_hook Vec2S32
|
||||
r_size_from_tex2d(R_Handle texture)
|
||||
{
|
||||
Vec2S32 result = {0, 0};
|
||||
R_OGL_Tex2D *t = r_ogl_tex2d_from_handle(texture);
|
||||
if(t)
|
||||
{
|
||||
result = t->size;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
r_hook R_Tex2DFormat
|
||||
r_format_from_tex2d(R_Handle texture)
|
||||
{
|
||||
R_Tex2DFormat result = R_Tex2DFormat_RGBA8;
|
||||
R_OGL_Tex2D *t = r_ogl_tex2d_from_handle(texture);
|
||||
if(t)
|
||||
{
|
||||
result = t->fmt;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
r_hook void
|
||||
r_fill_tex2d_region(R_Handle texture, Rng2S32 subrect, void *data)
|
||||
{
|
||||
R_OGL_Tex2D *t = r_ogl_tex2d_from_handle(texture);
|
||||
if(t)
|
||||
{
|
||||
R_OGL_FormatInfo fmt_info = r_ogl_format_info_from_tex2dformat(t->fmt);
|
||||
glBindTexture(GL_TEXTURE_2D, t->id);
|
||||
Vec2S32 rect_size = dim_2s32(subrect);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, subrect.x0, subrect.y0, rect_size.x, rect_size.y, fmt_info.format, fmt_info.base_type, data);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: buffers
|
||||
|
||||
r_hook R_Handle
|
||||
r_buffer_alloc(R_ResourceKind kind, U64 size, void *data)
|
||||
{
|
||||
R_Handle result = {0};
|
||||
return result;
|
||||
}
|
||||
|
||||
r_hook void
|
||||
r_buffer_release(R_Handle buffer)
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
|
||||
//- rjf: frame markers
|
||||
|
||||
r_hook void
|
||||
r_begin_frame(void)
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
|
||||
r_hook void
|
||||
r_end_frame(void)
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
|
||||
r_hook void
|
||||
r_window_begin_frame(OS_Handle os, R_Handle r)
|
||||
{
|
||||
r_ogl_os_select_window(os, r);
|
||||
|
||||
//- rjf: unpack window viewport info
|
||||
Rng2F32 client_rect = os_client_rect_from_window(os);
|
||||
Vec2F32 client_rect_dim = dim_2f32(client_rect);
|
||||
|
||||
//- rjf: clear and reset state
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glViewport(0, 0, (S32)client_rect_dim.x, (S32)client_rect_dim.y);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
r_hook void
|
||||
r_window_end_frame(OS_Handle os, R_Handle r)
|
||||
{
|
||||
r_ogl_os_window_swap(os, r);
|
||||
}
|
||||
|
||||
//- rjf: render pass submission
|
||||
|
||||
r_hook void
|
||||
r_window_submit(OS_Handle window, R_Handle window_equip, R_PassList *passes)
|
||||
{
|
||||
Rng2F32 viewport_rect = os_client_rect_from_window(window);
|
||||
Vec2F32 viewport_dim = dim_2f32(viewport_rect);
|
||||
for(R_PassNode *pass_n = passes->first; pass_n != 0; pass_n = pass_n->next)
|
||||
{
|
||||
R_Pass *pass = &pass_n->v;
|
||||
switch(pass->kind)
|
||||
{
|
||||
default:{}break;
|
||||
|
||||
////////////////////////
|
||||
//- rjf: ui rendering pass
|
||||
//
|
||||
case R_PassKind_UI:
|
||||
{
|
||||
//- rjf: unpack params
|
||||
R_PassParams_UI *params = pass->params_ui;
|
||||
R_BatchGroup2DList *rect_batch_groups = ¶ms->rects;
|
||||
|
||||
//- rjf: draw each batch group
|
||||
GLuint shader = r_ogl_state->shaders[R_OGL_ShaderKind_Rect];
|
||||
glBindVertexArrayScope(r_ogl_state->all_purpose_vao) glUseProgramScope(shader)
|
||||
{
|
||||
for(R_BatchGroup2DNode *group_n = rect_batch_groups->first; group_n != 0; group_n = group_n->next)
|
||||
{
|
||||
R_BatchList *batches = &group_n->batches;
|
||||
R_BatchGroup2DParams *group_params = &group_n->params;
|
||||
|
||||
//- rjf: unpack texture
|
||||
R_Tex2DFormat texture_fmt = R_Tex2DFormat_RGBA8;
|
||||
GLuint texture_id = r_ogl_state->white_texture;
|
||||
{
|
||||
R_OGL_Tex2D *tex = r_ogl_tex2d_from_handle(group_params->tex);
|
||||
if(tex != 0)
|
||||
{
|
||||
texture_id = tex->id;
|
||||
texture_fmt = tex->fmt;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: get & fill buffer
|
||||
GLuint buffer = r_ogl_state->scratch_buffer_2mb; // TODO(rjf): r_ogl_instance_buffer_from_size(batches->byte_count);
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||
U64 off = 0;
|
||||
for(R_BatchNode *batch_n = batches->first; batch_n != 0; batch_n = batch_n->next)
|
||||
{
|
||||
glBufferSubData(GL_ARRAY_BUFFER, off, batch_n->v.byte_count, batch_n->v.v);
|
||||
off += batch_n->v.byte_count;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: bind input attributes
|
||||
{
|
||||
R_OGL_AttributeArray inputs = r_ogl_shader_kind_input_attributes_table[R_OGL_ShaderKind_Rect];
|
||||
U64 off = 0;
|
||||
for EachIndex(idx, inputs.count)
|
||||
{
|
||||
glEnableVertexAttribArray(inputs.v[idx].index);
|
||||
glVertexAttribDivisor(inputs.v[idx].index, 1);
|
||||
glVertexAttribPointer(inputs.v[idx].index, inputs.v[idx].count, inputs.v[idx].type, GL_FALSE, sizeof(R_Rect2DInst), (void *)(off));
|
||||
// TODO(rjf): this is not correct if type != GL_FLOAT
|
||||
off += inputs.v[idx].count*sizeof(F32);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: bind texture
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_id);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
switch(group_params->tex_sample_kind)
|
||||
{
|
||||
default:
|
||||
case R_Tex2DSampleKind_Nearest:
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}break;
|
||||
case R_Tex2DSampleKind_Linear:
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
}break;
|
||||
}
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glUniform1i(glGetUniformLocation(shader, "u_tex_color"), 0);
|
||||
}
|
||||
|
||||
//- rjf: upload misc. uniforms
|
||||
{
|
||||
Mat4x4F32 texture_sample_channel_map = r_sample_channel_map_from_tex2dformat(texture_fmt);
|
||||
glUniformMatrix4fv(glGetUniformLocation(shader, "u_texture_sample_channel_map"), 1, 0, &texture_sample_channel_map.v[0][0]);
|
||||
glUniform2f(glGetUniformLocation(shader, "u_viewport_size_px"), viewport_dim.x, viewport_dim.y);
|
||||
glUniform1f(glGetUniformLocation(shader, "u_opacity"), 1.f - group_params->transparency);
|
||||
}
|
||||
|
||||
//- rjf: set up scissor
|
||||
if(group_params->clip.x0 != 0 ||
|
||||
group_params->clip.x1 != 0 ||
|
||||
group_params->clip.y0 != 0 ||
|
||||
group_params->clip.y1 != 0)
|
||||
{
|
||||
Rng2F32 clip = group_params->clip;
|
||||
glScissor(clip.x0, viewport_dim.y - clip.y1, (clip.x1-clip.x0) + 1, (clip.y1-clip.y0)+1);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
//- rjf: draw
|
||||
{
|
||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, batches->byte_count / batches->bytes_per_inst);
|
||||
}
|
||||
|
||||
//- rjf: unset scissor
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
}
|
||||
}break;
|
||||
|
||||
////////////////////////
|
||||
//- rjf: blur rendering pass
|
||||
//
|
||||
case R_PassKind_Blur:
|
||||
{
|
||||
R_PassParams_Blur *params = pass->params_blur;
|
||||
GLuint shader = r_ogl_state->shaders[R_OGL_ShaderKind_Blur];
|
||||
glBindVertexArrayScope(r_ogl_state->all_purpose_vao) glUseProgramScope(shader)
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
}break;
|
||||
|
||||
|
||||
////////////////////////
|
||||
//- rjf: 3d geometry rendering pass
|
||||
//
|
||||
case R_PassKind_Geo3D:
|
||||
{
|
||||
//- rjf: unpack params
|
||||
R_PassParams_Geo3D *params = pass->params_geo3d;
|
||||
R_BatchGroup3DMap *mesh_group_map = ¶ms->mesh_batches;
|
||||
// TODO(rjf)
|
||||
}break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef RENDER_OPENGL_H
|
||||
#define RENDER_OPENGL_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: OS Backend Includes
|
||||
|
||||
#if OS_WINDOWS
|
||||
# include "render/opengl/win32/render_opengl_win32.h"
|
||||
#else
|
||||
# error OS portion of OpenGL rendering backend not defined.
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shader Metadata Types
|
||||
|
||||
typedef struct R_OGL_Attribute R_OGL_Attribute;
|
||||
struct R_OGL_Attribute
|
||||
{
|
||||
U64 index;
|
||||
String8 name;
|
||||
GLenum type;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct R_OGL_AttributeArray R_OGL_AttributeArray;
|
||||
struct R_OGL_AttributeArray
|
||||
{
|
||||
R_OGL_Attribute *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Generated Code
|
||||
|
||||
#include "render/opengl/generated/render_opengl.meta.h"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Defines
|
||||
|
||||
typedef char GLchar;
|
||||
typedef ptrdiff_t GLsizeiptr;
|
||||
typedef ptrdiff_t GLintptr;
|
||||
|
||||
#define GL_FRAMEBUFFER_SRGB 0x8DB9
|
||||
#define GL_TEXTURE_MAX_LEVEL 0x813D
|
||||
|
||||
#define GL_R8 0x8229
|
||||
|
||||
#define GL_ARRAY_BUFFER 0x8892
|
||||
#define GL_STREAM_DRAW 0x88E0
|
||||
#define GL_STREAM_READ 0x88E1
|
||||
#define GL_STREAM_COPY 0x88E2
|
||||
#define GL_STATIC_DRAW 0x88E4
|
||||
#define GL_STATIC_READ 0x88E5
|
||||
#define GL_STATIC_COPY 0x88E6
|
||||
#define GL_DYNAMIC_DRAW 0x88E8
|
||||
#define GL_DYNAMIC_READ 0x88E9
|
||||
#define GL_DYNAMIC_COPY 0x88EA
|
||||
|
||||
#define GL_FRAGMENT_SHADER 0x8B30
|
||||
#define GL_VERTEX_SHADER 0x8B31
|
||||
#define GL_TESS_EVALUATION_SHADER 0x8E87
|
||||
#define GL_TESS_CONTROL_SHADER 0x8E88
|
||||
#define GL_INFO_LOG_LENGTH 0x8B84
|
||||
|
||||
#define GL_TEXTURE_2D_ARRAY 0x8C1A
|
||||
|
||||
#define GL_COMPILE_STATUS 0x8B81
|
||||
|
||||
#define GL_TEXTURE0 0x84C0
|
||||
#define GL_TEXTURE1 0x84C1
|
||||
#define GL_TEXTURE2 0x84C2
|
||||
#define GL_TEXTURE3 0x84C3
|
||||
#define GL_TEXTURE4 0x84C4
|
||||
#define GL_TEXTURE5 0x84C5
|
||||
#define GL_TEXTURE6 0x84C6
|
||||
#define GL_TEXTURE7 0x84C7
|
||||
#define GL_TEXTURE8 0x84C8
|
||||
#define GL_TEXTURE9 0x84C9
|
||||
#define GL_TEXTURE10 0x84CA
|
||||
#define GL_TEXTURE11 0x84CB
|
||||
#define GL_TEXTURE12 0x84CC
|
||||
#define GL_TEXTURE13 0x84CD
|
||||
#define GL_TEXTURE14 0x84CE
|
||||
#define GL_TEXTURE15 0x84CF
|
||||
#define GL_TEXTURE16 0x84D0
|
||||
#define GL_TEXTURE17 0x84D1
|
||||
#define GL_TEXTURE18 0x84D2
|
||||
#define GL_TEXTURE19 0x84D3
|
||||
#define GL_TEXTURE20 0x84D4
|
||||
#define GL_TEXTURE21 0x84D5
|
||||
#define GL_TEXTURE22 0x84D6
|
||||
#define GL_TEXTURE23 0x84D7
|
||||
#define GL_TEXTURE24 0x84D8
|
||||
#define GL_TEXTURE25 0x84D9
|
||||
#define GL_TEXTURE26 0x84DA
|
||||
#define GL_TEXTURE27 0x84DB
|
||||
#define GL_TEXTURE28 0x84DC
|
||||
#define GL_TEXTURE29 0x84DD
|
||||
#define GL_TEXTURE30 0x84DE
|
||||
#define GL_TEXTURE31 0x84DF
|
||||
|
||||
#define GL_DEBUG_OUTPUT 0x92E0
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: OpenGL Procedure List
|
||||
|
||||
#define R_OGL_ProcedureXList \
|
||||
X(glGenBuffers, void, (GLsizei n, GLuint *buffers))\
|
||||
X(glBindBuffer, void, (GLenum target, GLuint buffer))\
|
||||
X(glGenVertexArrays, void, (GLsizei n, GLuint *arrays))\
|
||||
X(glBindVertexArray, void, (GLuint array))\
|
||||
X(glCreateProgram, GLuint, (void))\
|
||||
X(glCreateShader, GLuint, (GLenum type))\
|
||||
X(glShaderSource, void, (GLuint shader, GLsizei count, char **string, GLint *length))\
|
||||
X(glCompileShader, void, (GLuint shader))\
|
||||
X(glGetShaderiv, void, (GLuint shader, GLenum pname, GLint *params))\
|
||||
X(glGetShaderInfoLog, void, (GLuint shader, GLsizei bufSize, GLsizei *length, char *infoLog))\
|
||||
X(glGetProgramiv, void, (GLuint program, GLenum pname, GLint *params))\
|
||||
X(glGetProgramInfoLog, void, (GLuint program, GLsizei bufSize, GLsizei *length, char *infoLog))\
|
||||
X(glAttachShader, void, (GLuint program, GLuint shader))\
|
||||
X(glLinkProgram, void, (GLuint program))\
|
||||
X(glValidateProgram, void, (GLuint program))\
|
||||
X(glDeleteShader, void, (GLuint shader))\
|
||||
X(glUseProgram, void, (GLuint program))\
|
||||
X(glGetUniformLocation, GLint, (GLuint program, char *name))\
|
||||
X(glGetAttribLocation, GLint, (GLuint program, char *name))\
|
||||
X(glEnableVertexAttribArray, void, (GLuint index))\
|
||||
X(glVertexAttribPointer, void, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer))\
|
||||
X(glBufferData, void, (GLenum target, ptrdiff_t size, void *data, GLenum usage))\
|
||||
X(glBufferSubData, void, (GLenum target, ptrdiff_t offset, ptrdiff_t size, const void *data))\
|
||||
X(glBlendFuncSeparate, void, (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha))\
|
||||
X(glUniform1f, void, (GLint location, GLfloat v0))\
|
||||
X(glUniform2f, void, (GLint location, GLfloat v0, GLfloat v1))\
|
||||
X(glUniform3f, void, (GLint location, GLfloat v0, GLfloat v1, GLfloat v2))\
|
||||
X(glUniform4f, void, (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3))\
|
||||
X(glUniformMatrix4fv, void, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value))\
|
||||
X(glUniform1i, void, (GLint location, GLint v0))\
|
||||
X(glTexImage3D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels))\
|
||||
X(glTexSubImage3D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels))\
|
||||
X(glGenerateMipmap, void, (GLenum target))\
|
||||
X(glBindAttribLocation, void, (GLuint programObj, GLuint index, char *name))\
|
||||
X(glBindFragDataLocation, void, (GLuint program, GLuint color, char *name))\
|
||||
X(glActiveTexture, void, (GLenum texture))\
|
||||
X(glVertexAttribDivisor, void, (GLuint index, GLuint divisor))\
|
||||
X(glDrawArraysInstanced, void, (GLenum mode, GLint first, GLsizei count, GLsizei instancecount))\
|
||||
X(glDebugMessageCallback, void, (void (*)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam), void *user_data))\
|
||||
|
||||
#define X(name, r, p) typedef r name##_FunctionType p;
|
||||
R_OGL_ProcedureXList
|
||||
#undef X
|
||||
#define X(name, r, p) global name##_FunctionType *name = 0;
|
||||
R_OGL_ProcedureXList
|
||||
#undef X
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: State Types
|
||||
|
||||
typedef struct R_OGL_FormatInfo R_OGL_FormatInfo;
|
||||
struct R_OGL_FormatInfo
|
||||
{
|
||||
GLint internal_format;
|
||||
GLenum format;
|
||||
GLenum base_type;
|
||||
};
|
||||
|
||||
typedef struct R_OGL_Tex2D R_OGL_Tex2D;
|
||||
struct R_OGL_Tex2D
|
||||
{
|
||||
R_OGL_Tex2D *next;
|
||||
GLuint id;
|
||||
R_ResourceKind resource_kind;
|
||||
R_Tex2DFormat fmt;
|
||||
Vec2S32 size;
|
||||
};
|
||||
|
||||
typedef struct R_OGL_State R_OGL_State;
|
||||
struct R_OGL_State
|
||||
{
|
||||
Arena *arena;
|
||||
R_OGL_Tex2D *free_tex2d;
|
||||
GLuint shaders[R_OGL_ShaderKind_COUNT];
|
||||
GLuint all_purpose_vao;
|
||||
GLuint scratch_buffer_2mb;
|
||||
GLuint white_texture;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global R_OGL_State *r_ogl_state = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal R_Handle r_ogl_handle_from_tex2d(R_OGL_Tex2D *t);
|
||||
internal R_OGL_Tex2D *r_ogl_tex2d_from_handle(R_Handle h);
|
||||
internal R_OGL_FormatInfo r_ogl_format_info_from_tex2dformat(R_Tex2DFormat fmt);
|
||||
internal void r_ogl_debug_message_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam);
|
||||
|
||||
#define glUseProgramScope(...) DeferLoop(glUseProgram(__VA_ARGS__), glUseProgram(0))
|
||||
#define glBindVertexArrayScope(...) DeferLoop(glBindVertexArray(__VA_ARGS__), glBindVertexArray(0))
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: OS-Specific Hooks
|
||||
|
||||
internal VoidProc *r_ogl_os_load_procedure(char *name);
|
||||
internal void r_ogl_os_init(CmdLine *cmdln);
|
||||
internal R_Handle r_ogl_os_window_equip(OS_Handle window);
|
||||
internal void r_ogl_os_window_unequip(OS_Handle os, R_Handle r);
|
||||
internal void r_ogl_os_select_window(OS_Handle os, R_Handle r);
|
||||
internal void r_ogl_os_window_swap(OS_Handle os, R_Handle r);
|
||||
|
||||
#endif // RENDER_OPENGL_H
|
||||
@@ -0,0 +1,292 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shader Table
|
||||
|
||||
@table(name name_lower input_atts output_atts)
|
||||
R_OGL_ShaderTable:
|
||||
{
|
||||
{Rect rect r_ogl_rect_input_attributes r_ogl_single_color_output_attributes}
|
||||
{Blur blur 0 r_ogl_single_color_output_attributes}
|
||||
}
|
||||
|
||||
@enum R_OGL_ShaderKind:
|
||||
{
|
||||
@expand(R_OGL_ShaderTable a) `$(a.name)`,
|
||||
COUNT
|
||||
}
|
||||
|
||||
@data(String8) r_ogl_shader_kind_name_table:
|
||||
{
|
||||
@expand(R_OGL_ShaderTable a) `str8_lit_comp("$(a.name_lower)")`,
|
||||
}
|
||||
|
||||
@data(`String8 *`) r_ogl_shader_kind_vshad_src_table:
|
||||
{
|
||||
@expand(R_OGL_ShaderTable a) `&r_ogl_$(a.name_lower)_vshad_src`,
|
||||
}
|
||||
|
||||
@data(`String8 *`) r_ogl_shader_kind_pshad_src_table:
|
||||
{
|
||||
@expand(R_OGL_ShaderTable a) `&r_ogl_$(a.name_lower)_pshad_src`,
|
||||
}
|
||||
|
||||
@data(R_OGL_AttributeArray) r_ogl_shader_kind_input_attributes_table:
|
||||
{
|
||||
@expand(R_OGL_ShaderTable a) `{ $(a.input_atts), $(a.input_atts != 0 -> "ArrayCount(" .. a.input_atts .. ")") }`,
|
||||
}
|
||||
|
||||
@data(R_OGL_AttributeArray) r_ogl_shader_kind_output_attributes_table:
|
||||
{
|
||||
@expand(R_OGL_ShaderTable a) `{ $(a.output_atts), ArrayCount($(a.output_atts)) }`,
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: UI Rectangle Shaders
|
||||
|
||||
//- rjf: vertex
|
||||
@embed_string r_ogl_rect_vshad_src:
|
||||
```
|
||||
#version 330 core
|
||||
|
||||
in vec4 c2v_dst_rect;
|
||||
in vec4 c2v_src_rect;
|
||||
in vec4 c2v_colors_0;
|
||||
in vec4 c2v_colors_1;
|
||||
in vec4 c2v_colors_2;
|
||||
in vec4 c2v_colors_3;
|
||||
in vec4 c2v_corner_radii;
|
||||
in vec4 c2v_style; // x: border_thickness_px, y: softness_px, z: omit_texture, w: unused
|
||||
|
||||
out vec2 v2p_sdf_sample_pos;
|
||||
out vec2 v2p_texcoord_pct;
|
||||
out vec2 v2p_rect_half_size_px;
|
||||
out vec4 v2p_tint;
|
||||
out float v2p_corner_radius;
|
||||
out float v2p_border_thickness;
|
||||
out float v2p_softness;
|
||||
out float v2p_omit_texture;
|
||||
|
||||
uniform sampler2D u_tex_color;
|
||||
uniform vec2 u_viewport_size_px;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
// rjf: constants
|
||||
vec2 vertices[] = vec2[](vec2(-1, -1), vec2(-1, +1), vec2(+1, -1), vec2(+1, +1));
|
||||
|
||||
// rjf: find dst position
|
||||
vec2 dst_half_size = (c2v_dst_rect.zw - c2v_dst_rect.xy) / 2;
|
||||
vec2 dst_center = (c2v_dst_rect.zw + c2v_dst_rect.xy) / 2;
|
||||
vec2 dst_position = vertices[gl_VertexID] * dst_half_size + dst_center;
|
||||
|
||||
// rjf: find src position
|
||||
vec2 src_half_size = (c2v_src_rect.zw - c2v_src_rect.xy) / 2;
|
||||
vec2 src_center = (c2v_src_rect.zw + c2v_src_rect.xy) / 2;
|
||||
vec2 src_position = vertices[gl_VertexID] * src_half_size + src_center;
|
||||
|
||||
// rjf: find color
|
||||
vec4 colors[] = vec4[](c2v_colors_0, c2v_colors_1, c2v_colors_2, c2v_colors_3);
|
||||
vec4 color = colors[gl_VertexID];
|
||||
|
||||
// rjf: find corner radius
|
||||
float corner_radii[] = float[](c2v_corner_radii.x, c2v_corner_radii.y, c2v_corner_radii.z, c2v_corner_radii.w);
|
||||
float corner_radius = corner_radii[gl_VertexID];
|
||||
|
||||
// rjf: fill outputs
|
||||
vec2 dst_verts_pct = vec2(((gl_VertexID >> 1) != 1) ? 1.f : 0.f,
|
||||
((gl_VertexID & 1) != 0) ? 0.f : 1.f);
|
||||
ivec2 u_tex_color_size_i = textureSize(u_tex_color, 0);
|
||||
vec2 u_tex_color_size = vec2(float(u_tex_color_size_i.x), float(u_tex_color_size_i.y));
|
||||
{
|
||||
gl_Position = vec4(2 * dst_position.x / u_viewport_size_px.x - 1,
|
||||
2 * (1 - dst_position.y / u_viewport_size_px.y) - 1,
|
||||
0.0, 1.0);
|
||||
v2p_sdf_sample_pos = (2.f * dst_verts_pct - 1.f) * dst_half_size;
|
||||
v2p_texcoord_pct = src_position / u_tex_color_size;
|
||||
v2p_rect_half_size_px = dst_half_size;
|
||||
v2p_tint = color;
|
||||
v2p_corner_radius = corner_radius;
|
||||
v2p_border_thickness = c2v_style.x;
|
||||
v2p_softness = c2v_style.y;
|
||||
v2p_omit_texture = c2v_style.z;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
//- rjf: pixel
|
||||
@embed_string r_ogl_rect_pshad_src:
|
||||
```
|
||||
#version 330 core
|
||||
|
||||
in vec2 v2p_sdf_sample_pos;
|
||||
in vec2 v2p_texcoord_pct;
|
||||
in vec2 v2p_rect_half_size_px;
|
||||
in vec4 v2p_tint;
|
||||
in float v2p_corner_radius;
|
||||
in float v2p_border_thickness;
|
||||
in float v2p_softness;
|
||||
in float v2p_omit_texture;
|
||||
|
||||
out vec4 final_color;
|
||||
|
||||
uniform float u_opacity;
|
||||
uniform sampler2D u_tex_color;
|
||||
uniform mat4 u_texture_sample_channel_map;
|
||||
|
||||
float rect_sdf(vec2 sample_pos, vec2 rect_half_size, float r)
|
||||
{
|
||||
return length(max(abs(sample_pos) - rect_half_size + r, 0.0)) - r;
|
||||
}
|
||||
|
||||
float linear_from_srgb_f32(float x)
|
||||
{
|
||||
return x < 0.0404482362771082 ? x / 12.92 : pow((x + 0.055) / 1.055, 2.4);
|
||||
}
|
||||
|
||||
vec4 linear_from_srgba(vec4 v)
|
||||
{
|
||||
vec4 result = vec4(linear_from_srgb_f32(v.x),
|
||||
linear_from_srgb_f32(v.y),
|
||||
linear_from_srgb_f32(v.z),
|
||||
v.w);
|
||||
return result;
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
// rjf: sample texture
|
||||
vec4 albedo_sample = vec4(1, 1, 1, 1);
|
||||
if(v2p_omit_texture < 1)
|
||||
{
|
||||
albedo_sample = u_texture_sample_channel_map * texture(u_tex_color, v2p_texcoord_pct);
|
||||
albedo_sample = linear_from_srgba(albedo_sample);
|
||||
}
|
||||
|
||||
// rjf: sample for borders
|
||||
float border_sdf_t = 1;
|
||||
if(v2p_border_thickness > 0)
|
||||
{
|
||||
float border_sdf_s = rect_sdf(v2p_sdf_sample_pos,
|
||||
v2p_rect_half_size_px - vec2(v2p_softness*2.f, v2p_softness*2.f) - v2p_border_thickness,
|
||||
max(v2p_corner_radius-v2p_border_thickness, 0));
|
||||
border_sdf_t = smoothstep(0, 2*v2p_softness, border_sdf_s);
|
||||
}
|
||||
if(border_sdf_t < 0.001f)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
// rjf: sample for corners
|
||||
float corner_sdf_t = 1;
|
||||
if(v2p_corner_radius > 0 || v2p_softness > 0.75f)
|
||||
{
|
||||
float corner_sdf_s = rect_sdf(v2p_sdf_sample_pos,
|
||||
v2p_rect_half_size_px - vec2(v2p_softness*2.f, v2p_softness*2.f),
|
||||
v2p_corner_radius);
|
||||
corner_sdf_t = 1-smoothstep(0, 2*v2p_softness, corner_sdf_s);
|
||||
}
|
||||
|
||||
// rjf: form+return final color
|
||||
final_color = albedo_sample;
|
||||
final_color *= v2p_tint;
|
||||
final_color.a *= u_opacity;
|
||||
final_color.a *= corner_sdf_t;
|
||||
final_color.a *= border_sdf_t;
|
||||
}
|
||||
```
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Blur Shaders
|
||||
|
||||
//- rjf: vertex
|
||||
@embed_string r_ogl_blur_vshad_src:
|
||||
```
|
||||
#version 330 core
|
||||
|
||||
uniform vec4 rect;
|
||||
uniform vec4 corner_radii_px;
|
||||
uniform vec2 viewport_size;
|
||||
uniform uint blur_count;
|
||||
|
||||
out vec2 texcoord;
|
||||
out vec2 sdf_sample_pos;
|
||||
out vec2 rect_half_size;
|
||||
out float corner_radius;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
vec2 vertex_positions_scrn[] = vec2[](rect.xw,
|
||||
rect.xy,
|
||||
rect.zw,
|
||||
rect.zy);
|
||||
float corner_radii_px[] = float[](corner_radii_px.y,
|
||||
corner_radii_px.x,
|
||||
corner_radii_px.w,
|
||||
corner_radii_px.z);
|
||||
vec2 cornercoords_pct = vec2((gl_VertexID >> 1) != 0 ? 1.f : 0.f,
|
||||
(gl_VertexID & 1) != 0 ? 0.f : 1.f);
|
||||
|
||||
vec2 vertex_position_pct = vertex_positions_scrn[gl_VertexID] / viewport_size;
|
||||
vec2 vertex_position_scr = 2.f * vertex_position_pct - 1.f;
|
||||
|
||||
vec2 rect_half_size = vec2((rect.z-rect.x)/2, (rect.w-rect.y)/2);
|
||||
|
||||
gl_Position = vec4(vertex_position_scr.x, -vertex_position_scr.y, 0.f, 1.f);
|
||||
texcoord = vertex_position_pct;
|
||||
sdf_sample_pos = (2.f * cornercoords_pct - 1.f) * rect_half_size;
|
||||
rect_half_size = rect_half_size - 2.f;
|
||||
corner_radius = corner_radii_px[gl_VertexID];
|
||||
}
|
||||
```
|
||||
|
||||
//- rjf: pixel
|
||||
@embed_string r_ogl_blur_pshad_src:
|
||||
```
|
||||
#version 330 core
|
||||
|
||||
uniform sampler2D tex;
|
||||
uniform vec4 kernel[32];
|
||||
uniform int blur_count;
|
||||
uniform vec2 direction;
|
||||
|
||||
in vec2 texcoord;
|
||||
in vec2 sdf_sample_pos;
|
||||
in vec2 rect_half_size;
|
||||
in float corner_radius;
|
||||
|
||||
out vec4 final_color;
|
||||
|
||||
float rect_sdf(vec2 sample_pos, vec2 rect_half_size, float r)
|
||||
{
|
||||
return length(max(abs(sample_pos) - rect_half_size + r, 0.0)) - r;
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
// rjf: blend weighted texture samples into color
|
||||
vec3 color = kernel[0].x * texture(tex, texcoord).rgb;
|
||||
|
||||
for(int i = 1; i < blur_count; i += 1)
|
||||
{
|
||||
float weight = kernel[i].x;
|
||||
float offset = kernel[i].y;
|
||||
color += weight * texture(tex, texcoord - offset * direction).rgb;
|
||||
color += weight * texture(tex, texcoord + offset * direction).rgb;
|
||||
}
|
||||
|
||||
// rjf: sample for corners
|
||||
float corner_sdf_s = rect_sdf(sdf_sample_pos, rect_half_size, corner_radius);
|
||||
float corner_sdf_t = 1-smoothstep(0, 2, corner_sdf_s);
|
||||
|
||||
// rjf: weight output color by sdf
|
||||
// this is doing alpha testing, leave blurring only where mostly opaque pixels are
|
||||
if(corner_sdf_t < 0.9f)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
final_color = vec4(color, 1.f);
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,184 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal VoidProc *
|
||||
r_ogl_os_load_procedure(char *name)
|
||||
{
|
||||
VoidProc *p = (VoidProc*)wglGetProcAddress(name);
|
||||
if(p == (VoidProc*)1 || p == (VoidProc*)2 || p == (VoidProc*)3 || p == (VoidProc*)-1)
|
||||
{
|
||||
p = 0;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
internal void
|
||||
r_ogl_os_init(CmdLine *cmdline)
|
||||
{
|
||||
//- rjf: create bootstrapping window
|
||||
HWND bootstrap_hwnd = 0;
|
||||
{
|
||||
WNDCLASSEXW wndclass = { sizeof(wndclass) };
|
||||
wndclass.lpfnWndProc = DefWindowProcW;
|
||||
wndclass.hInstance = GetModuleHandle(0);
|
||||
wndclass.lpszClassName = L"bootstrap-window";
|
||||
ATOM wndatom = RegisterClassExW(&wndclass);
|
||||
bootstrap_hwnd = CreateWindowExW(0, L"bootstrap-window", L"", 0,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
0, 0, wndclass.hInstance, 0);
|
||||
}
|
||||
|
||||
//- rjf: grab dc
|
||||
HDC dc = GetDC(bootstrap_hwnd);
|
||||
|
||||
//- rjf: build pixel format descriptor
|
||||
int pf = 0;
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd)};
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cColorBits = 32;
|
||||
pfd.cDepthBits = 24;
|
||||
pfd.cStencilBits = 8;
|
||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||
pf = ChoosePixelFormat(dc, &pfd);
|
||||
BOOL describe = DescribePixelFormat(dc, pf, sizeof(pfd), &pfd);
|
||||
BOOL set_pf = SetPixelFormat(dc, pf, &pfd);
|
||||
}
|
||||
|
||||
//- rjf: make bootstrap ctx + make current
|
||||
HGLRC bootstrap_ctx = wglCreateContext(dc);
|
||||
wglMakeCurrent(dc, bootstrap_ctx);
|
||||
|
||||
//- rjf: load modern extensions
|
||||
wglChoosePixelFormatARB = (FNWGLCHOOSEPIXELFORMATARBPROC*) r_ogl_os_load_procedure("wglChoosePixelFormatARB");
|
||||
wglCreateContextAttribsARB = (FNWGLCREATECONTEXTATTRIBSARBPROC*)r_ogl_os_load_procedure("wglCreateContextAttribsARB");
|
||||
wglSwapIntervalEXT = (FNWGLSWAPINTERVALEXTPROC*) r_ogl_os_load_procedure("wglSwapIntervalEXT");
|
||||
|
||||
//- rjf: set up real pixel format
|
||||
{
|
||||
int pf_attribs_i[] =
|
||||
{
|
||||
WGL_DRAW_TO_WINDOW_ARB, 1,
|
||||
WGL_SUPPORT_OPENGL_ARB, 1,
|
||||
WGL_DOUBLE_BUFFER_ARB, 1,
|
||||
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
|
||||
WGL_COLOR_BITS_ARB, 32,
|
||||
WGL_DEPTH_BITS_ARB, 24,
|
||||
WGL_STENCIL_BITS_ARB, 8,
|
||||
0
|
||||
};
|
||||
UINT num_formats = 0;
|
||||
wglChoosePixelFormatARB(dc, pf_attribs_i, 0, 1, &pf, &num_formats);
|
||||
}
|
||||
|
||||
//- rjf: make real gl ctx
|
||||
HGLRC real_ctx = 0;
|
||||
if(pf)
|
||||
{
|
||||
const int context_attribs[] =
|
||||
{
|
||||
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
|
||||
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
|
||||
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
|
||||
0
|
||||
};
|
||||
real_ctx = wglCreateContextAttribsARB(dc, bootstrap_ctx, context_attribs);
|
||||
r_ogl_w32_hglrc = real_ctx;
|
||||
}
|
||||
|
||||
//- rjf: clean up bootstrap context
|
||||
wglMakeCurrent(dc, 0);
|
||||
wglDeleteContext(bootstrap_ctx);
|
||||
wglMakeCurrent(dc, real_ctx);
|
||||
wglSwapIntervalEXT(1);
|
||||
ReleaseDC(bootstrap_hwnd, dc);
|
||||
DestroyWindow(bootstrap_hwnd);
|
||||
}
|
||||
|
||||
internal R_Handle
|
||||
r_ogl_os_window_equip(OS_Handle window)
|
||||
{
|
||||
//- rjf: unpack window
|
||||
OS_W32_Window *w = os_w32_window_from_handle(window);
|
||||
HWND hwnd = w->hwnd;
|
||||
HDC hdc = GetDC(hwnd);
|
||||
|
||||
//- rjf: select in ctx
|
||||
wglMakeCurrent(hdc, r_ogl_w32_hglrc);
|
||||
|
||||
//- rjf: setup real pixel format
|
||||
int pixel_format = 0;
|
||||
UINT num_formats = 0;
|
||||
int pf_attribs_i[] =
|
||||
{
|
||||
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
|
||||
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
|
||||
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
|
||||
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
|
||||
WGL_COLOR_BITS_ARB, 32,
|
||||
WGL_DEPTH_BITS_ARB, 24,
|
||||
WGL_STENCIL_BITS_ARB, 8,
|
||||
0
|
||||
};
|
||||
wglChoosePixelFormatARB(hdc,
|
||||
pf_attribs_i,
|
||||
0,
|
||||
1,
|
||||
&pixel_format,
|
||||
&num_formats);
|
||||
|
||||
// NOTE(rjf): This doesn't seem to be necessary for SetPixelFormat, we can
|
||||
// just pass 0 for it, and SetPixelFormat needs to be called here, but the
|
||||
// docs don't seem to suggest that 0 is an acceptable value, so I am just
|
||||
// filling this out with the same attribs as that for the wgl function,
|
||||
// and passing it.
|
||||
PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd)};
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cColorBits = 32;
|
||||
pfd.cDepthBits = 24;
|
||||
pfd.cStencilBits = 8;
|
||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||
|
||||
//- rjf: set pixel format
|
||||
SetPixelFormat(hdc, pixel_format, &pfd);
|
||||
|
||||
//- rjf: release hdc
|
||||
ReleaseDC(hwnd, hdc);
|
||||
R_Handle result = {0};
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
r_ogl_os_window_unequip(OS_Handle os, R_Handle r)
|
||||
{
|
||||
}
|
||||
|
||||
internal void
|
||||
r_ogl_os_select_window(OS_Handle os, R_Handle r)
|
||||
{
|
||||
OS_W32_Window *w = os_w32_window_from_handle(os);
|
||||
if(w != 0)
|
||||
{
|
||||
HWND hwnd = w->hwnd;
|
||||
HDC hdc = GetDC(hwnd);
|
||||
wglMakeCurrent(hdc, r_ogl_w32_hglrc);
|
||||
ReleaseDC(hwnd, hdc);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
r_ogl_os_window_swap(OS_Handle os, R_Handle r)
|
||||
{
|
||||
OS_W32_Window *w = os_w32_window_from_handle(os);
|
||||
if(w != 0)
|
||||
{
|
||||
HDC dc = GetDC(w->hwnd);
|
||||
SwapBuffers(dc);
|
||||
ReleaseDC(w->hwnd, dc);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef RENDER_OPENGL_WIN32_H
|
||||
#define RENDER_OPENGL_WIN32_H
|
||||
|
||||
#include <GL/gl.h>
|
||||
#pragma comment(lib, "opengl32")
|
||||
|
||||
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
|
||||
#define WGL_SUPPORT_OPENGL_ARB 0x2010
|
||||
#define WGL_DOUBLE_BUFFER_ARB 0x2011
|
||||
#define WGL_PIXEL_TYPE_ARB 0x2013
|
||||
#define WGL_COLOR_BITS_ARB 0x2014
|
||||
#define WGL_DEPTH_BITS_ARB 0x2022
|
||||
#define WGL_STENCIL_BITS_ARB 0x2023
|
||||
#define WGL_TYPE_RGBA_ARB 0x202B
|
||||
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
|
||||
|
||||
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
||||
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
|
||||
#define WGL_CONTEXT_FLAGS_ARB 0x2094
|
||||
|
||||
typedef BOOL WINAPI FNWGLCHOOSEPIXELFORMATARBPROC(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
|
||||
typedef HGLRC WINAPI FNWGLCREATECONTEXTATTRIBSARBPROC(HDC hDC, HGLRC hShareContext, const int *attribList);
|
||||
typedef BOOL WINAPI FNWGLSWAPINTERVALEXTPROC(int interval);
|
||||
|
||||
FNWGLCHOOSEPIXELFORMATARBPROC *wglChoosePixelFormatARB;
|
||||
FNWGLCREATECONTEXTATTRIBSARBPROC *wglCreateContextAttribsARB;
|
||||
FNWGLSWAPINTERVALEXTPROC *wglSwapIntervalEXT;
|
||||
|
||||
global HGLRC r_ogl_w32_hglrc = 0;
|
||||
|
||||
#endif // RENDER_OPENGL_WIN32_H
|
||||
@@ -6,6 +6,33 @@
|
||||
|
||||
#include "generated/render.meta.c"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal Mat4x4F32
|
||||
r_sample_channel_map_from_tex2dformat(R_Tex2DFormat fmt)
|
||||
{
|
||||
Mat4x4F32 result =
|
||||
{
|
||||
{
|
||||
{1, 0, 0, 0},
|
||||
{0, 1, 0, 0},
|
||||
{0, 0, 1, 0},
|
||||
{0, 0, 0, 1},
|
||||
}
|
||||
};
|
||||
switch(fmt)
|
||||
{
|
||||
default:{}break;
|
||||
case R_Tex2DFormat_R8:
|
||||
{
|
||||
MemoryZeroArray(result.v[0]);
|
||||
result.v[0][0] = result.v[0][1] = result.v[0][2] = result.v[0][3] = 1.f;
|
||||
}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Type Functions
|
||||
|
||||
|
||||
@@ -194,6 +194,11 @@ struct R_PassList
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal Mat4x4F32 r_sample_channel_map_from_tex2dformat(R_Tex2DFormat fmt);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Handle Type Functions
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
# include "stub/render_stub.c"
|
||||
#elif R_BACKEND == R_BACKEND_D3D11
|
||||
# include "d3d11/render_d3d11.c"
|
||||
#elif R_BACKEND == R_BACKEND_OPENGL
|
||||
# include "opengl/render_opengl.c"
|
||||
#else
|
||||
# error Renderer backend not specified.
|
||||
#endif
|
||||
|
||||
@@ -9,12 +9,15 @@
|
||||
|
||||
#define R_BACKEND_STUB 0
|
||||
#define R_BACKEND_D3D11 1
|
||||
#define R_BACKEND_OPENGL 2
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Decide On Backend
|
||||
|
||||
#if !defined(R_BACKEND) && OS_WINDOWS
|
||||
# define R_BACKEND R_BACKEND_D3D11
|
||||
#elif !defined(R_BACKEND) && OS_LINUX
|
||||
# define R_BACKEND R_BACKEND_OPENGL
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
@@ -29,6 +32,8 @@
|
||||
# include "stub/render_stub.h"
|
||||
#elif R_BACKEND == R_BACKEND_D3D11
|
||||
# include "d3d11/render_d3d11.h"
|
||||
#elif R_BACKEND == R_BACKEND_OPENGL
|
||||
# include "opengl/render_opengl.h"
|
||||
#else
|
||||
# error Renderer backend not specified.
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user