@ -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 ;
// elapsed_time
double unwarped_dt_double = 0.0 ;
{
{
unwarped_dt_double = stm_sec ( stm_diff ( stm_now ( ) , last_frame_time ) ) ;
if ( it - > mesh )
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 ) ;
sg_bindings bindings = { 0 } ;
bindings . fs_images [ SLOT_threedee_tex ] = it - > mesh - > image ;
if ( ! for_outline )
bindings . fs_images [ SLOT_threedee_shadow_map ] = state . shadows . color_img ;
bindings . vertex_buffers [ 0 ] = it - > mesh - > loaded_buffer ;
sg_apply_bindings ( & bindings ) ;
//colorquad(false, quad_at(V2(0.0, 100.0), V2(100.0f, 100.0f)), RED);
Mat4 model = transform_to_matrix ( it - > t ) ;
sg_image img = image_white_square ;
threedee_vs_params_t vs_params = {
AABB region = full_region ( img ) ;
. model = model ,
//region.lower_right.X *= 0.5f;
. view = view ,
draw_quad ( ( DrawParams ) { false , quad_at ( V2 ( 0.0 , 100.0 ) , V2 ( 100.0f , 100.0f ) ) , img , region , WHITE } ) ;
. 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 ;
if ( ! for_outline )
{
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 ) ) ;
}
flush_quad_batch ( ) ;
sg_draw ( 0 , ( int ) it - > mesh - > num_vertices , 1 ) ;
sg_end_pass ( ) ;
sg_commit ( ) ;
}
}
return ;
# endif
PROFILE_SCOPE ( " frame " )
if ( it - > armature )
{
{
uint64_t time_start_frame = stm_now ( ) ;
if ( for_outline )
sg_apply_pipeline ( state . outline_armature_pip ) ;
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 ) ;
Vec3 player_pos = V3 ( gs . player - > pos . x , 0.0 , gs . player - > pos . y ) ;
Mat4 model = transform_to_matrix ( it - > t ) ;
//dbgline(V2(0,0), V2(500, 500));
threedee_skeleton_vs_params_t params = {
const float vertical_to_horizontal_ratio = CAM_VERTICAL_TO_HORIZONTAL_RATIO ;
. model = model ,
const float cam_distance = CAM_DISTANCE ;
. view = view ,
Vec3 away_from_player ;
. projection = projection ,
{
. directional_light_space_matrix = light_space_matrix ,
float ratio = vertical_to_horizontal_ratio ;
. bones_tex_size = V2 ( ( float ) it - > armature - > bones_texture_width , ( float ) it - > armature - > bones_texture_height ) ,
float x = sqrtf ( ( cam_distance * cam_distance ) / ( 1 + ( ratio * ratio ) ) ) ;
} ;
float y = ratio * x ;
sg_apply_uniforms ( SG_SHADERSTAGE_VS , SLOT_threedee_skeleton_vs_params , & SG_RANGE ( params ) ) ;
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 ( ! for_outline )
bool interact = false ;
if ( mobile_controls )
{
{
movement = SubV2 ( thumbstick_nub_pos , thumbstick_base_pos ) ;
threedee_fs_params_t fs_params = { 0 } ;
if ( LenV2 ( movement ) > 0.0f )
fs_params . shadow_map_dimension = SHADOW_MAP_DIMENSION ;
{
sg_apply_uniforms ( SG_SHADERSTAGE_FS , SLOT_threedee_fs_params , & SG_RANGE ( fs_params ) ) ;
movement = MulV2F ( NormV2 ( movement ) , LenV2 ( movement ) / ( thumbstick_base_size ( ) * 0.5f ) ) ;
}
interact = pressed . interact ;
}
}
else
{
num_draw_calls + = 1 ;
movement = V2 (
num_vertices + = ( int ) it - > armature - > vertices_length ;
( float ) keydown [ SAPP_KEYCODE_D ] - ( float ) keydown [ SAPP_KEYCODE_A ] ,
sg_draw ( 0 , ( int ) it - > armature - > vertices_length , 1 ) ;
( float ) keydown [ SAPP_KEYCODE_W ] - ( float ) keydown [ SAPP_KEYCODE_S ]
) ;
interact = pressed . interact ;
}
}
if ( LenV2 ( movement ) > 1.0 )
{
movement = NormV2 ( movement ) ;
}
}
// 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 )
{
{
Armature * cur = * it ;
// Draw all the 3D drawn things. Draw the shadows, then draw the things with the shadows.
// Process armatures and upload their skeleton textures
if ( cur - > go_to_animation . size > 0 )
{
{
if ( MD_S8Match ( cur - > go_to_animation , cur - > target_animation , 0 ) )
// Animate armatures, and upload their bone textures. Also debug draw their skeleton
{
{
}
SLICE_ITER ( DrawnThing , drawn_this_frame )
else
{
{
memcpy ( cur - > current_poses , cur - > anim_blended_poses , cur - > bones_length * sizeof ( * cur - > current_poses ) ) ;
if ( it - > armature )
cur - > target_animation = cur - > go_to_animation ;
cur - > animation_blend_t = 0.0f ;
cur - > go_to_animation = ( MD_String8 ) { 0 } ;
}
}
if ( cur - > animation_blend_t < 1.0f )
{
{
cur - > animation_blend_t + = dt / ANIMATION_BLEND_TIME ;
MD_ArenaTemp scratch = MD_GetScratch ( 0 , 0 ) ;
Armature * armature = it - > armature ;
Animation * to_anim = get_anim_by_name ( cur , cur - > target_animation ) ;
int bones_tex_size = 4 * armature - > bones_texture_width * armature - > bones_texture_height ;
assert ( to_anim ) ;
MD_u8 * bones_tex = MD_ArenaPush ( scratch . arena , bones_tex_size ) ;
for ( MD_u64 i = 0 ; i < cur - > bones_length ; i + + )
for ( MD_u64 i = 0 ; i < armature - > bones_length ; i + + )
{
{
Transform * output_transform = & cur - > anim_blended_poses [ i ] ;
Bone * cur = & armature - > bones [ 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 ;
// zero out everything
float x = cosf ( t ) ;
SLICE_ITER ( DrawnThing , drawn_this_frame )
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 )
{
{
* 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 ( & params , & cur_batch_params , sizeof ( params ) ) ! = 0 )
if ( d . image . id ! = cur_batch_image . id | | memcmp ( & params , & 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 )