-
Notifications
You must be signed in to change notification settings - Fork 80
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
341 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,262 @@ | ||
//------------------------------------------------------------------------------ | ||
// layerrender-sapp.c | ||
// | ||
// Rendering into texture-array layers. | ||
//------------------------------------------------------------------------------ | ||
#include "sokol_app.h" | ||
#include "sokol_gfx.h" | ||
#include "sokol_log.h" | ||
#include "sokol_glue.h" | ||
#define SOKOL_SHAPE_IMPL | ||
#include "sokol_shape.h" | ||
#define HANDMADE_MATH_IMPLEMENTATION | ||
#define HANDMADE_MATH_NO_SSE | ||
#include "HandmadeMath.h" | ||
#include "dbgui/dbgui.h" | ||
#include "layerrender-sapp.glsl.h" | ||
|
||
#define IMG_WIDTH (512) | ||
#define IMG_HEIGHT (512) | ||
#define IMG_NUM_LAYERS (3) | ||
|
||
#define SHAPE_BOX (0) | ||
#define SHAPE_DONUT (1) | ||
#define SHAPE_CYLINDER (2) | ||
#define NUM_SHAPES (3) | ||
|
||
static struct { | ||
float rx, ry; | ||
double time; | ||
sg_buffer vbuf; | ||
sg_buffer ibuf; | ||
sg_image img; | ||
sg_sampler smp; | ||
struct { | ||
sg_pipeline pip; | ||
sg_pass_action pass_action; | ||
sg_bindings bindings; | ||
sshape_element_range_t shapes[NUM_SHAPES]; | ||
sg_pass pass[IMG_NUM_LAYERS]; | ||
} offscreen; | ||
struct { | ||
sg_pipeline pip; | ||
sg_pass_action pass_action; | ||
sg_bindings bindings; | ||
sshape_element_range_t plane; | ||
} display; | ||
} state; | ||
|
||
static vs_params_t compute_offscreen_vsparams(float rx, float ry); | ||
static vs_params_t compute_display_vsparams(void); | ||
|
||
static void init(void) { | ||
sg_setup(&(sg_desc){ | ||
.context = sapp_sgcontext(), | ||
.logger.func = slog_func, | ||
}); | ||
__dbgui_setup(sapp_sample_count()); | ||
|
||
// setup a couple of shape geometries | ||
static sshape_vertex_t vertices[4 * 1024]; | ||
static uint16_t indices[12 * 1024]; | ||
sshape_buffer_t buf = { | ||
.vertices.buffer = SSHAPE_RANGE(vertices), | ||
.indices.buffer = SSHAPE_RANGE(indices), | ||
}; | ||
buf = sshape_build_box(&buf, &(sshape_box_t){ .width = 1.5f, .height = 1.5f, .depth = 1.5f }); | ||
state.offscreen.shapes[SHAPE_BOX] = sshape_element_range(&buf); | ||
buf = sshape_build_torus(&buf, &(sshape_torus_t){ .radius = 1.0f, .ring_radius = 0.3f, .rings = 36, .sides = 18 }); | ||
state.offscreen.shapes[SHAPE_DONUT] = sshape_element_range(&buf); | ||
buf = sshape_build_cylinder(&buf, &(sshape_cylinder_t){ .radius = 1.0f, .height = 1.5f, .slices = 36, .stacks = 1 }); | ||
state.offscreen.shapes[SHAPE_CYLINDER] = sshape_element_range(&buf); | ||
buf = sshape_build_plane(&buf, &(sshape_plane_t){ .width = 2.0f, .depth = 2.0f }); | ||
state.display.plane = sshape_element_range(&buf); | ||
assert(buf.valid); | ||
|
||
// create one vertex- and one index-buffer for all shapes | ||
const sg_buffer_desc vbuf_desc = sshape_vertex_buffer_desc(&buf); | ||
const sg_buffer_desc ibuf_desc = sshape_index_buffer_desc(&buf); | ||
state.vbuf = sg_make_buffer(&vbuf_desc); | ||
state.ibuf = sg_make_buffer(&ibuf_desc); | ||
|
||
// create an array-texture as render target | ||
state.img = sg_make_image(&(sg_image_desc){ | ||
.render_target = true, | ||
.type = SG_IMAGETYPE_ARRAY, | ||
.width = IMG_WIDTH, | ||
.height = IMG_HEIGHT, | ||
.num_slices = IMG_NUM_LAYERS, | ||
.num_mipmaps = 1, | ||
.pixel_format = SG_PIXELFORMAT_RGBA8, | ||
.sample_count = 1, | ||
}); | ||
|
||
// ...and a matching depth buffer image | ||
sg_image depth_img = sg_make_image(&(sg_image_desc){ | ||
.render_target = true, | ||
.width = IMG_WIDTH, | ||
.height = IMG_HEIGHT, | ||
.num_mipmaps = 1, | ||
.pixel_format = SG_PIXELFORMAT_DEPTH, | ||
.sample_count = 1, | ||
}); | ||
|
||
// a sampler for sampling the array texture | ||
state.smp = sg_make_sampler(&(sg_sampler_desc){ | ||
.min_filter = SG_FILTER_LINEAR, | ||
.mag_filter = SG_FILTER_LINEAR, | ||
.wrap_u = SG_WRAP_CLAMP_TO_EDGE, | ||
.wrap_v = SG_WRAP_CLAMP_TO_EDGE, | ||
}); | ||
|
||
// one render pass object per texture array layer | ||
for (int i = 0; i < IMG_NUM_LAYERS; i++) { | ||
state.offscreen.pass[i] = sg_make_pass(&(sg_pass_desc){ | ||
.color_attachments[0] = { .image = state.img, .slice = i }, | ||
.depth_stencil_attachment = { .image = depth_img }, | ||
}); | ||
} | ||
|
||
// a pipeline object for the offscreen pass | ||
state.offscreen.pip = sg_make_pipeline(&(sg_pipeline_desc){ | ||
.layout = { | ||
.buffers[0].stride = sizeof(sshape_vertex_t), | ||
.attrs = { | ||
[ATTR_vs_offscreen_in_pos] = sshape_position_vertex_attr_state(), | ||
[ATTR_vs_offscreen_in_nrm] = sshape_normal_vertex_attr_state(), | ||
}, | ||
}, | ||
.shader = sg_make_shader(offscreen_shader_desc(sg_query_backend())), | ||
.index_type = SG_INDEXTYPE_UINT16, | ||
.cull_mode = SG_CULLMODE_BACK, | ||
.sample_count = 1, | ||
.depth = { | ||
.write_enabled = true, | ||
.compare = SG_COMPAREFUNC_LESS_EQUAL, | ||
.pixel_format = SG_PIXELFORMAT_DEPTH, | ||
}, | ||
.colors[0].pixel_format = SG_PIXELFORMAT_RGBA8, | ||
}); | ||
|
||
// ...and a pipeline object for the display pass | ||
state.display.pip = sg_make_pipeline(&(sg_pipeline_desc){ | ||
.layout = { | ||
.buffers[0].stride = sizeof(sshape_vertex_t), | ||
.attrs = { | ||
[ATTR_vs_display_in_pos] = sshape_position_vertex_attr_state(), | ||
[ATTR_vs_display_in_uv] = sshape_texcoord_vertex_attr_state(), | ||
}, | ||
}, | ||
.shader = sg_make_shader(display_shader_desc(sg_query_backend())), | ||
.index_type = SG_INDEXTYPE_UINT16, | ||
.cull_mode = SG_CULLMODE_BACK, | ||
.sample_count = 1, | ||
.depth = { | ||
.write_enabled = true, | ||
.compare = SG_COMPAREFUNC_LESS_EQUAL, | ||
}, | ||
}); | ||
|
||
// initialize resource bindings | ||
state.offscreen.bindings = (sg_bindings){ | ||
.vertex_buffers[0] = state.vbuf, | ||
.index_buffer = state.ibuf, | ||
}; | ||
state.display.bindings = (sg_bindings){ | ||
.vertex_buffers[0] = state.vbuf, | ||
.index_buffer = state.ibuf, | ||
.fs = { | ||
.images[SLOT_tex] = state.img, | ||
.samplers[SLOT_smp] = state.smp, | ||
}, | ||
}; | ||
|
||
// initialize pass actions | ||
state.offscreen.pass_action = (sg_pass_action){ | ||
.colors[0] = { .load_action = SG_LOADACTION_CLEAR, .clear_value = { 0.5f, 0.5f, 0.5f, 1.0f } }, | ||
}; | ||
state.display.pass_action = (sg_pass_action){ | ||
.colors[0] = { .load_action = SG_LOADACTION_CLEAR, .clear_value = { 0.0f, 0.0f, 0.0f, 1.0f } }, | ||
}; | ||
} | ||
|
||
static void frame(void) { | ||
double dt = sapp_frame_duration(); | ||
state.time += dt; | ||
state.rx += (float)(dt * 20.0f); | ||
state.ry += (float)(dt * 40.0f); | ||
|
||
const vs_params_t display_vsparams = compute_display_vsparams(); | ||
|
||
// render different shapes into each texture array layer | ||
for (int i = 0; i < IMG_NUM_LAYERS; i++) { | ||
sg_begin_pass(state.offscreen.pass[i], &state.offscreen.pass_action); | ||
sg_apply_pipeline(state.offscreen.pip); | ||
sg_apply_bindings(&state.offscreen.bindings); | ||
float rx = state.rx; | ||
float ry = state.ry; | ||
switch (i) { | ||
case 0: break; | ||
case 1: rx = -rx; break; | ||
default: ry = -ry; break; | ||
} | ||
const vs_params_t offscreen_vsparams = compute_offscreen_vsparams(rx, ry); | ||
sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_vs_params, &SG_RANGE(offscreen_vsparams)); | ||
const sshape_element_range_t shape = state.offscreen.shapes[i]; | ||
sg_draw(shape.base_element, shape.num_elements, 1); | ||
sg_end_pass(); | ||
} | ||
|
||
// default pass: render a textured plane which accesses all texture layers in the fragment shader | ||
sg_begin_default_pass(&state.display.pass_action, sapp_width(), sapp_height()); | ||
sg_apply_pipeline(state.display.pip); | ||
sg_apply_bindings(&state.display.bindings); | ||
sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_vs_params, &SG_RANGE(display_vsparams)); | ||
sg_draw(state.display.plane.base_element, state.display.plane.num_elements, 1); | ||
__dbgui_draw(); | ||
sg_end_pass(); | ||
sg_commit(); | ||
} | ||
|
||
static void cleanup(void) { | ||
__dbgui_shutdown(); | ||
sg_shutdown(); | ||
} | ||
|
||
// compute a model-view-projection matrix for offscreen rendering (aspect ratio 1:1) | ||
static vs_params_t compute_offscreen_vsparams(float rx, float ry) { | ||
hmm_mat4 proj = HMM_Perspective(60.0f, 1.0f, 0.01f, 10.0f); | ||
hmm_mat4 view = HMM_LookAt(HMM_Vec3(0.0f, 0.0f, 3.0f), HMM_Vec3(0.0f, 0.0f, 0.0f), HMM_Vec3(0.0f, 1.0f, 0.0f)); | ||
hmm_mat4 view_proj = HMM_MultiplyMat4(proj, view); | ||
hmm_mat4 rxm = HMM_Rotate(rx, HMM_Vec3(1.0f, 0.0f, 0.0f)); | ||
hmm_mat4 rym = HMM_Rotate(ry, HMM_Vec3(0.0f, 0.0f, 1.0f)); | ||
hmm_mat4 model = HMM_MultiplyMat4(rxm, rym); | ||
return (vs_params_t){ .mvp = HMM_MultiplyMat4(view_proj, model) }; | ||
} | ||
|
||
// compute a model-view-projection matrix with display aspect ratio | ||
static vs_params_t compute_display_vsparams(void) { | ||
const float w = sapp_widthf(); | ||
const float h = sapp_heightf(); | ||
hmm_mat4 proj = HMM_Perspective(40.0f, w/h, 0.01f, 10.0f); | ||
hmm_mat4 view = HMM_LookAt(HMM_Vec3(0.0f, 0.0f, 5.0f), HMM_Vec3(0.0f, 0.0f, 0.0f), HMM_Vec3(0.0f, 1.0f, 0.0f)); | ||
hmm_mat4 view_proj = HMM_MultiplyMat4(proj, view); | ||
hmm_mat4 model = HMM_Rotate(90.0f, HMM_Vec3(1.0f, 0.0f, 0.0f)); | ||
return (vs_params_t){ .mvp = HMM_MultiplyMat4(view_proj, model) }; | ||
} | ||
|
||
sapp_desc sokol_main(int argc, char* argv[]) { | ||
(void)argc; (void)argv; | ||
return (sapp_desc) { | ||
.init_cb = init, | ||
.frame_cb = frame, | ||
.cleanup_cb = cleanup, | ||
.event_cb = __dbgui_event, | ||
.width = 800, | ||
.height = 600, | ||
.sample_count = 1, | ||
.window_title = "layerrender-sapp.c", | ||
.icon.sokol_default = true, | ||
.logger.func = slog_func, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
@ctype mat4 hmm_mat4 | ||
|
||
@block vs_uniforms | ||
uniform vs_params { | ||
mat4 mvp; | ||
}; | ||
@end | ||
|
||
@vs vs_offscreen | ||
@include_block vs_uniforms | ||
|
||
in vec4 in_pos; | ||
in vec3 in_nrm; | ||
out vec3 nrm; | ||
|
||
void main() { | ||
gl_Position = mvp * in_pos; | ||
nrm = in_nrm; | ||
} | ||
@end | ||
|
||
@fs fs_offscreen | ||
in vec3 nrm; | ||
out vec4 frag_color; | ||
|
||
void main() { | ||
frag_color = vec4(nrm * 0.5 + 0.5, 1.0); | ||
} | ||
@end | ||
|
||
@program offscreen vs_offscreen fs_offscreen | ||
|
||
@vs vs_display | ||
@include_block vs_uniforms | ||
|
||
in vec4 in_pos; | ||
in vec2 in_uv; | ||
out vec2 uv; | ||
|
||
void main() { | ||
gl_Position = mvp * in_pos; | ||
uv = in_uv; | ||
} | ||
@end | ||
|
||
@fs fs_display | ||
uniform texture2DArray tex; | ||
uniform sampler smp; | ||
|
||
in vec2 uv; | ||
out vec4 frag_color; | ||
|
||
void main() { | ||
vec3 c0 = texture(sampler2DArray(tex, smp), vec3(uv, 0)).xyz; | ||
vec3 c1 = texture(sampler2DArray(tex, smp), vec3(uv, 1)).xyz; | ||
vec3 c2 = texture(sampler2DArray(tex, smp), vec3(uv, 2)).xyz; | ||
frag_color = vec4((c0 + c1 + c2) * 0.34, 1.0); | ||
} | ||
@end | ||
|
||
@program display vs_display fs_display |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.