From: hgn Date: Thu, 4 May 2023 04:35:11 +0000 (+0100) Subject: my fucking fingers X-Git-Url: https://harrygodden.com/git/?a=commitdiff_plain;h=a99e5f5d5c16a3e865796a96ad648e3c570d32ac;p=carveJwlIkooP6JGAAIwe30JlM.git my fucking fingers --- diff --git a/blender_export.py b/blender_export.py index 73d1705..7c61247 100644 --- a/blender_export.py +++ b/blender_export.py @@ -31,7 +31,8 @@ sr_entity_list = [ ('ent_font_variant', 'Font:Variant', '', 10 ), ('ent_traffic', 'Traffic Model', '', 11 ), ('ent_skateshop', 'Skate Shop', '', 12 ), - ('ent_camera', 'Camera', '', 13 ) + ('ent_camera', 'Camera', '', 13 ), + ('ent_swspreview', 'Workshop Preview', '', 14 ) ] def get_entity_enum_id( alias ): @@ -347,6 +348,13 @@ class ent_skateshop(Structure): ("id_camera",c_uint32)] #} +class ent_swspreview(Structure): +#{ + _fields_ = [("id_camera",c_uint32), + ("id_display",c_uint32), + ("id_display1",c_uint32)] +#} + class ent_camera(Structure): #{ _fields_ = [("transform",mdl_transform), @@ -1386,7 +1394,7 @@ def sr_compile( collection ): elif ent_type == 'ent_camera': #{ cam = ent_camera() compile_obj_transform( obj, cam.transform ) - cam.fov = obj.data.angle + cam.fov = obj.data.angle * 45.0 sr_ent_push(cam) #} elif ent_type == 'ent_gate': #{ @@ -1521,6 +1529,14 @@ def sr_compile( collection ): compile_obj_transform( obj, skateshop.transform ) sr_ent_push(skateshop) #} + elif ent_type == 'ent_swspreview':#{ + workshop_preview = ent_swspreview() + obj_data = obj.SR_data.ent_swspreview[0] + workshop_preview.id_display = sr_entity_id( obj_data.mark_display ) + workshop_preview.id_display1 = sr_entity_id( obj_data.mark_display1) + workshop_preview.id_camera = sr_entity_id( obj_data.cam ) + sr_ent_push( workshop_preview ) + #} #} #} @@ -2635,6 +2651,19 @@ class SR_OBJECT_ENT_SKATESHOP(bpy.types.PropertyGroup): poll=lambda self,obj: sr_filter_ent_type(obj,['ent_camera'])) #} +class SR_OBJECT_ENT_WORKSHOP_PREVIEW(bpy.types.PropertyGroup): +#{ + mark_display: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Board Display", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_marker'])) + mark_display1: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Board Display (other side)", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_marker'])) + cam: bpy.props.PointerProperty( \ + type=bpy.types.Object, name="Viewpoint", \ + poll=lambda self,obj: sr_filter_ent_type(obj,['ent_camera'])) +#} + class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup): #{ ent_gate: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_GATE) @@ -2647,6 +2676,9 @@ class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup): ent_font: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_FONT) ent_traffic: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_TRAFFIC) ent_skateshop: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_SKATESHOP) + ent_swspreview: \ + bpy.props.CollectionProperty(type=SR_OBJECT_ENT_WORKSHOP_PREVIEW) + ent_type: bpy.props.EnumProperty( name="Type", items=sr_entity_list, @@ -3621,6 +3653,18 @@ def cv_draw(): if info: cv_draw_ucube( info.matrix_world, cc2, info_cu, info_co ) #} + elif ent_type == 'ent_swspreview':#{ + cc1 = (0.4,0.9,0.2) + data = obj.SR_data.ent_swspreview[0] + display = data.mark_display + display1 = data.mark_display1 + display_cu = Vector((0.3,1.2,0.1))*0.5 + display_co = Vector((0.0,0.0,0.1))*0.5 + if display: + cv_draw_ucube( display.matrix_world, cc1, display_cu, display_co) + if display1: + cv_draw_ucube(display1.matrix_world, cc1, display_cu, display_co) + #} #} #} @@ -3655,6 +3699,7 @@ classes = [ SR_INTERFACE, SR_MATERIAL_PANEL,\ SR_OBJECT_ENT_GLYPH_ENTRY,\ SR_UL_FONT_VARIANT_LIST,SR_UL_FONT_GLYPH_LIST,\ SR_OBJECT_ENT_FONT,SR_OBJECT_ENT_TRAFFIC,SR_OBJECT_ENT_SKATESHOP,\ + SR_OBJECT_ENT_WORKSHOP_PREVIEW,\ \ SR_OBJECT_PROPERTIES, SR_LIGHT_PROPERTIES, SR_BONE_PROPERTIES, SR_MESH_PROPERTIES, SR_MATERIAL_PROPERTIES \ diff --git a/camera.h b/camera.h index 405f055..6fcd2fc 100644 --- a/camera.h +++ b/camera.h @@ -49,7 +49,7 @@ VG_STATIC void camera_lerp( camera *a, camera *b, float t, camera *d ) VG_STATIC void camera_update_transform( camera *cam ) { v4f qyaw, qpitch, qcam; - q_axis_angle( qyaw, (v3f){ 0.0f, 1.0f, 0.0f }, -cam->angles[0] ); + q_axis_angle( qyaw, (v3f){ 0.0f, 1.0f, 0.0f }, -cam->angles[0] ); q_axis_angle( qpitch, (v3f){ 1.0f, 0.0f, 0.0f }, -cam->angles[1] ); q_mul( qyaw, qpitch, qcam ); diff --git a/conf.h b/conf.h index 387ed21..eecd540 100644 --- a/conf.h +++ b/conf.h @@ -4,6 +4,8 @@ #define VG_GAME #include "vg/vg.h" +#define SKATERIFT_APPID 2103940 + VG_STATIC float cl_fov = 0.86f, cl_blur_strength = 0.3f; VG_STATIC int cl_blur = 1, diff --git a/ent_skateshop.c b/ent_skateshop.c index 3ebc9f0..e985582 100644 --- a/ent_skateshop.c +++ b/ent_skateshop.c @@ -20,13 +20,13 @@ static int skateshop_workshop_name_blacklisted( u32 hash, const char *name ) return 0; } -VG_STATIC void skateshop_loader_start( void (*pfn)(void) ) +VG_STATIC void skateshop_loader_start( void (*pfn)(void *data) ) { if( global_skateshop.loading ) vg_fatal_error( "skateshop thread sync failure\n" ); global_skateshop.loading = 1; - vg_loader_start( pfn ); + vg_loader_start( pfn, NULL ); } VG_STATIC void skateshop_async_post( void *payload, u32 size ) @@ -159,7 +159,7 @@ VG_STATIC void skateshop_load_requested_boards(void) } } -VG_STATIC void skateshop_thread1_refresh(void) +VG_STATIC void skateshop_thread1_refresh( void *data ) { skateshop_load_requested_boards(); vg_async_call( skateshop_async_post, NULL, 0 ); @@ -221,7 +221,7 @@ VG_STATIC void skateshop_use_board_suggest( int argc, const char *argv[] ) } } -VG_STATIC void skateshop_scan_for_items(void) +VG_STATIC void skateshop_scan_for_items( void *data ) { vg_linear_clear( vg_mem.scratch ); @@ -481,7 +481,7 @@ VG_STATIC void skateshop_init(void) vg_console_reg_cmd( "use_board", skateshop_use_board, skateshop_use_board_suggest ); - skateshop_scan_for_items(); + //skateshop_scan_for_items(NULL); } VG_STATIC void skateshop_render(void) diff --git a/ent_skateshop.h b/ent_skateshop.h index e7acd43..7e2fcf2 100644 --- a/ent_skateshop.h +++ b/ent_skateshop.h @@ -41,7 +41,6 @@ struct{ struct player_board board; u32 registry_id; - double last_use_time; } *dynamic_boards; diff --git a/entity.h b/entity.h index d56d702..56938ce 100644 --- a/entity.h +++ b/entity.h @@ -23,6 +23,7 @@ typedef struct ent_font_variant ent_font_variant; typedef struct ent_glyph ent_glyph; typedef struct ent_skateshop ent_skateshop; typedef struct ent_camera ent_camera; +typedef struct ent_swspreview ent_swspreview; enum entity_alias{ k_ent_none = 0, @@ -38,7 +39,8 @@ enum entity_alias{ k_ent_font_variant= 10, k_ent_traffic = 11, k_ent_skateshop = 12, - k_ent_camera = 13 + k_ent_camera = 13, + k_ent_swspreview = 14 }; static u32 mdl_entity_id_type( u32 entity_id ) @@ -220,6 +222,10 @@ struct ent_skateshop{ id_camera; }; +struct ent_swspreview{ + u32 id_camera, id_display, id_display1; +}; + struct ent_traffic{ mdl_transform transform; u32 submesh_start, diff --git a/input.h b/input.h index dffcb28..a909d7b 100644 --- a/input.h +++ b/input.h @@ -179,11 +179,8 @@ static const char *joystick_display_string( enum sr_joystick joystick ) static int buttons_filter_fixed(void) { - if( srinput.ignore_input_frames ) - return 1; - - if( vg_console.enabled ) - return 1; + if( srinput.ignore_input_frames ) return 1; + if( vg_ui.wants_mouse ) return 1; if( vg.engine_stage == k_engine_stage_update_fixed ) if( vg.fixed_iterations > 0 ) @@ -195,8 +192,7 @@ static int buttons_filter_fixed(void) /* Rising edge of button */ static int button_down( enum sr_bind button ) { - if( buttons_filter_fixed() ) - return 0; + if( buttons_filter_fixed() ) return 0; if( srinput.button_states[ button ][0] && !srinput.button_states[ button ][1] ) @@ -208,8 +204,7 @@ static int button_down( enum sr_bind button ) /* Falling edge of button */ static int button_up( enum sr_bind button ) { - if( buttons_filter_fixed() ) - return 0; + if( buttons_filter_fixed() ) return 0; if( !srinput.button_states[ button ][0] && srinput.button_states[ button ][1] ) @@ -221,15 +216,13 @@ static int button_up( enum sr_bind button ) /* State of button */ static int button_press( enum sr_bind button ) { - if( vg_console.enabled ) - return 0; - + if( vg_ui.wants_mouse ) return 0; return srinput.button_states[ button ][0]; } static void joystick_state( enum sr_joystick joystick, v2f state ) { - if( vg_console.enabled ) + if( vg_ui.wants_mouse ) v2_zero( state ); else v2_copy( srinput.joystick_states[ joystick ][0], state ); @@ -237,7 +230,7 @@ static void joystick_state( enum sr_joystick joystick, v2f state ) static float axis_state( enum sr_axis axis ) { - if( vg_console.enabled ) return 0.0f; + if( vg_ui.wants_mouse ) return 0.0f; else return srinput.axis_states[axis][0]; } @@ -312,7 +305,7 @@ static void skaterift_preupdate_inputs(void) if( vg_getkey( SDLK_RIGHT ) ) srinput.axis_states[ k_sraxis_mbrowse_h ][0] += 1.0f; - if( vg_input.active_controller_index != -1 ){ + if( vg_input.active_controller_index >= 0 ){ struct vg_controller *controller = &vg_input.controllers[vg_input.active_controller_index]; diff --git a/maps_src/mp_spawn.mdl b/maps_src/mp_spawn.mdl index 3692a9c..ca63a88 100644 Binary files a/maps_src/mp_spawn.mdl and b/maps_src/mp_spawn.mdl differ diff --git a/models_src/boards/workshop/2971125779/skaterift_fish.mdl b/models_src/boards/workshop/2971125779/skaterift_fish.mdl new file mode 100644 index 0000000..33af54e Binary files /dev/null and b/models_src/boards/workshop/2971125779/skaterift_fish.mdl differ diff --git a/network.h b/network.h index ffd2dbe..3d45ab8 100644 --- a/network.h +++ b/network.h @@ -92,11 +92,12 @@ VG_STATIC void request_auth_ticket(void) */ vg_info( "Requesting new authorization ticket\n" ); - steam_async *call = steam_new_async(); - call->data = NULL; + + vg_steam_async_call *call = vg_alloc_async_steam_api_call(); + call->userdata = NULL; call->p_handler = on_auth_ticket_recieved; - call->id = SteamAPI_ISteamUser_RequestEncryptedAppTicket( hSteamUser, - NULL, 0 ); + call->id = + SteamAPI_ISteamUser_RequestEncryptedAppTicket( hSteamUser, NULL, 0 ); } VG_STATIC void send_auth_ticket(void) diff --git a/player_common.c b/player_common.c index 669c20a..5c5dda1 100644 --- a/player_common.c +++ b/player_common.c @@ -237,6 +237,8 @@ VG_STATIC void player__cam_iterate( player_instance *player ) VG_STATIC void player_look( player_instance *player, v3f angles ) { + if( vg_ui.wants_mouse ) return; + angles[2] = 0.0f; v2f mouse_input; @@ -254,7 +256,6 @@ VG_STATIC void player_look( player_instance *player, v3f angles ) input_y *= -1.0f; angles[1] += input_y; - angles[1] = vg_clampf( angles[1], -VG_PIf*0.5f, VG_PIf*0.5f ); } diff --git a/player_render.c b/player_render.c index f34aa16..8f25215 100644 --- a/player_render.c +++ b/player_render.c @@ -61,6 +61,7 @@ VG_STATIC void player_model_load( struct player_model *mdl, const char *path ) mdl_close( &ctx ); } +/* TODO: allow error handling */ VG_STATIC void player_board_load( struct player_board *mdl, const char *path ) { vg_linear_clear( vg_mem.scratch ); @@ -305,6 +306,7 @@ VG_STATIC void render_board( camera *cam, world_instance *world, shader_model_board_view_uTexSceneDepth( 1 ); render_fb_inverse_ratio( gpipeline.fb_main, inverse ); + inverse[2] = main_camera.farz-main_camera.nearz; shader_model_board_view_uInverseRatioDepth( inverse ); diff --git a/render.h b/render.h index b617228..41aeef2 100644 --- a/render.h +++ b/render.h @@ -36,7 +36,8 @@ VG_STATIC struct pipeline{ framebuffer *fb_main, *fb_water_reflection, - *fb_water_beneath; + *fb_water_beneath, + *fb_workshop_preview; int ready; float view_render_scale, @@ -175,6 +176,27 @@ framebuffers[] = .attachment = GL_DEPTH_STENCIL_ATTACHMENT } } + }, + { + "workshop_preview", + .link = &gpipeline.fb_workshop_preview, + .resolution_div = 0, + .fixed_w = 504, .fixed_h = 336, + .attachments = + { + { + "colour", k_framebuffer_attachment_type_texture, + .internalformat = GL_RGB, + .format = GL_RGB, + .type = GL_UNSIGNED_BYTE, + .attachment = GL_COLOR_ATTACHMENT0 + }, + { + "depth_stencil", k_framebuffer_attachment_type_renderbuffer, + .internalformat = GL_DEPTH24_STENCIL8, + .attachment = GL_DEPTH_STENCIL_ATTACHMENT + } + } } }; diff --git a/server.c b/server.c index e3149c9..be3f2a9 100644 --- a/server.c +++ b/server.c @@ -397,8 +397,8 @@ int main( int argc, char *argv[] ) hSteamHTTP, k_EHTTPMethodGET, "https://www.harrygodden.com/hello.txt" ); - steam_async *call1 = steam_new_async(); - call1->data = NULL; + vg_steam_async_call *call1 = vg_alloc_async_steam_api_call(); + call1->userdata = NULL; call1->p_handler = recieve_http; SteamAPI_ISteamHTTP_SendHTTPRequest( hSteamHTTP, test_req, &call1->id ); #endif diff --git a/skaterift.c b/skaterift.c index c29d876..fedaa3d 100644 --- a/skaterift.c +++ b/skaterift.c @@ -11,9 +11,7 @@ * ============================================================================= */ -#include "skaterift_imgui_dev.c" - -#if 0 +#if 1 #define SR_NETWORKED #define VG_DEVWINDOW @@ -27,6 +25,7 @@ #include "player.h" #include "entity.c" +#include "workshop.c" VG_STATIC struct player_avatar localplayer_avatar; VG_STATIC struct player_model localplayer_models[3]; @@ -134,6 +133,7 @@ VG_STATIC void vg_load(void) vg_loader_step( player_init, NULL ); vg_loader_step( player_ragdoll_init, NULL ); + vg_loader_step( workshop_init, NULL ); vg_loader_step( skateshop_init, NULL ); /* ----------------- */ @@ -408,8 +408,6 @@ VG_STATIC void render_main_game(void) main_camera.fov = vg_lerpf( localplayer.cam.fov, menu_smooth_fov, menu_opacity ); - main_camera.fov = vg_lerpf( main_camera.fov, 90.0f, - global_skateshop.factive ); main_camera.nearz = 0.1f; main_camera.farz = 2100.0f; @@ -487,8 +485,14 @@ VG_STATIC void vg_gui(void) #endif world_instance *world = get_active_world(); menu_crap_ui(); + + workshop_form_gui(); render_view_framebuffer_ui(); } +#else + +#include "skaterift_imgui_dev.c" + #endif diff --git a/skaterift_imgui_dev.c b/skaterift_imgui_dev.c index 7684b50..383ff8c 100644 --- a/skaterift_imgui_dev.c +++ b/skaterift_imgui_dev.c @@ -22,9 +22,9 @@ #include "font.h" #include "player.h" #include "entity.c" +#include "workshop.c" static int skaterift_loaded = 0; -static GLuint tex_error; int main( int argc, char *argv[] ) { @@ -59,7 +59,6 @@ VG_STATIC void skaterift_load_post( void *data, u32 len ) VG_STATIC void vg_load(void) { - vg_tex2d_replace_with_error( &tex_error ); vg_bake_shaders(); vg_async_call( skaterift_load_post, NULL, 0 ); } @@ -93,98 +92,15 @@ VG_STATIC void vg_render(void) glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); /* Other shite */ - glDisable(GL_BLEND); - glDisable(GL_DEPTH_TEST); + glDisable( GL_BLEND ); + glDisable( GL_DEPTH_TEST ); vg_lines_drawall(); } -struct workshop_form{ - char title[80]; - char description[512]; -} -static form_test; - VG_STATIC void vg_gui(void) { if( !skaterift_loaded ) return; - ui_rect screen = { 0, 0, vg.window_x, vg.window_y }; - - ui_rect window = { 0, 0, 1000, 800 }; - ui_rect_center( screen, window ); - { - ui_fill( window, ui_colour( k_ui_bg+1 ) ); - ui_outline( window, 1, ui_colour( k_ui_bg+7 ) ); - - ui_rect title, panel; - ui_split_px( window, k_ui_axis_h, 28, 0, title, panel ); - ui_fill( title, ui_colour( k_ui_bg+7 ) ); - ui_text( title, "Workshop tool", 1, k_ui_align_middle_center, - ui_colourcont(k_ui_bg+7) ); - - ui_rect sidebar, content; - ui_split_ratio( panel, k_ui_axis_v, 0.3f, 1, sidebar, content ); - - /* entries panel */ - ui_fill( sidebar, ui_colour( k_ui_bg+2 ) ); - - ui_split_px( sidebar, k_ui_axis_h, 28, 0, title, sidebar ); - ui_text( title, "Your submissions", 1, k_ui_align_middle_center, 0 ); - - ui_rect controls; - ui_split_px( sidebar, k_ui_axis_h, 28, 0, controls, sidebar ); - ui_fill( controls, ui_colour( k_ui_bg+1 ) ); - ui_outline( controls, -1, ui_colour( k_ui_bg+4 ) ); - - ui_rect info; - ui_split_ratio( controls, k_ui_axis_v, 0.25f, 0, info, controls ); - ui_text( info, "page 0/2", 1, k_ui_align_middle_center, 0 ); - - ui_rect btn_left, btn_right; - ui_split_ratio( controls, k_ui_axis_v, 0.5f, 2, btn_left, btn_right ); - - if( ui_button_text( btn_left, "prev", 1, k_ui_bg+4 ) ){ - vg_info( "left\n" ); - } - - if( ui_button_text( btn_right, "next", 1, k_ui_bg+4 ) ){ - vg_info( "right\n" ); - } - - /* content page */ - ui_rect_pad( content, 8 ); - - ui_rect image_plane; - ui_split_px( content, k_ui_axis_h, 300, 0, image_plane, content ); - ui_fill( image_plane, ui_colour( k_ui_bg+0 ) ); - - ui_rect img_box; - ui_fit_item( image_plane, (ui_px[2]){ 3, 2 }, img_box ); - ui_image( img_box, tex_error ); - - ui_rect title_entry, null, label; - ui_split_px( content, k_ui_axis_h, 8, 0, null, content ); - ui_split_px( content, k_ui_axis_h, 28, 0, title_entry, content ); - - const char *str_title = "Title:", *str_desc = "Description:"; - ui_split_px( title_entry, k_ui_axis_v, - ui_text_line_width(str_title)+8, 0, label, title_entry ); - - ui_text( label, str_title, 1, k_ui_align_middle_left, 0 ); - ui_textbox( title_entry, form_test.title, - vg_list_size(form_test.title), 0 ); - - /* description box */ - ui_rect desc_entry; - ui_split_px( content, k_ui_axis_h, 8, 0, null, content ); - ui_split_px( content, k_ui_axis_h, 28*4, 0, desc_entry, content ); - ui_split_px( desc_entry, k_ui_axis_v, - ui_text_line_width(str_desc)+8, 0, label, desc_entry ); - ui_text( label, str_desc, 1, k_ui_align_middle_left, 0 ); - ui_textbox( desc_entry, form_test.description, - vg_list_size(form_test.description), - UI_TEXTBOX_MULTILINE|UI_TEXTBOX_WRAP ); - } - + workshop_form_gui(); ui_dev_colourview(); } diff --git a/steam.h b/steam.h index 52b7a4f..4ca106f 100644 --- a/steam.h +++ b/steam.h @@ -248,7 +248,6 @@ VG_STATIC int steam_init(void) * -------------------------------------------------------- */ hSteamUserStats = SteamAPI_SteamUserStats(); - steam_register_callback( k_iUserStatsReceived, steam_on_recieve_current_stats ); diff --git a/workshop.c b/workshop.c new file mode 100644 index 0000000..c0c1011 --- /dev/null +++ b/workshop.c @@ -0,0 +1,609 @@ +#ifndef WORKSHOP_C +#define WORKSHOP_C + +#define VG_GAME +#include "vg/vg.h" +#include "vg/vg_tex.h" +#include "ent_skateshop.h" + +#include "vg/vg_steam_ugc.h" + +struct workshop_form{ + char title[80]; + char description[512]; + char model_path[128]; + + struct player_board board_model; + + world_instance *view_world; + ent_swspreview *ptr_ent; + + v2f view_angles, + view_angles_begin; + v3f view_offset, + view_offset_begin; + + float view_dist; + int view_changed; + + enum workshop_form_status{ + k_workshop_form_hidden, + k_workshop_form_editing, + k_workshop_form_submitting, + k_workshop_form_failed + } + status; + const char *failure_reason; + PublishedFileId_t publishing_file_id; + + int img_w, img_h; + u8 *img_buffer; +} +static workshop_form; + +struct workshop_package_info { + int success; + char abs_preview_image[ 1024 ]; + char abs_content_folder[ 1024 ]; + char abs_content_file[ 1024 ]; +}; + +VG_STATIC void on_workshop_update_result( void *data, void *user ) +{ + vg_info( "Recieved workshop update result\n" ); + SubmitItemUpdateResult_t *result = data; + + if( result->m_bUserNeedsToAcceptWorkshopLegalAgreement ){ + vg_warn( "Workshop agreement currently not accepted\n" ); + } + + if( result->m_eResult == k_EResultOK ){ + vg_success( "Successfully uploaded workshop file\n" ); + } + else{ + vg_error( "Error with the submitted file (%d)\n", result->m_eResult ); + } +} + +VG_STATIC void workshop_form_async_package_complete( void *data, u32 size ) +{ + struct workshop_package_info *info = data; + if( !info->success ){ + workshop_form.status = k_workshop_form_failed; + workshop_form.failure_reason = "Packaging workshop folder failed."; + return; + } + + ISteamUGC *hSteamUGC = SteamAPI_SteamUGC(); + UGCUpdateHandle_t handle + = SteamAPI_ISteamUGC_StartItemUpdate( hSteamUGC, SKATERIFT_APPID, + workshop_form.publishing_file_id ); + + /* TODO: Handle failure cases for these */ + vg_info( "Setting title\n" ); + SteamAPI_ISteamUGC_SetItemTitle( hSteamUGC, handle, workshop_form.title ); + + vg_info( "Setting description\n" ); + SteamAPI_ISteamUGC_SetItemDescription( hSteamUGC, handle, + workshop_form.description ); + vg_info( "Setting preview image\n" ); + SteamAPI_ISteamUGC_SetItemPreview( hSteamUGC, + handle, info->abs_preview_image ); + vg_info( "Setting item content\n" ); + SteamAPI_ISteamUGC_SetItemContent( hSteamUGC, handle, + info->abs_content_folder ); + vg_info( "Setting visibility\n" ); + SteamAPI_ISteamUGC_SetItemVisibility( hSteamUGC, handle, + k_ERemoteStoragePublishedFileVisibilityPublic ); + + vg_info( "Submitting updates\n" ); + vg_steam_async_call *call = vg_alloc_async_steam_api_call(); + call->userdata = NULL; + call->p_handler = on_workshop_update_result; + call->id = SteamAPI_ISteamUGC_SubmitItemUpdate( hSteamUGC, handle, "" ); +} + +VG_STATIC void workshop_package_thread( void *data ) +{ + vg_info( "Packaging workshop content folder\n" ); + + vg_async_item *call = vg_async_alloc( sizeof(struct workshop_package_info) ); + struct workshop_package_info *info = call->payload; + + /* build content folder path */ + snprintf( info->abs_content_folder, 1024, "%smodels/boards/workshop/%lu", + vg.base_path, (u64)workshop_form.publishing_file_id ); + + /* build content file path */ + snprintf( info->abs_content_file, 1024, "%s/%s", + info->abs_content_folder, + vg_path_filename( workshop_form.model_path ) ); + + /* build workshop preview file path */ + snprintf( info->abs_preview_image, 1024, "%sworkshop_preview.jpg", + vg.base_path ); + + /* arange files */ + if( !vg_mkdir( info->abs_content_folder ) ){ + info->success = 0; + vg_async_dispatch( call, workshop_form_async_package_complete ); + return; + } + + vg_linear_clear( vg_mem.scratch ); + if( !vg_file_copy( workshop_form.model_path, info->abs_content_file, + vg_mem.scratch ) ){ + info->success = 0; + vg_async_dispatch( call, workshop_form_async_package_complete ); + return; + } + + info->success = 1; + vg_async_dispatch( call, workshop_form_async_package_complete ); +} + +VG_STATIC void on_workshop_createitem( void *data, void *user ) +{ + CreateItemResult_t *result = data; + + if( result->m_eResult == k_EResultOK ){ + vg_info( "Created workshop file with id: %lu\n", + result->m_nPublishedFileId ); + + + if( result->m_bUserNeedsToAcceptWorkshopLegalAgreement ){ + vg_warn( "Workshop agreement currently not accepted\n" ); + } + + workshop_form.publishing_file_id = result->m_nPublishedFileId; + vg_loader_start( workshop_package_thread, NULL ); + } + else{ + const char *error = NULL; + switch( result->m_eResult ){ + case k_EResultInsufficientPrivilege: + error = "Your account currently is restricted from uploading content " + "due to a hub ban, account lock, or community ban. You need to " + "contact Steam Support to resolve the issue.\n"; + break; + case k_EResultBanned: + error = "You do not have permission to upload content to this hub " + "because you have an active VAC or Game ban."; + break; + case k_EResultTimeout: + error = "Timeout: The operation took longer than expected, please try " + "again."; + break; + case k_EResultNotLoggedOn: + error = "You are currently not logged into Steam."; + break; + case k_EResultServiceUnavailable: + error = "The workshop server is having issues, please try again."; + break; + case k_EResultInvalidParam: + error = "One of the submission fields contains something not being " + "accepted by that field."; + break; + case k_EResultAccessDenied: + error = "There was a problem trying to save the title and description. " + "Access was denied."; + break; + case k_EResultLimitExceeded: + error = "You have exceeded your Steam Cloud quota. If you wish to " + "upload this file, you must remove some published items."; + break; + case k_EResultFileNotFound: + error = "The uploaded file could not be found."; + break; + case k_EResultDuplicateRequest: + error = "The file was already successfully uploaded."; + break; + case k_EResultDuplicateName: + error = "You already have a Steam Workshop item with that name."; + break; + case k_EResultServiceReadOnly: + error = "Due to a recent password or email change, you are not allowed " + "to upload new content. Usually this restriction will expire in" + " 5 days, but can last up to 30 days if the account has been " + "inactive recently."; + break; + default: workshop_form.failure_reason = "Unknown failure"; + } + + vg_error( "ISteamUGC_CreateItem() failed(%d): '%s' \n", + result->m_eResult, error ); + workshop_form.failure_reason = error; + workshop_form.status = k_workshop_form_failed; + } +} + +VG_STATIC void workshop_form_async_submit_complete( void *payload, u32 size ) +{ + vg_steam_async_call *call = vg_alloc_async_steam_api_call(); + call->userdata = NULL; + call->p_handler = on_workshop_createitem; + + ISteamUGC *hSteamUGC = SteamAPI_SteamUGC(); + call->id = SteamAPI_ISteamUGC_CreateItem( hSteamUGC, SKATERIFT_APPID, + k_EWorkshopFileTypeCommunity ); +} + +VG_STATIC void workshop_form_sync_download_image( void *payload, u32 size ) +{ + int w, h; + render_fb_get_current_res( gpipeline.fb_workshop_preview, &w, &h ); + vg_linear_clear( vg_mem.scratch ); + workshop_form.img_buffer = vg_linear_alloc( vg_mem.scratch, w*h*3 ); + + vg_info( "read framebuffer: glReadPixels( %dx%d )\n", w,h ); + + glBindFramebuffer( GL_READ_FRAMEBUFFER, gpipeline.fb_workshop_preview->fb ); + glReadBuffer( GL_COLOR_ATTACHMENT0 ); + glReadPixels( 0,0, w,h, GL_RGB, GL_UNSIGNED_BYTE, workshop_form.img_buffer ); + + workshop_form.img_w = w; + workshop_form.img_h = h; +} + +VG_STATIC void workshop_form_submit_thread( void *data ) +{ + vg_async_call( workshop_form_sync_download_image, NULL, 0 ); + vg_async_stall(); + + int w = workshop_form.img_w, + h = workshop_form.img_h; + + vg_info( "writing: workshop_preview.jpg (%dx%d @90%%)\n", w,h ); + stbi_flip_vertically_on_write(1); + stbi_write_jpg( "workshop_preview.jpg", w,h, 3, + workshop_form.img_buffer, 90 ); + + vg_async_call( workshop_form_async_submit_complete, NULL, 0 ); +} + +VG_STATIC void workshop_form_async_complete( void *payload, u32 size ) +{ + v2_zero( workshop_form.view_angles ); + v3_zero( workshop_form.view_offset ); + workshop_form.view_dist = 1.0f; + workshop_form.status = k_workshop_form_editing; + workshop_form.view_changed = 1; +} + +VG_STATIC void workshop_form_load_thread( void *data ) +{ + vg_info( "workshop_form_load_thread()\n" ); + player_board_load( &workshop_form.board_model, workshop_form.model_path ); + vg_success( "loaded\n" ); + + vg_async_call( workshop_form_async_complete, NULL, 0 ); +} + +VG_STATIC void workshop_start_submission( const char *path ) +{ + if( workshop_form.status != k_workshop_form_hidden ){ + vg_error( "Workshop form is already open\n" ); + return; + } + + workshop_form.view_world = get_active_world(); + + if( mdl_arrcount( &workshop_form.view_world->ent_swspreview ) ){ + workshop_form.ptr_ent = + mdl_arritm( &workshop_form.view_world->ent_swspreview, 0 ); + + vg_strncpy( path, workshop_form.model_path, 128, + k_strncpy_always_add_null ); + workshop_form.description[0] = '\0'; + workshop_form.title[0] = '\0'; + + vg_loader_start( workshop_form_load_thread, NULL ); + } + else{ + vg_error( "There is no ent_swspreview in the level. " + "Cannot publish here\n" ); + } +} + +VG_STATIC int workshop_submit_command( int argc, const char *argv[] ) +{ + if( argc == 1 ){ + workshop_start_submission( argv[0] ); + } + else{ + vg_error( "usage: workshop_submit \n" ); + } + return 0; +} + +VG_STATIC void workshop_init(void) +{ + vg_console_reg_cmd( "workshop_submit", workshop_submit_command, NULL ); +} + +VG_STATIC void workshop_form_gui(void) +{ + if( workshop_form.status == k_workshop_form_hidden ) return; + + ui_rect null; + ui_rect screen = { 0, 0, vg.window_x, vg.window_y }; + ui_rect window = { 0, 0, 1000, 700 }; + ui_rect_center( screen, window ); + vg_ui.wants_mouse = 1; + + ui_fill( window, ui_colour( k_ui_bg+1 ) ); + ui_outline( window, 1, ui_colour( k_ui_bg+7 ) ); + + ui_rect title, panel; + ui_split_px( window, k_ui_axis_h, 28, 0, title, panel ); + ui_fill( title, ui_colour( k_ui_bg+7 ) ); + ui_text( title, "Workshop tool", 1, k_ui_align_middle_center, + ui_colourcont(k_ui_bg+7) ); + + if( workshop_form.status == k_workshop_form_submitting ){ + ui_text( panel, "Submitting... status: ...\n", 1, + k_ui_align_middle_center, 0 ); + return; + } + + /* re draw board preview if need to */ + if( workshop_form.view_changed ){ + render_fb_bind( gpipeline.fb_workshop_preview, 0 ); + + glClearColor( 0.0f, 0.0f, 0.3f, 1.0f ); + glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); + glEnable( GL_DEPTH_TEST ); + glDisable( GL_BLEND ); + + ent_swspreview *swsprev = workshop_form.ptr_ent; + world_instance *world = workshop_form.view_world; + + ent_camera *ref = mdl_arritm( &world->ent_camera, + mdl_entity_id_id(swsprev->id_camera) ); + ent_marker *display = mdl_arritm( &world->ent_marker, + mdl_entity_id_id(swsprev->id_display) ), + *display1= mdl_arritm( &world->ent_marker, + mdl_entity_id_id(swsprev->id_display1) ); + + v3f baseco; + v3_add( display->transform.co, display1->transform.co, baseco ); + v3_muls( baseco, 0.5f, baseco ); + + camera cam; + v3f basevector; + v3_sub( display->transform.co, ref->transform.co, basevector ); + float dist = v3_length( basevector ); + + v3f baseangles; + player_vector_angles( baseangles, basevector, 1.0f, 0.0f ); + + v2_add( workshop_form.view_angles, baseangles, cam.angles ); + cam.angles[2] = 0.0f; + + float sX = sinf( cam.angles[0] ), + cX = cosf( cam.angles[0] ), + sY = sinf( cam.angles[1] ), + cY = cosf( cam.angles[1] ); + + v3f offset = { -sX * cY, sY, cX * cY }; + + v3_muladds( display->transform.co, offset, + dist*workshop_form.view_dist, cam.pos ); + + cam.pos[0] += -sX*workshop_form.view_offset[2]; + cam.pos[2] += cX*workshop_form.view_offset[2]; + cam.pos[0] += cX*workshop_form.view_offset[0]; + cam.pos[2] += sX*workshop_form.view_offset[0]; + cam.pos[1] += workshop_form.view_offset[1]; + + cam.nearz = 0.01f; + cam.farz = 100.0f; + cam.fov = ref->fov; + + camera_update_transform( &cam ); + camera_update_view( &cam ); + camera_update_projection( &cam ); + camera_finalize( &cam ); + + m4x3f mmdl, mmdl1; + mdl_transform_m4x3( &display->transform, mmdl ); + mdl_transform_m4x3( &display1->transform, mmdl1 ); + + /* force update this for nice shadows. its usually set in the world + * pre-render step, but that includes timer stuff + */ + struct player_board *board = &workshop_form.board_model; + struct ub_world_lighting *ubo = &world->ub_lighting; + v3f vp0, vp1; + v3_copy((v3f){0.0f,0.1f, board->truck_positions[0][2]}, vp0 ); + v3_copy((v3f){0.0f,0.1f, board->truck_positions[1][2]}, vp1 ); + m4x3_mulv( mmdl1, vp0, ubo->g_board_0 ); + m4x3_mulv( mmdl1, vp1, ubo->g_board_1 ); + glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting ); + glBufferSubData( GL_UNIFORM_BUFFER, 0, + sizeof(struct ub_world_lighting), &world->ub_lighting ); + + render_world( world, &cam, 1 ); + render_board( &cam, world, board, mmdl, k_board_shader_entity ); + render_board( &cam, world, board, mmdl1, k_board_shader_entity ); + + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + glViewport( 0,0, vg.window_x, vg.window_y ); + + workshop_form.view_changed = 0; + } + + struct workshop_form *form = &workshop_form; + + ui_rect sidebar, content; + ui_split_ratio( panel, k_ui_axis_v, 0.3f, 1, sidebar, content ); + + /* entries panel */ + ui_fill( sidebar, ui_colour( k_ui_bg+2 ) ); + + ui_split_px( sidebar, k_ui_axis_h, 28, 0, title, sidebar ); + ui_text( title, "Your submissions", 1, k_ui_align_middle_center, 0 ); + + ui_rect controls; + ui_split_px( sidebar, k_ui_axis_h, 28, 0, controls, sidebar ); + ui_fill( controls, ui_colour( k_ui_bg+1 ) ); + ui_outline( controls, -1, ui_colour( k_ui_bg+4 ) ); + + ui_rect info; + ui_split_ratio( controls, k_ui_axis_v, 0.25f, 0, info, controls ); + ui_text( info, "page 0/2", 1, k_ui_align_middle_center, 0 ); + + ui_rect btn_left, btn_right; + ui_split_ratio( controls, k_ui_axis_v, 0.5f, 2, btn_left, btn_right ); + + if( ui_button_text( btn_left, "prev", 1 ) ){ + vg_info( "left\n" ); + } + + if( ui_button_text( btn_right, "next", 1 ) ){ + vg_info( "right\n" ); + } + + /* content page */ + ui_rect_pad( content, 8 ); + + ui_rect image_plane; + ui_split_px( content, k_ui_axis_h, 300, 0, image_plane, content ); + ui_fill( image_plane, ui_colour( k_ui_bg+0 ) ); + + ui_rect img_box; + ui_fit_item( image_plane, (ui_px[2]){ 3, 2 }, img_box ); + ui_image( img_box, gpipeline.fb_workshop_preview->attachments[0].id ); + + { + int hover = ui_inside_rect( img_box, vg_ui.mouse ), + target = ui_inside_rect( img_box, vg_ui.mouse_click ); + + if( ui_click_down(UI_MOUSE_MIDDLE) && target ){ + v3_copy( workshop_form.view_offset, + workshop_form.view_offset_begin ); + } + else if( ui_click_down(UI_MOUSE_LEFT) && target ){ + v2_copy( workshop_form.view_angles, + workshop_form.view_angles_begin ); + } + + if( ui_clicking(UI_MOUSE_MIDDLE) && target ){ + v2f delta = { vg_ui.mouse[0]-vg_ui.mouse_click[0], + vg_ui.mouse[1]-vg_ui.mouse_click[1] }; + + float *begin = workshop_form.view_offset_begin, + *offset = workshop_form.view_offset; + offset[0] = vg_clampf( begin[0]-delta[0]*0.002f, -1.0f, 1.0f ); + offset[2] = vg_clampf( begin[2]-delta[1]*0.002f, -1.0f, 1.0f ); + workshop_form.view_changed = 1; + } + else if( ui_clicking(UI_MOUSE_LEFT) && target ){ + v2f delta = { vg_ui.mouse[0]-vg_ui.mouse_click[0], + vg_ui.mouse[1]-vg_ui.mouse_click[1] }; + + v2f angles; + v2_muladds( workshop_form.view_angles_begin, delta, 0.002f, angles); + + float limit = VG_PIf*0.2f; + + angles[0] = vg_clampf( angles[0], -limit, limit ); + angles[1] = vg_clampf( angles[1], -limit, limit ); + + v2_copy( angles, workshop_form.view_angles ); + workshop_form.view_changed = 1; + } + + if( !ui_clicking(UI_MOUSE_LEFT) && hover ){ + float zoom = workshop_form.view_dist; + zoom += vg.mouse_wheel[1] * -0.07f; + zoom = vg_clampf( zoom, 0.4f, 2.0f ); + + if( zoom != workshop_form.view_dist ){ + workshop_form.view_changed = 1; + workshop_form.view_dist = zoom; + } + } + } + + /* file path */ + ui_rect file_label; + ui_split_px( content, k_ui_axis_h, 8, 0, null, content ); + ui_split_px( content, k_ui_axis_h, 28, 0, file_label, content ); + ui_text( file_label, form->model_path, 1, k_ui_align_middle_center, + ui_colour( k_ui_fg+4 ) ); + + /* title box */ + ui_rect title_entry, label; + ui_split_px( content, k_ui_axis_h, 8, 0, null, content ); + ui_split_px( content, k_ui_axis_h, 28, 0, title_entry, content ); + + const char *str_title = "Title:", *str_desc = "Description:"; + ui_split_px( title_entry, k_ui_axis_v, + ui_text_line_width(str_title)+8, 0, label, title_entry ); + + ui_text( label, str_title, 1, k_ui_align_middle_left, 0 ); + ui_textbox( title_entry, form->title, vg_list_size(form->title), 0 ); + + /* description box */ + ui_rect desc_entry; + ui_split_px( content, k_ui_axis_h, 8, 0, null, content ); + ui_split_px( content, k_ui_axis_h, 28*4, 0, desc_entry, content ); + ui_split_px( desc_entry, k_ui_axis_v, + ui_text_line_width(str_desc)+8, 0, label, desc_entry ); + ui_text( label, str_desc, 1, k_ui_align_middle_left, 0 ); + ui_textbox( desc_entry, form->description, + vg_list_size(form->description), + UI_TEXTBOX_MULTILINE|UI_TEXTBOX_WRAP ); + + /* submissionable */ + ui_rect submission_row; + ui_split_px( content, k_ui_axis_h, 8, 0, null, content ); + ui_split_px( content, k_ui_axis_h, content[3]-32-8, 0, content, + submission_row ); + + ui_rect submission_center; + rect_copy( submission_row, submission_center ); + submission_center[2] = 256; + ui_rect_center( submission_row, submission_center ); + + ui_split_ratio( submission_center, k_ui_axis_v, 0.5f, 8, + btn_left, btn_right ); + + if( ui_button_text( btn_left, "Publish", 1 ) ){ + workshop_form.status = k_workshop_form_submitting; + vg_loader_start( workshop_form_submit_thread, NULL ); + } + if( ui_button_text( btn_right, "Cancel", 1 ) ){ + vg_info( "left\n" ); + } + + /* disclaimer */ + const char *disclaimer_text = + "By submitting this item, you agree to the workshop terms of service"; + + ui_rect disclaimer_row, inner, link; + ui_split_px( content, k_ui_axis_h, 8, 0, null, content ); + ui_split_px( content, k_ui_axis_h, content[3]-32, 0, content, + disclaimer_row ); + + ui_px btn_width = 32; + + rect_copy( disclaimer_row, inner ); + inner[2] = ui_text_line_width( disclaimer_text ) + btn_width+8; + + ui_rect_center( disclaimer_row, inner ); + ui_split_px( inner, k_ui_axis_v, inner[2]-btn_width, 0, label, btn_right); + ui_rect_pad( btn_right, 2 ); + + if( ui_button_text( btn_right, "\x91", 2 ) ){ + vg_info( "Open link\n" ); + } + + ui_text( label, disclaimer_text, 1, k_ui_align_middle_left, + ui_colour( k_ui_fg+4 ) ); +} + + + +#endif /* WORKSHOP_C */ diff --git a/world.h b/world.h index f065cb3..010364c 100644 --- a/world.h +++ b/world.h @@ -168,7 +168,8 @@ struct world_instance { ent_traffic, ent_skateshop, ent_marker, - ent_camera; + ent_camera, + ent_swspreview; ent_gate *rendering_gate; diff --git a/world_gen.h b/world_gen.h index 79bb754..c274eac 100644 --- a/world_gen.h +++ b/world_gen.h @@ -834,6 +834,7 @@ VG_STATIC void world_load( u32 index, const char *path ) mdl_load_array( meta, &world->ent_traffic, "ent_traffic", heap ); mdl_load_array( meta, &world->ent_marker, "ent_marker", heap ); mdl_load_array( meta, &world->ent_skateshop, "ent_skateshop", heap ); + mdl_load_array( meta, &world->ent_swspreview,"ent_swspreview", heap ); /* process resources from pack */ world_process_resources( world ); diff --git a/world_render.h b/world_render.h index 6a415e6..790f9a1 100644 --- a/world_render.h +++ b/world_render.h @@ -425,7 +425,7 @@ VG_STATIC void world_prerender( world_instance *world ) state->g_debug_indices = k_debug_light_indices; state->g_light_preview = k_light_preview; state->g_debug_complexity = k_debug_light_complexity; -state->g_time_of_day = vg_fractf( g_time ); + state->g_time_of_day = vg_fractf( g_time ); state->g_day_phase = cosf( state->g_time_of_day * VG_PIf * 2.0f ); state->g_sunset_phase= cosf( state->g_time_of_day * VG_PIf * 4.0f + VG_PIf );