|
|
@ -1369,7 +1369,6 @@ ThreeDeeLevel load_level(MD_Arena *arena, MD_String8 binary_file)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#include "assets.gen.c"
|
|
|
|
#include "assets.gen.c"
|
|
|
|
#include "quad-sapp.glsl.h"
|
|
|
|
|
|
|
|
#include "threedee.glsl.h"
|
|
|
|
#include "threedee.glsl.h"
|
|
|
|
|
|
|
|
|
|
|
|
AABB level_aabb = { .upper_left = { 0.0f, 0.0f }, .lower_right = { TILE_SIZE * LEVEL_TILES, -(TILE_SIZE * LEVEL_TILES) } };
|
|
|
|
AABB level_aabb = { .upper_left = { 0.0f, 0.0f }, .lower_right = { TILE_SIZE * LEVEL_TILES, -(TILE_SIZE * LEVEL_TILES) } };
|
|
|
@ -2618,16 +2617,121 @@ static struct
|
|
|
|
{
|
|
|
|
{
|
|
|
|
sg_pass_action clear_everything_pass_action;
|
|
|
|
sg_pass_action clear_everything_pass_action;
|
|
|
|
sg_pass_action clear_depth_buffer_pass_action;
|
|
|
|
sg_pass_action clear_depth_buffer_pass_action;
|
|
|
|
sg_pipeline pip;
|
|
|
|
sg_pipeline twodee_pip;
|
|
|
|
sg_bindings bind;
|
|
|
|
sg_bindings bind;
|
|
|
|
|
|
|
|
|
|
|
|
sg_pipeline threedee_pip;
|
|
|
|
sg_pipeline threedee_pip;
|
|
|
|
sg_pipeline armature_pip;
|
|
|
|
sg_pipeline armature_pip;
|
|
|
|
sg_bindings threedee_bind;
|
|
|
|
sg_bindings threedee_bind;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sg_image outline_pass_image;
|
|
|
|
|
|
|
|
sg_pass outline_pass;
|
|
|
|
|
|
|
|
sg_pipeline outline_mesh_pip;
|
|
|
|
|
|
|
|
sg_pipeline outline_armature_pip;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sg_pipeline twodee_outline_pip;
|
|
|
|
|
|
|
|
|
|
|
|
Shadow_State shadows;
|
|
|
|
Shadow_State shadows;
|
|
|
|
} state;
|
|
|
|
} state;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// is a function, because also called when window resized to recreate the pass and the image.
|
|
|
|
|
|
|
|
// its target image must be the same size as the viewport. Is the reason. Cowabunga!
|
|
|
|
|
|
|
|
void create_outline_gfx_state()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if(state.outline_pass.id != 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
sg_destroy_pass(state.outline_pass);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if(state.outline_pass_image.id != 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
sg_destroy_image(state.outline_pass_image);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const sg_shader_desc *shd_desc = threedee_mesh_outline_shader_desc(sg_query_backend());
|
|
|
|
|
|
|
|
assert(shd_desc);
|
|
|
|
|
|
|
|
sg_shader shd = sg_make_shader(shd_desc);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
state.outline_mesh_pip = sg_make_pipeline(&(sg_pipeline_desc)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
.shader = shd,
|
|
|
|
|
|
|
|
.depth = {
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
.sample_count = 1,
|
|
|
|
|
|
|
|
.layout = {
|
|
|
|
|
|
|
|
.attrs =
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
[ATTR_threedee_vs_pos_in].format = SG_VERTEXFORMAT_FLOAT3,
|
|
|
|
|
|
|
|
[ATTR_threedee_vs_uv_in].format = SG_VERTEXFORMAT_FLOAT2,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
.colors[0].blend = (sg_blend_state) { // allow transparency
|
|
|
|
|
|
|
|
.enabled = true,
|
|
|
|
|
|
|
|
.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA,
|
|
|
|
|
|
|
|
.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
|
|
|
|
|
|
|
|
.op_rgb = SG_BLENDOP_ADD,
|
|
|
|
|
|
|
|
.src_factor_alpha = SG_BLENDFACTOR_ONE,
|
|
|
|
|
|
|
|
.dst_factor_alpha = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
|
|
|
|
|
|
|
|
.op_alpha = SG_BLENDOP_ADD,
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
.label = "outline-mesh-pipeline",
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
shd_desc = threedee_armature_outline_shader_desc(sg_query_backend());
|
|
|
|
|
|
|
|
assert(shd_desc);
|
|
|
|
|
|
|
|
shd = sg_make_shader(shd_desc);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
state.outline_armature_pip = sg_make_pipeline(&(sg_pipeline_desc)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
.shader = shd,
|
|
|
|
|
|
|
|
.depth = {
|
|
|
|
|
|
|
|
.pixel_format = SG_PIXELFORMAT_NONE,
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
.sample_count = 1,
|
|
|
|
|
|
|
|
.layout = {
|
|
|
|
|
|
|
|
.attrs =
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
[ATTR_threedee_vs_skeleton_pos_in].format = SG_VERTEXFORMAT_FLOAT3,
|
|
|
|
|
|
|
|
[ATTR_threedee_vs_skeleton_uv_in].format = SG_VERTEXFORMAT_FLOAT2,
|
|
|
|
|
|
|
|
[ATTR_threedee_vs_skeleton_indices_in].format = SG_VERTEXFORMAT_USHORT4N,
|
|
|
|
|
|
|
|
[ATTR_threedee_vs_skeleton_weights_in].format = SG_VERTEXFORMAT_FLOAT4,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
.colors[0].blend = (sg_blend_state) { // allow transparency
|
|
|
|
|
|
|
|
.enabled = true,
|
|
|
|
|
|
|
|
.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA,
|
|
|
|
|
|
|
|
.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
|
|
|
|
|
|
|
|
.op_rgb = SG_BLENDOP_ADD,
|
|
|
|
|
|
|
|
.src_factor_alpha = SG_BLENDFACTOR_ONE,
|
|
|
|
|
|
|
|
.dst_factor_alpha = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
|
|
|
|
|
|
|
|
.op_alpha = SG_BLENDOP_ADD,
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
.label = "outline-armature-pipeline",
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sg_image_desc desc = {
|
|
|
|
|
|
|
|
.render_target = true,
|
|
|
|
|
|
|
|
.width = sapp_width(),
|
|
|
|
|
|
|
|
.height = sapp_height(),
|
|
|
|
|
|
|
|
.pixel_format = SG_PIXELFORMAT_RGBA8,
|
|
|
|
|
|
|
|
.min_filter = SG_FILTER_LINEAR,
|
|
|
|
|
|
|
|
.mag_filter = SG_FILTER_LINEAR,
|
|
|
|
|
|
|
|
.wrap_u = SG_WRAP_CLAMP_TO_BORDER,
|
|
|
|
|
|
|
|
.wrap_v = SG_WRAP_CLAMP_TO_BORDER,
|
|
|
|
|
|
|
|
.border_color = SG_BORDERCOLOR_OPAQUE_WHITE,
|
|
|
|
|
|
|
|
.sample_count = 1,
|
|
|
|
|
|
|
|
.label = "outline-pass-render-target",
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
state.outline_pass_image = sg_make_image(&desc);
|
|
|
|
|
|
|
|
state.outline_pass = sg_make_pass(&(sg_pass_desc){
|
|
|
|
|
|
|
|
.color_attachments[0].image = state.outline_pass_image,
|
|
|
|
|
|
|
|
.depth_stencil_attachment = {
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
.label = "outline-pass",
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int num_draw_calls = 0;
|
|
|
|
int num_draw_calls = 0;
|
|
|
|
int num_vertices = 0;
|
|
|
|
int num_vertices = 0;
|
|
|
|
|
|
|
|
|
|
|
@ -3094,15 +3198,15 @@ void init(void)
|
|
|
|
.label = "quad-vertices"
|
|
|
|
.label = "quad-vertices"
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
create_outline_gfx_state();
|
|
|
|
state.shadows = init_shadow_state();
|
|
|
|
state.shadows = init_shadow_state();
|
|
|
|
|
|
|
|
|
|
|
|
const sg_shader_desc *desc = quad_program_shader_desc(sg_query_backend());
|
|
|
|
const sg_shader_desc *desc = threedee_twodee_shader_desc(sg_query_backend());
|
|
|
|
assert(desc);
|
|
|
|
assert(desc);
|
|
|
|
sg_shader shd = sg_make_shader(desc);
|
|
|
|
sg_shader shd = sg_make_shader(desc);
|
|
|
|
|
|
|
|
|
|
|
|
Color clearcol = colhex(0x98734c);
|
|
|
|
Color clearcol = colhex(0x98734c);
|
|
|
|
state.pip = sg_make_pipeline(&(sg_pipeline_desc)
|
|
|
|
state.twodee_pip = sg_make_pipeline(&(sg_pipeline_desc)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
.shader = shd,
|
|
|
|
.shader = shd,
|
|
|
|
.depth = {
|
|
|
|
.depth = {
|
|
|
@ -3112,8 +3216,34 @@ void init(void)
|
|
|
|
.layout = {
|
|
|
|
.layout = {
|
|
|
|
.attrs =
|
|
|
|
.attrs =
|
|
|
|
{
|
|
|
|
{
|
|
|
|
[ATTR_quad_vs_position].format = SG_VERTEXFORMAT_FLOAT3,
|
|
|
|
[ATTR_threedee_vs_twodee_position].format = SG_VERTEXFORMAT_FLOAT3,
|
|
|
|
[ATTR_quad_vs_texcoord0].format = SG_VERTEXFORMAT_FLOAT2,
|
|
|
|
[ATTR_threedee_vs_twodee_texcoord0].format = SG_VERTEXFORMAT_FLOAT2,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
.colors[0].blend = (sg_blend_state) { // allow transparency
|
|
|
|
|
|
|
|
.enabled = true,
|
|
|
|
|
|
|
|
.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA,
|
|
|
|
|
|
|
|
.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
|
|
|
|
|
|
|
|
.op_rgb = SG_BLENDOP_ADD,
|
|
|
|
|
|
|
|
.src_factor_alpha = SG_BLENDFACTOR_ONE,
|
|
|
|
|
|
|
|
.dst_factor_alpha = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
|
|
|
|
|
|
|
|
.op_alpha = SG_BLENDOP_ADD,
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
.label = "quad-pipeline",
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
state.twodee_outline_pip = sg_make_pipeline(&(sg_pipeline_desc)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
.shader = sg_make_shader(threedee_twodee_outline_shader_desc(sg_query_backend())),
|
|
|
|
|
|
|
|
.depth = {
|
|
|
|
|
|
|
|
.compare = SG_COMPAREFUNC_LESS_EQUAL,
|
|
|
|
|
|
|
|
.write_enabled = true
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
.layout = {
|
|
|
|
|
|
|
|
.attrs =
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
[ATTR_threedee_vs_twodee_position].format = SG_VERTEXFORMAT_FLOAT3,
|
|
|
|
|
|
|
|
[ATTR_threedee_vs_twodee_texcoord0].format = SG_VERTEXFORMAT_FLOAT2,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.colors[0].blend = (sg_blend_state) { // allow transparency
|
|
|
|
.colors[0].blend = (sg_blend_state) { // allow transparency
|
|
|
@ -3128,6 +3258,7 @@ void init(void)
|
|
|
|
.label = "quad-pipeline",
|
|
|
|
.label = "quad-pipeline",
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
desc = threedee_mesh_shader_desc(sg_query_backend());
|
|
|
|
desc = threedee_mesh_shader_desc(sg_query_backend());
|
|
|
|
assert(desc);
|
|
|
|
assert(desc);
|
|
|
|
shd = sg_make_shader(desc);
|
|
|
|
shd = sg_make_shader(desc);
|
|
|
@ -3463,14 +3594,28 @@ float cur_batch_data[1024*10] = { 0 };
|
|
|
|
int cur_batch_data_index = 0;
|
|
|
|
int cur_batch_data_index = 0;
|
|
|
|
// @TODO check last tint as well, do this when factor into drawing parameters
|
|
|
|
// @TODO check last tint as well, do this when factor into drawing parameters
|
|
|
|
sg_image cur_batch_image = { 0 };
|
|
|
|
sg_image cur_batch_image = { 0 };
|
|
|
|
quad_fs_params_t cur_batch_params = { 0 };
|
|
|
|
threedee_twodee_fs_params_t cur_batch_params = { 0 };
|
|
|
|
|
|
|
|
sg_pipeline cur_batch_pipeline = { 0 };
|
|
|
|
void flush_quad_batch()
|
|
|
|
void flush_quad_batch()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (cur_batch_image.id == 0 || cur_batch_data_index == 0) return; // flush called when image changes, image starts out null!
|
|
|
|
if (cur_batch_image.id == 0 || cur_batch_data_index == 0) return; // flush called when image changes, image starts out null!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(cur_batch_pipeline.id != 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
sg_apply_pipeline(cur_batch_pipeline);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
sg_apply_pipeline(state.twodee_pip);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
state.bind.vertex_buffer_offsets[0] = sg_append_buffer(state.bind.vertex_buffers[0], &(sg_range) { cur_batch_data, cur_batch_data_index*sizeof(*cur_batch_data) });
|
|
|
|
state.bind.vertex_buffer_offsets[0] = sg_append_buffer(state.bind.vertex_buffers[0], &(sg_range) { cur_batch_data, cur_batch_data_index*sizeof(*cur_batch_data) });
|
|
|
|
state.bind.fs_images[SLOT_quad_tex] = cur_batch_image;
|
|
|
|
state.bind.fs_images[SLOT_threedee_twodee_tex] = cur_batch_image;
|
|
|
|
sg_apply_bindings(&state.bind);
|
|
|
|
sg_apply_bindings(&state.bind);
|
|
|
|
sg_apply_uniforms(SG_SHADERSTAGE_FS, SLOT_quad_fs_params, &SG_RANGE(cur_batch_params));
|
|
|
|
cur_batch_params.tex_size = img_size(cur_batch_image);
|
|
|
|
|
|
|
|
sg_apply_uniforms(SG_SHADERSTAGE_FS, SLOT_threedee_twodee_fs_params, &SG_RANGE(cur_batch_params));
|
|
|
|
|
|
|
|
cur_batch_params.tex_size = V2(0,0); // unsure if setting the tex_size to something nonzero fucks up the batching so I'm just resetting it back here
|
|
|
|
assert(cur_batch_data_index % FLOATS_PER_VERTEX == 0);
|
|
|
|
assert(cur_batch_data_index % FLOATS_PER_VERTEX == 0);
|
|
|
|
sg_draw(0, cur_batch_data_index / FLOATS_PER_VERTEX, 1);
|
|
|
|
sg_draw(0, cur_batch_data_index / FLOATS_PER_VERTEX, 1);
|
|
|
|
num_draw_calls += 1;
|
|
|
|
num_draw_calls += 1;
|
|
|
@ -3547,6 +3692,8 @@ typedef struct DrawParams
|
|
|
|
bool do_clipping;
|
|
|
|
bool do_clipping;
|
|
|
|
Layer layer;
|
|
|
|
Layer layer;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sg_pipeline custom_pipeline;
|
|
|
|
|
|
|
|
|
|
|
|
// for debugging purposes
|
|
|
|
// for debugging purposes
|
|
|
|
int line_number;
|
|
|
|
int line_number;
|
|
|
|
} DrawParams;
|
|
|
|
} DrawParams;
|
|
|
@ -3891,6 +4038,7 @@ typedef struct
|
|
|
|
Mesh *mesh;
|
|
|
|
Mesh *mesh;
|
|
|
|
Armature *armature;
|
|
|
|
Armature *armature;
|
|
|
|
Transform t;
|
|
|
|
Transform t;
|
|
|
|
|
|
|
|
bool outline;
|
|
|
|
} DrawnThing;
|
|
|
|
} DrawnThing;
|
|
|
|
|
|
|
|
|
|
|
|
int drawn_this_frame_length = 0;
|
|
|
|
int drawn_this_frame_length = 0;
|
|
|
@ -3911,6 +4059,7 @@ void draw_thing(DrawnThing params)
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct TextParams
|
|
|
|
typedef struct TextParams
|
|
|
|
{
|
|
|
|
{
|
|
|
|
bool dry_run;
|
|
|
|
bool dry_run;
|
|
|
@ -4820,7 +4969,6 @@ Shadow_State init_shadow_state() {
|
|
|
|
return shadows;
|
|
|
|
return shadows;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
typedef struct {
|
|
|
|
float l;
|
|
|
|
float l;
|
|
|
|
float r;
|
|
|
|
float r;
|
|
|
@ -4939,211 +5087,101 @@ Shadow_Volume_Params calculate_shadow_volume_params(Vec3 light_dir)
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void actually_draw_thing(DrawnThing *it, Mat4 light_space_matrix, bool for_outline)
|
|
|
|
void frame(void)
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
static float speed_factor = 1.0f;
|
|
|
|
if(it->mesh)
|
|
|
|
// elapsed_time
|
|
|
|
|
|
|
|
double unwarped_dt_double = 0.0;
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
unwarped_dt_double = stm_sec(stm_diff(stm_now(), last_frame_time));
|
|
|
|
|
|
|
|
unwarped_dt_double = fmin(unwarped_dt_double, MINIMUM_TIMESTEP * 5.0); // clamp dt at maximum 5 frames, avoid super huge dt
|
|
|
|
|
|
|
|
elapsed_time += unwarped_dt_double*speed_factor;
|
|
|
|
|
|
|
|
unwarped_elapsed_time += unwarped_dt_double;
|
|
|
|
|
|
|
|
last_frame_time = stm_now();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
double dt_double = unwarped_dt_double*speed_factor;
|
|
|
|
|
|
|
|
float unwarped_dt = (float)unwarped_dt_double;
|
|
|
|
|
|
|
|
float dt = (float)dt_double;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
printf("Frametime: %.1f ms\n", dt*1000.0);
|
|
|
|
if(for_outline)
|
|
|
|
sg_begin_default_pass(&state.pass_action, sapp_width(), sapp_height());
|
|
|
|
sg_apply_pipeline(state.outline_mesh_pip);
|
|
|
|
sg_apply_pipeline(state.pip);
|
|
|
|
else
|
|
|
|
|
|
|
|
sg_apply_pipeline(state.threedee_pip);
|
|
|
|
//colorquad(false, quad_at(V2(0.0, 100.0), V2(100.0f, 100.0f)), RED);
|
|
|
|
sg_bindings bindings = {0};
|
|
|
|
sg_image img = image_white_square;
|
|
|
|
bindings.fs_images[SLOT_threedee_tex] = it->mesh->image;
|
|
|
|
AABB region = full_region(img);
|
|
|
|
if(!for_outline)
|
|
|
|
//region.lower_right.X *= 0.5f;
|
|
|
|
bindings.fs_images[SLOT_threedee_shadow_map] = state.shadows.color_img;
|
|
|
|
draw_quad((DrawParams) { false, quad_at(V2(0.0, 100.0), V2(100.0f, 100.0f)), img, region, WHITE });
|
|
|
|
bindings.vertex_buffers[0] = it->mesh->loaded_buffer;
|
|
|
|
|
|
|
|
sg_apply_bindings(&bindings);
|
|
|
|
|
|
|
|
|
|
|
|
flush_quad_batch();
|
|
|
|
Mat4 model = transform_to_matrix(it->t);
|
|
|
|
sg_end_pass();
|
|
|
|
threedee_vs_params_t vs_params = {
|
|
|
|
sg_commit();
|
|
|
|
.model = model,
|
|
|
|
}
|
|
|
|
.view = view,
|
|
|
|
return;
|
|
|
|
.projection = projection,
|
|
|
|
#endif
|
|
|
|
.directional_light_space_matrix = light_space_matrix,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_threedee_vs_params, &SG_RANGE(vs_params));
|
|
|
|
|
|
|
|
num_draw_calls += 1;
|
|
|
|
|
|
|
|
num_vertices += (int)it->mesh->num_vertices;
|
|
|
|
|
|
|
|
|
|
|
|
PROFILE_SCOPE("frame")
|
|
|
|
if(!for_outline)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
uint64_t time_start_frame = stm_now();
|
|
|
|
threedee_fs_params_t fs_params = {0};
|
|
|
|
|
|
|
|
fs_params.shadow_map_dimension = SHADOW_MAP_DIMENSION;
|
|
|
|
|
|
|
|
sg_apply_uniforms(SG_SHADERSTAGE_FS, SLOT_threedee_fs_params, &SG_RANGE(fs_params));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Vec3 player_pos = V3(gs.player->pos.x, 0.0, gs.player->pos.y);
|
|
|
|
sg_draw(0, (int)it->mesh->num_vertices, 1);
|
|
|
|
//dbgline(V2(0,0), V2(500, 500));
|
|
|
|
|
|
|
|
const float vertical_to_horizontal_ratio = CAM_VERTICAL_TO_HORIZONTAL_RATIO;
|
|
|
|
|
|
|
|
const float cam_distance = CAM_DISTANCE;
|
|
|
|
|
|
|
|
Vec3 away_from_player;
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
float ratio = vertical_to_horizontal_ratio;
|
|
|
|
|
|
|
|
float x = sqrtf( (cam_distance * cam_distance) / (1 + (ratio*ratio)) );
|
|
|
|
|
|
|
|
float y = ratio * x;
|
|
|
|
|
|
|
|
away_from_player = V3(x, y, 0.0);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
away_from_player = MulM4V4(Rotate_RH(-PI32/3.0f + PI32, V3(0,1,0)), IsPoint(away_from_player)).xyz;
|
|
|
|
|
|
|
|
Vec3 cam_pos = AddV3(player_pos, away_from_player);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Vec2 movement = { 0 };
|
|
|
|
if(it->armature)
|
|
|
|
bool interact = false;
|
|
|
|
|
|
|
|
if (mobile_controls)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
movement = SubV2(thumbstick_nub_pos, thumbstick_base_pos);
|
|
|
|
|
|
|
|
if (LenV2(movement) > 0.0f)
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
movement = MulV2F(NormV2(movement), LenV2(movement) / (thumbstick_base_size()*0.5f));
|
|
|
|
if(for_outline)
|
|
|
|
}
|
|
|
|
sg_apply_pipeline(state.outline_armature_pip);
|
|
|
|
interact = pressed.interact;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
else
|
|
|
|
|
|
|
|
sg_apply_pipeline(state.armature_pip);
|
|
|
|
|
|
|
|
sg_bindings bindings = {0};
|
|
|
|
|
|
|
|
bindings.vs_images[SLOT_threedee_bones_tex] = it->armature->bones_texture;
|
|
|
|
|
|
|
|
bindings.fs_images[SLOT_threedee_tex] = it->armature->image;
|
|
|
|
|
|
|
|
if(!for_outline)
|
|
|
|
|
|
|
|
bindings.fs_images[SLOT_threedee_shadow_map] = state.shadows.color_img;
|
|
|
|
|
|
|
|
bindings.vertex_buffers[0] = it->armature->loaded_buffer;
|
|
|
|
|
|
|
|
sg_apply_bindings(&bindings);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Mat4 model = transform_to_matrix(it->t);
|
|
|
|
|
|
|
|
threedee_skeleton_vs_params_t params = {
|
|
|
|
|
|
|
|
.model = model,
|
|
|
|
|
|
|
|
.view = view,
|
|
|
|
|
|
|
|
.projection = projection,
|
|
|
|
|
|
|
|
.directional_light_space_matrix = light_space_matrix,
|
|
|
|
|
|
|
|
.bones_tex_size = V2((float)it->armature->bones_texture_width,(float)it->armature->bones_texture_height),
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_threedee_skeleton_vs_params, &SG_RANGE(params));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(!for_outline)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
movement = V2(
|
|
|
|
threedee_fs_params_t fs_params = {0};
|
|
|
|
(float)keydown[SAPP_KEYCODE_D] - (float)keydown[SAPP_KEYCODE_A],
|
|
|
|
fs_params.shadow_map_dimension = SHADOW_MAP_DIMENSION;
|
|
|
|
(float)keydown[SAPP_KEYCODE_W] - (float)keydown[SAPP_KEYCODE_S]
|
|
|
|
sg_apply_uniforms(SG_SHADERSTAGE_FS, SLOT_threedee_fs_params, &SG_RANGE(fs_params));
|
|
|
|
);
|
|
|
|
|
|
|
|
interact = pressed.interact;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (LenV2(movement) > 1.0)
|
|
|
|
|
|
|
|
{
|
|
|
|
num_draw_calls += 1;
|
|
|
|
movement = NormV2(movement);
|
|
|
|
num_vertices += (int)it->armature->vertices_length;
|
|
|
|
|
|
|
|
sg_draw(0, (int)it->armature->vertices_length, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// progress the animation, then blend the two animations if necessary, and finally
|
|
|
|
// I moved this out into its own separate function so that you could
|
|
|
|
// output into anim_blended_poses
|
|
|
|
// define helper functions to be used multiple times in it, and those functions
|
|
|
|
ARR_ITER(Armature*, armatures)
|
|
|
|
// would be near the actual 3d drawing in the file
|
|
|
|
|
|
|
|
void flush_all_drawn_things(Vec3 light_dir)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// Draw all the 3D drawn things. Draw the shadows, then draw the things with the shadows.
|
|
|
|
|
|
|
|
// Process armatures and upload their skeleton textures
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Armature *cur = *it;
|
|
|
|
// Animate armatures, and upload their bone textures. Also debug draw their skeleton
|
|
|
|
|
|
|
|
|
|
|
|
if(cur->go_to_animation.size > 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if(MD_S8Match(cur->go_to_animation, cur->target_animation, 0))
|
|
|
|
SLICE_ITER(DrawnThing, drawn_this_frame)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
}
|
|
|
|
if(it->armature)
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
memcpy(cur->current_poses, cur->anim_blended_poses, cur->bones_length * sizeof(*cur->current_poses));
|
|
|
|
MD_ArenaTemp scratch = MD_GetScratch(0, 0);
|
|
|
|
cur->target_animation = cur->go_to_animation;
|
|
|
|
Armature *armature = it->armature;
|
|
|
|
cur->animation_blend_t = 0.0f;
|
|
|
|
int bones_tex_size = 4 * armature->bones_texture_width * armature->bones_texture_height;
|
|
|
|
cur->go_to_animation = (MD_String8){0};
|
|
|
|
MD_u8 *bones_tex = MD_ArenaPush(scratch.arena, bones_tex_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(cur->animation_blend_t < 1.0f)
|
|
|
|
for(MD_u64 i = 0; i < armature->bones_length; i++)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
cur->animation_blend_t += dt / ANIMATION_BLEND_TIME;
|
|
|
|
Bone *cur = &armature->bones[i];
|
|
|
|
|
|
|
|
|
|
|
|
Animation *to_anim = get_anim_by_name(cur, cur->target_animation);
|
|
|
|
|
|
|
|
assert(to_anim);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(MD_u64 i = 0; i < cur->bones_length; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Transform *output_transform = &cur->anim_blended_poses[i];
|
|
|
|
|
|
|
|
Transform from_transform = cur->current_poses[i];
|
|
|
|
|
|
|
|
Transform to_transform = get_animated_bone_transform(&to_anim->tracks[i], &cur->bones[i], (float)elapsed_time);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*output_transform = lerp_transforms(from_transform, cur->animation_blend_t, to_transform);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Animation *cur_anim = get_anim_by_name(cur, cur->target_animation);
|
|
|
|
|
|
|
|
for(MD_u64 i = 0; i < cur->bones_length; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
cur->anim_blended_poses[i] = get_animated_bone_transform(&cur_anim->tracks[i], &cur->bones[i], (float)elapsed_time);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Vec3 light_dir;
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
float spin_factor = 0.5f;
|
|
|
|
|
|
|
|
float t = (float)elapsed_time * spin_factor;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float x = cosf(t);
|
|
|
|
|
|
|
|
float z = sinf(t);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
light_dir = NormV3(V3(x, -0.5f, z));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// make movement relative to camera forward
|
|
|
|
|
|
|
|
Vec3 facing = NormV3(SubV3(player_pos, cam_pos));
|
|
|
|
|
|
|
|
Vec3 right = Cross(facing, V3(0,1,0));
|
|
|
|
|
|
|
|
Vec2 forward_2d = NormV2(V2(facing.x, facing.z));
|
|
|
|
|
|
|
|
Vec2 right_2d = NormV2(V2(right.x, right.z));
|
|
|
|
|
|
|
|
movement = AddV2(MulV2F(forward_2d, movement.y), MulV2F(right_2d, movement.x));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
view = Translate(V3(0.0, 1.0, -5.0f));
|
|
|
|
|
|
|
|
//view = LookAt_RH(V3(0,1,-5
|
|
|
|
|
|
|
|
if(flycam)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Basis basis = flycam_basis();
|
|
|
|
|
|
|
|
view = LookAt_RH(flycam_pos, AddV3(flycam_pos, basis.forward), V3(0, 1, 0));
|
|
|
|
|
|
|
|
//view = flycam_matrix();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
view = LookAt_RH(cam_pos, player_pos, V3(0, 1, 0));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
projection = Perspective_RH_NO(FIELD_OF_VIEW, screen_size().x / screen_size().y, NEAR_PLANE_DISTANCE, FAR_PLANE_DISTANCE);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(PlacedMesh *cur = level_threedee.placed_mesh_list; cur; cur = cur->next)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
draw_thing((DrawnThing){.mesh = cur->draw_with, .t = cur->t});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ENTITIES_ITER(gs.entities)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if(it->is_npc || it->is_character)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Transform draw_with = entity_transform(it);
|
|
|
|
|
|
|
|
if(it->npc_kind == NPC_Player)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
draw_thing((DrawnThing){.armature = &player_armature, .t = draw_with});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else if(it->npc_kind == NPC_Farmer)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
farmer_armature.go_to_animation = MD_S8Lit("Dance");
|
|
|
|
|
|
|
|
draw_thing((DrawnThing){.armature = &farmer_armature, .t = draw_with});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
draw_thing((DrawnThing){.mesh = &mesh_player, .t = draw_with});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Draw all the 3D drawn things. Draw the shadows, then draw the things with the shadows.
|
|
|
|
|
|
|
|
// Process armatures and upload their skeleton textures
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// Animate armatures, and upload their bone textures. Also debug draw their skeleton
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
SLICE_ITER(DrawnThing, drawn_this_frame)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if(it->armature)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
MD_ArenaTemp scratch = MD_GetScratch(0, 0);
|
|
|
|
|
|
|
|
Armature *armature = it->armature;
|
|
|
|
|
|
|
|
int bones_tex_size = 4 * armature->bones_texture_width * armature->bones_texture_height;
|
|
|
|
|
|
|
|
MD_u8 *bones_tex = MD_ArenaPush(scratch.arena, bones_tex_size);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(MD_u64 i = 0; i < armature->bones_length; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Bone *cur = &armature->bones[i];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// for debug drawing
|
|
|
|
// for debug drawing
|
|
|
|
Vec3 from = MulM4V3(cur->matrix_local, V3(0,0,0));
|
|
|
|
Vec3 from = MulM4V3(cur->matrix_local, V3(0,0,0));
|
|
|
@ -5271,89 +5309,249 @@ void frame(void)
|
|
|
|
sg_end_pass();
|
|
|
|
sg_end_pass();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// do the outline pass
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
sg_begin_pass(state.outline_pass, &(sg_pass_action) {
|
|
|
|
|
|
|
|
.colors[0] = {
|
|
|
|
|
|
|
|
.action = SG_ACTION_CLEAR,
|
|
|
|
|
|
|
|
.value = { 0.0f, 0.0f, 0.0f, 0.0f },
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SLICE_ITER(DrawnThing, drawn_this_frame)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if(it->outline)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
actually_draw_thing(it, light_space_matrix, true);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sg_end_pass();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// actually draw, IMPORTANT after this drawn_this_frame is zeroed out!
|
|
|
|
// actually draw, IMPORTANT after this drawn_this_frame is zeroed out!
|
|
|
|
{
|
|
|
|
{
|
|
|
|
sg_begin_default_pass(&state.clear_everything_pass_action, sapp_width(), sapp_height());
|
|
|
|
sg_begin_default_pass(&state.clear_everything_pass_action, sapp_width(), sapp_height());
|
|
|
|
|
|
|
|
|
|
|
|
// draw meshes
|
|
|
|
// draw meshes
|
|
|
|
sg_apply_pipeline(state.threedee_pip);
|
|
|
|
|
|
|
|
SLICE_ITER(DrawnThing, drawn_this_frame)
|
|
|
|
SLICE_ITER(DrawnThing, drawn_this_frame)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if(it->mesh)
|
|
|
|
actually_draw_thing(it, light_space_matrix, false);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// draw armatures armature rendering
|
|
|
|
|
|
|
|
SLICE_ITER(DrawnThing, drawn_this_frame)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
sg_bindings bindings = {0};
|
|
|
|
actually_draw_thing(it, light_space_matrix, false);
|
|
|
|
bindings.fs_images[SLOT_threedee_tex] = it->mesh->image;
|
|
|
|
}
|
|
|
|
bindings.fs_images[SLOT_threedee_shadow_map] = state.shadows.color_img;
|
|
|
|
|
|
|
|
bindings.vertex_buffers[0] = it->mesh->loaded_buffer;
|
|
|
|
|
|
|
|
sg_apply_bindings(&bindings);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Mat4 model = transform_to_matrix(it->t);
|
|
|
|
|
|
|
|
threedee_vs_params_t vs_params = {
|
|
|
|
|
|
|
|
.model = model,
|
|
|
|
|
|
|
|
.view = view,
|
|
|
|
|
|
|
|
.projection = projection,
|
|
|
|
|
|
|
|
.directional_light_space_matrix = light_space_matrix,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_threedee_vs_params, &SG_RANGE(vs_params));
|
|
|
|
|
|
|
|
num_draw_calls += 1;
|
|
|
|
|
|
|
|
num_vertices += (int)it->mesh->num_vertices;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
threedee_fs_params_t fs_params = {0};
|
|
|
|
// zero out everything
|
|
|
|
fs_params.shadow_map_dimension = SHADOW_MAP_DIMENSION;
|
|
|
|
SLICE_ITER(DrawnThing, drawn_this_frame)
|
|
|
|
sg_apply_uniforms(SG_SHADERSTAGE_FS, SLOT_threedee_fs_params, &SG_RANGE(fs_params));
|
|
|
|
{
|
|
|
|
|
|
|
|
*it = (DrawnThing){0};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
sg_end_pass();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
drawn_this_frame_length = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sg_draw(0, (int)it->mesh->num_vertices, 1);
|
|
|
|
void frame(void)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
static float speed_factor = 1.0f;
|
|
|
|
|
|
|
|
// elapsed_time
|
|
|
|
|
|
|
|
double unwarped_dt_double = 0.0;
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
unwarped_dt_double = stm_sec(stm_diff(stm_now(), last_frame_time));
|
|
|
|
|
|
|
|
unwarped_dt_double = fmin(unwarped_dt_double, MINIMUM_TIMESTEP * 5.0); // clamp dt at maximum 5 frames, avoid super huge dt
|
|
|
|
|
|
|
|
elapsed_time += unwarped_dt_double*speed_factor;
|
|
|
|
|
|
|
|
unwarped_elapsed_time += unwarped_dt_double;
|
|
|
|
|
|
|
|
last_frame_time = stm_now();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
double dt_double = unwarped_dt_double*speed_factor;
|
|
|
|
|
|
|
|
float unwarped_dt = (float)unwarped_dt_double;
|
|
|
|
|
|
|
|
float dt = (float)dt_double;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
printf("Frametime: %.1f ms\n", dt*1000.0);
|
|
|
|
|
|
|
|
sg_begin_default_pass(&state.pass_action, sapp_width(), sapp_height());
|
|
|
|
|
|
|
|
sg_apply_pipeline(state.twodee_pipeline);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//colorquad(false, quad_at(V2(0.0, 100.0), V2(100.0f, 100.0f)), RED);
|
|
|
|
|
|
|
|
sg_image img = image_white_square;
|
|
|
|
|
|
|
|
AABB region = full_region(img);
|
|
|
|
|
|
|
|
//region.lower_right.X *= 0.5f;
|
|
|
|
|
|
|
|
draw_quad((DrawParams) { false, quad_at(V2(0.0, 100.0), V2(100.0f, 100.0f)), img, region, WHITE });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
flush_quad_batch();
|
|
|
|
|
|
|
|
sg_end_pass();
|
|
|
|
|
|
|
|
sg_commit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PROFILE_SCOPE("frame")
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
uint64_t time_start_frame = stm_now();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Vec3 player_pos = V3(gs.player->pos.x, 0.0, gs.player->pos.y);
|
|
|
|
|
|
|
|
//dbgline(V2(0,0), V2(500, 500));
|
|
|
|
|
|
|
|
const float vertical_to_horizontal_ratio = CAM_VERTICAL_TO_HORIZONTAL_RATIO;
|
|
|
|
|
|
|
|
const float cam_distance = CAM_DISTANCE;
|
|
|
|
|
|
|
|
Vec3 away_from_player;
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
float ratio = vertical_to_horizontal_ratio;
|
|
|
|
|
|
|
|
float x = sqrtf( (cam_distance * cam_distance) / (1 + (ratio*ratio)) );
|
|
|
|
|
|
|
|
float y = ratio * x;
|
|
|
|
|
|
|
|
away_from_player = V3(x, y, 0.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
away_from_player = MulM4V4(Rotate_RH(-PI32/3.0f + PI32, V3(0,1,0)), IsPoint(away_from_player)).xyz;
|
|
|
|
|
|
|
|
Vec3 cam_pos = AddV3(player_pos, away_from_player);
|
|
|
|
|
|
|
|
|
|
|
|
// draw armatures armature rendering
|
|
|
|
Vec2 movement = { 0 };
|
|
|
|
sg_apply_pipeline(state.armature_pip);
|
|
|
|
bool interact = false;
|
|
|
|
SLICE_ITER(DrawnThing, drawn_this_frame)
|
|
|
|
if (mobile_controls)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if(it->armature)
|
|
|
|
movement = SubV2(thumbstick_nub_pos, thumbstick_base_pos);
|
|
|
|
|
|
|
|
if (LenV2(movement) > 0.0f)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
sg_bindings bindings = {0};
|
|
|
|
movement = MulV2F(NormV2(movement), LenV2(movement) / (thumbstick_base_size()*0.5f));
|
|
|
|
bindings.vs_images[SLOT_threedee_bones_tex] = it->armature->bones_texture;
|
|
|
|
}
|
|
|
|
bindings.fs_images[SLOT_threedee_tex] = it->armature->image;
|
|
|
|
interact = pressed.interact;
|
|
|
|
bindings.fs_images[SLOT_threedee_shadow_map] = state.shadows.color_img;
|
|
|
|
}
|
|
|
|
bindings.vertex_buffers[0] = it->armature->loaded_buffer;
|
|
|
|
else
|
|
|
|
sg_apply_bindings(&bindings);
|
|
|
|
{
|
|
|
|
|
|
|
|
movement = V2(
|
|
|
|
|
|
|
|
(float)keydown[SAPP_KEYCODE_D] - (float)keydown[SAPP_KEYCODE_A],
|
|
|
|
|
|
|
|
(float)keydown[SAPP_KEYCODE_W] - (float)keydown[SAPP_KEYCODE_S]
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
interact = pressed.interact;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (LenV2(movement) > 1.0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
movement = NormV2(movement);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Mat4 model = transform_to_matrix(it->t);
|
|
|
|
// progress the animation, then blend the two animations if necessary, and finally
|
|
|
|
threedee_skeleton_vs_params_t params = {
|
|
|
|
// output into anim_blended_poses
|
|
|
|
.model = model,
|
|
|
|
ARR_ITER(Armature*, armatures)
|
|
|
|
.view = view,
|
|
|
|
{
|
|
|
|
.projection = projection,
|
|
|
|
Armature *cur = *it;
|
|
|
|
.directional_light_space_matrix = light_space_matrix,
|
|
|
|
|
|
|
|
.bones_tex_size = V2((float)it->armature->bones_texture_width,(float)it->armature->bones_texture_height),
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_threedee_skeleton_vs_params, &SG_RANGE(params));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
threedee_fs_params_t fs_params = {0};
|
|
|
|
if(cur->go_to_animation.size > 0)
|
|
|
|
fs_params.shadow_map_dimension = SHADOW_MAP_DIMENSION;
|
|
|
|
{
|
|
|
|
sg_apply_uniforms(SG_SHADERSTAGE_FS, SLOT_threedee_fs_params, &SG_RANGE(fs_params));
|
|
|
|
if(MD_S8Match(cur->go_to_animation, cur->target_animation, 0))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
memcpy(cur->current_poses, cur->anim_blended_poses, cur->bones_length * sizeof(*cur->current_poses));
|
|
|
|
|
|
|
|
cur->target_animation = cur->go_to_animation;
|
|
|
|
|
|
|
|
cur->animation_blend_t = 0.0f;
|
|
|
|
|
|
|
|
cur->go_to_animation = (MD_String8){0};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
num_draw_calls += 1;
|
|
|
|
if(cur->animation_blend_t < 1.0f)
|
|
|
|
num_vertices += (int)it->armature->vertices_length;
|
|
|
|
{
|
|
|
|
sg_draw(0, (int)it->armature->vertices_length, 1);
|
|
|
|
cur->animation_blend_t += dt / ANIMATION_BLEND_TIME;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Animation *to_anim = get_anim_by_name(cur, cur->target_animation);
|
|
|
|
|
|
|
|
assert(to_anim);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(MD_u64 i = 0; i < cur->bones_length; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Transform *output_transform = &cur->anim_blended_poses[i];
|
|
|
|
|
|
|
|
Transform from_transform = cur->current_poses[i];
|
|
|
|
|
|
|
|
Transform to_transform = get_animated_bone_transform(&to_anim->tracks[i], &cur->bones[i], (float)elapsed_time);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*output_transform = lerp_transforms(from_transform, cur->animation_blend_t, to_transform);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Animation *cur_anim = get_anim_by_name(cur, cur->target_animation);
|
|
|
|
|
|
|
|
for(MD_u64 i = 0; i < cur->bones_length; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
cur->anim_blended_poses[i] = get_animated_bone_transform(&cur_anim->tracks[i], &cur->bones[i], (float)elapsed_time);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Vec3 light_dir;
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
float spin_factor = 0.5f;
|
|
|
|
|
|
|
|
float t = (float)elapsed_time * spin_factor;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float x = cosf(t);
|
|
|
|
|
|
|
|
float z = sinf(t);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
light_dir = NormV3(V3(x, -0.5f, z));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// zero out everything
|
|
|
|
|
|
|
|
SLICE_ITER(DrawnThing, drawn_this_frame)
|
|
|
|
// make movement relative to camera forward
|
|
|
|
|
|
|
|
Vec3 facing = NormV3(SubV3(player_pos, cam_pos));
|
|
|
|
|
|
|
|
Vec3 right = Cross(facing, V3(0,1,0));
|
|
|
|
|
|
|
|
Vec2 forward_2d = NormV2(V2(facing.x, facing.z));
|
|
|
|
|
|
|
|
Vec2 right_2d = NormV2(V2(right.x, right.z));
|
|
|
|
|
|
|
|
movement = AddV2(MulV2F(forward_2d, movement.y), MulV2F(right_2d, movement.x));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
view = Translate(V3(0.0, 1.0, -5.0f));
|
|
|
|
|
|
|
|
//view = LookAt_RH(V3(0,1,-5
|
|
|
|
|
|
|
|
if(flycam)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
*it = (DrawnThing){0};
|
|
|
|
Basis basis = flycam_basis();
|
|
|
|
|
|
|
|
view = LookAt_RH(flycam_pos, AddV3(flycam_pos, basis.forward), V3(0, 1, 0));
|
|
|
|
|
|
|
|
//view = flycam_matrix();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sg_end_pass();
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
view = LookAt_RH(cam_pos, player_pos, V3(0, 1, 0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
drawn_this_frame_length = 0;
|
|
|
|
|
|
|
|
|
|
|
|
projection = Perspective_RH_NO(FIELD_OF_VIEW, screen_size().x / screen_size().y, NEAR_PLANE_DISTANCE, FAR_PLANE_DISTANCE);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(PlacedMesh *cur = level_threedee.placed_mesh_list; cur; cur = cur->next)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
draw_thing((DrawnThing){.mesh = cur->draw_with, .t = cur->t});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ENTITIES_ITER(gs.entities)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if(it->is_npc || it->is_character)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Transform draw_with = entity_transform(it);
|
|
|
|
|
|
|
|
if(it->npc_kind == NPC_Player)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
draw_thing((DrawnThing){.armature = &player_armature, .t = draw_with, .outline = true});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else if(it->npc_kind == NPC_Farmer)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
farmer_armature.go_to_animation = MD_S8Lit("Dance");
|
|
|
|
|
|
|
|
draw_thing((DrawnThing){.armature = &farmer_armature, .t = draw_with});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
draw_thing((DrawnThing){.mesh = &mesh_player, .t = draw_with});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
flush_all_drawn_things(light_dir);
|
|
|
|
|
|
|
|
|
|
|
|
// 2d drawing
|
|
|
|
// draw the freaking outline. Play ball!
|
|
|
|
|
|
|
|
draw_quad((DrawParams){quad_at(V2(0.0, screen_size().y), screen_size()), IMG(state.outline_pass_image), WHITE, .layer = LAYER_UI_FG, .custom_pipeline = state.twodee_outline_pip});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 2d drawing TODO move this to when the drawing is flushed.
|
|
|
|
sg_begin_default_pass(&state.clear_depth_buffer_pass_action, sapp_width(), sapp_height());
|
|
|
|
sg_begin_default_pass(&state.clear_depth_buffer_pass_action, sapp_width(), sapp_height());
|
|
|
|
sg_apply_pipeline(state.pip);
|
|
|
|
sg_apply_pipeline(state.twodee_pip);
|
|
|
|
|
|
|
|
|
|
|
|
// Draw Tilemap draw tilemap tilemap drawing
|
|
|
|
// Draw Tilemap draw tilemap tilemap drawing
|
|
|
|
#if 0
|
|
|
|
#if 0
|
|
|
@ -6809,8 +7007,8 @@ void frame(void)
|
|
|
|
if (show_devtools)
|
|
|
|
if (show_devtools)
|
|
|
|
PROFILE_SCOPE("statistics")
|
|
|
|
PROFILE_SCOPE("statistics")
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// shadow map
|
|
|
|
|
|
|
|
draw_quad((DrawParams){quad_at(V2(screen_size().x - 512.0f, screen_size().y), V2(512.0f, 512.0f)), IMG(state.shadows.color_img), WHITE, .layer = LAYER_UI_FG});
|
|
|
|
draw_quad((DrawParams){quad_at(V2(screen_size().x - 512.0f, screen_size().y), V2(512.0f, 512.0f)), IMG(state.shadows.color_img), WHITE, .layer = LAYER_UI_FG});
|
|
|
|
|
|
|
|
draw_quad((DrawParams){quad_at(V2(0.0, screen_size().y/2.0f), MulV2F(screen_size(), 0.1f)), IMG(state.outline_pass_image), WHITE, .layer = LAYER_UI_FG});
|
|
|
|
|
|
|
|
|
|
|
|
Vec2 pos = V2(0.0, screen_size().Y);
|
|
|
|
Vec2 pos = V2(0.0, screen_size().Y);
|
|
|
|
int num_entities = 0;
|
|
|
|
int num_entities = 0;
|
|
|
@ -6829,7 +7027,7 @@ void frame(void)
|
|
|
|
#endif // devtools
|
|
|
|
#endif // devtools
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// @Place(actually render)
|
|
|
|
// @Place(actually render 2d)
|
|
|
|
PROFILE_SCOPE("flush rendering")
|
|
|
|
PROFILE_SCOPE("flush rendering")
|
|
|
|
{
|
|
|
|
{
|
|
|
|
ARR_ITER_I(RenderingQueue, rendering_queues, i)
|
|
|
|
ARR_ITER_I(RenderingQueue, rendering_queues, i)
|
|
|
@ -6844,34 +7042,29 @@ void frame(void)
|
|
|
|
PROFILE_SCOPE("Draw quad")
|
|
|
|
PROFILE_SCOPE("Draw quad")
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Vec2 *points = d.quad.points;
|
|
|
|
Vec2 *points = d.quad.points;
|
|
|
|
quad_fs_params_t params = { 0 };
|
|
|
|
threedee_twodee_fs_params_t params = {
|
|
|
|
params.tint[0] = d.tint.R;
|
|
|
|
.tint = d.tint,
|
|
|
|
params.tint[1] = d.tint.G;
|
|
|
|
};
|
|
|
|
params.tint[2] = d.tint.B;
|
|
|
|
|
|
|
|
params.tint[3] = d.tint.A;
|
|
|
|
|
|
|
|
params.alpha_clip_threshold = d.alpha_clip_threshold;
|
|
|
|
params.alpha_clip_threshold = d.alpha_clip_threshold;
|
|
|
|
if (d.do_clipping)
|
|
|
|
if (d.do_clipping)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Vec2 aabb_clip_ul = into_clip_space(d.clip_to.upper_left);
|
|
|
|
Vec2 aabb_clip_ul = into_clip_space(d.clip_to.upper_left);
|
|
|
|
Vec2 aabb_clip_lr = into_clip_space(d.clip_to.lower_right);
|
|
|
|
Vec2 aabb_clip_lr = into_clip_space(d.clip_to.lower_right);
|
|
|
|
params.clip_ul[0] = aabb_clip_ul.x;
|
|
|
|
params.clip_ul = aabb_clip_ul;
|
|
|
|
params.clip_ul[1] = aabb_clip_ul.y;
|
|
|
|
params.clip_lr = aabb_clip_lr;
|
|
|
|
params.clip_lr[0] = aabb_clip_lr.x;
|
|
|
|
|
|
|
|
params.clip_lr[1] = aabb_clip_lr.y;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
else
|
|
|
|
{
|
|
|
|
{
|
|
|
|
params.clip_ul[0] = -1.0;
|
|
|
|
params.clip_ul = V2(-1.0, 1.0);
|
|
|
|
params.clip_ul[1] = 1.0;
|
|
|
|
params.clip_lr = V2(1.0, -1.0);
|
|
|
|
params.clip_lr[0] = 1.0;
|
|
|
|
|
|
|
|
params.clip_lr[1] = -1.0;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if the rendering call is different, and the batch must be flushed
|
|
|
|
// if the rendering call is different, and the batch must be flushed
|
|
|
|
if (d.image.id != cur_batch_image.id || memcmp(¶ms, &cur_batch_params, sizeof(params)) != 0)
|
|
|
|
if (d.image.id != cur_batch_image.id || memcmp(¶ms, &cur_batch_params, sizeof(params)) != 0 || d.custom_pipeline.id != cur_batch_pipeline.id)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
flush_quad_batch();
|
|
|
|
flush_quad_batch();
|
|
|
|
cur_batch_image = d.image;
|
|
|
|
cur_batch_image = d.image;
|
|
|
|
cur_batch_params = params;
|
|
|
|
cur_batch_params = params;
|
|
|
|
|
|
|
|
cur_batch_pipeline = d.custom_pipeline;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -6990,6 +7183,11 @@ void cleanup(void)
|
|
|
|
void event(const sapp_event *e)
|
|
|
|
void event(const sapp_event *e)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (e->key_repeat) return;
|
|
|
|
if (e->key_repeat) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (e->type == SAPP_EVENTTYPE_RESIZED)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
create_outline_gfx_state();
|
|
|
|
|
|
|
|
}
|
|
|
|
if (e->type == SAPP_EVENTTYPE_TOUCHES_BEGAN)
|
|
|
|
if (e->type == SAPP_EVENTTYPE_TOUCHES_BEGAN)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (!mobile_controls)
|
|
|
|
if (!mobile_controls)
|
|
|
|