--- /dev/null
+import bpy, math, gpu, blf
+from mathutils import *
+from gpu_extras.batch import batch_for_shader
+
+bl_info = {
+ "name":"Graphics Cropper",
+ "author": "Harry Godden (hgn)",
+ "version": (0,1),
+ "blender":(3,1,0),
+ "location":"",
+ "descriptin":"",
+ "warning":"",
+ "wiki_url":"",
+ "category":"",
+}
+
+# Clicky clicky GUI
+# ------------------------------------------------------------------------------
+
+cropper_view_draw_handler = None
+cropper_ui_draw_handler = None
+cropper_view_shader = gpu.shader.from_builtin('3D_SMOOTH_COLOR')
+
+def cropper_draw_ui():
+ mtx = bpy.context.region_data.perspective_matrix
+ w = bpy.context.region.width
+ h = bpy.context.region.height
+
+ for obj in bpy.context.scene.objects:
+ if obj.cropper_data.enabled and obj.visible_get():
+ x = obj.cropper_data.resolution[0]
+ y = obj.cropper_data.resolution[1]
+ c = Vector((1,1,0,1)) if obj.select_get() else Vector((0.6,0.4,0,1))
+ p0 = obj.matrix_world @ Vector((0,0,0))
+ p1 = obj.matrix_world @ Vector((x,0,0))
+ p2 = obj.matrix_world @ Vector((x,y,0))
+ p3 = obj.matrix_world @ Vector((0,y,0))
+
+ co = mtx @ Vector((p3[0],p3[1],p3[2],1.0))
+
+ co[0] /= co[3]
+ co[1] /= co[3]
+ co[0] *= 0.5
+ co[1] *= 0.5
+ co[0] += 0.5
+ co[1] += 0.5
+ co[0] *= w
+ co[1] *= h
+
+ blf.position(0,co[0],co[1]+8,0)
+ blf.size(0,20,48)
+ blf.color(0,c[0],c[1],c[2],c[3])
+ blf.draw(0,obj.cropper_data.filename)
+
+def cropper_draw():
+ global cropper_view_shader
+
+ verts = []
+ colours = []
+
+ for obj in bpy.context.scene.objects:
+ if obj.cropper_data.enabled and obj.visible_get():
+ x = obj.cropper_data.resolution[0]
+ y = obj.cropper_data.resolution[1]
+ c = Vector((1,1,0,1)) if obj.select_get() else Vector((0.6,0.4,0,1))
+ p0 = obj.matrix_world @ Vector((0,0,0))
+ p1 = obj.matrix_world @ Vector((x,0,0))
+ p2 = obj.matrix_world @ Vector((x,y,0))
+ p3 = obj.matrix_world @ Vector((0,y,0))
+
+ verts += [p0,p1,p1,p2,p2,p3,p3,p0]
+ colours += [c,c,c,c,c,c,c,c]
+
+ cropper_view_shader.bind()
+ gpu.state.depth_mask_set(False)
+ gpu.state.line_width_set(2.0)
+ gpu.state.face_culling_set('BACK')
+ gpu.state.depth_test_set('NONE')
+ gpu.state.blend_set('NONE')
+ lines = batch_for_shader( cropper_view_shader, 'LINES', \
+ { "pos":verts, "color":colours })
+ lines.draw( cropper_view_shader )
+
+# Blender
+# ------------------------------------------------------------------------------
+
+def cropper_render_item(obj,context):
+ cam = context.scene.camera
+ original_pos_x = cam.location[0]
+ original_pos_y = cam.location[1]
+ original_res_x = context.scene.render.resolution_x
+ original_res_y = context.scene.render.resolution_y
+ original_file = context.scene.render.filepath
+ original_scale = cam.data.ortho_scale
+
+ x = obj.cropper_data.resolution[0]
+ y = obj.cropper_data.resolution[1]
+ fmt = context.scene.render.image_settings.file_format.lower()
+ fn = F"{obj.cropper_data.filename}.{fmt}"
+
+ p0 = obj.matrix_world @ Vector((0,0,0))
+ p1 = obj.matrix_world @ Vector((x,0,0))
+ p2 = obj.matrix_world @ Vector((x,y,0))
+ p3 = obj.matrix_world @ Vector((0,y,0))
+ c = obj.matrix_world @ Vector((x*0.5,y*0.5,0))
+
+ if x > y: s = p2[0]-p0[0]
+ else: s = p2[1]-p0[1]
+
+ cam.location[0] = c[0]
+ cam.location[1] = c[1]
+
+ cam.data.ortho_scale = s
+ context.scene.render.resolution_x = x
+ context.scene.render.resolution_y = y
+ context.scene.render.filepath = original_file + fn
+ print( F"render to: {context.scene.render.filepath}" )
+ bpy.ops.render.render(write_still=True)
+
+ # Reset
+ context.scene.render.resolution_x = original_res_x
+ context.scene.render.resolution_y = original_res_y
+ context.scene.render.filepath = original_file
+
+ cam.data.ortho_scale = original_scale
+ cam.location[0] = original_pos_x
+ cam.location[1] = original_pos_y
+
+class CROPPER_RENDER_ALL(bpy.types.Operator):
+ bl_idname="cropper.render_all"
+ bl_label="Render all"
+ def execute(_,context):
+ for obj in context.scene.objects:
+ if obj.cropper_data.enabled and obj.visible_get():
+ cropper_render_item(obj,context)
+
+ return {'FINISHED'}
+
+class CROPPER_RENDER(bpy.types.Operator):
+ bl_idname="cropper.render"
+ bl_label="Render"
+ def execute(_,context):
+ obj = context.active_object
+ if obj != None and obj.cropper_data.enabled:
+ cropper_render_item(obj,context)
+
+ return {'FINISHED'}
+
+class CROPPER_OBJ_SETTINGS(bpy.types.PropertyGroup):
+ enabled: bpy.props.BoolProperty( name="enabled" )
+ filename: bpy.props.StringProperty( name="filename" )
+ resolution: bpy.props.IntVectorProperty( name="resolution",size=2 )
+
+class CROPPER_OBJ_PANEL(bpy.types.Panel):
+ bl_label="Cropper Settings"
+ bl_idname="SCENE_PT_cropper"
+ bl_space_type='PROPERTIES'
+ bl_region_type='WINDOW'
+ bl_context="object"
+
+ def draw(_,context):
+ active_object = context.active_object
+ if active_object == None: return
+ _.layout.prop( active_object.cropper_data, "enabled" )
+
+ box = _.layout.box()
+ if not active_object.cropper_data.enabled:
+ box.enabled = False
+
+ box.prop( active_object.cropper_data, "filename" )
+ box.prop( active_object.cropper_data, "resolution" )
+ box.operator( "cropper.render" )
+ _.layout.operator( "cropper.render_all" )
+
+classes = [ CROPPER_OBJ_SETTINGS, CROPPER_OBJ_PANEL, \
+ CROPPER_RENDER, CROPPER_RENDER_ALL ]
+
+def register():
+ global cropper_view_draw_handler, cropper_ui_draw_handler
+
+ for c in classes:
+ bpy.utils.register_class(c)
+
+ bpy.types.Object.cropper_data = \
+ bpy.props.PointerProperty(type=CROPPER_OBJ_SETTINGS)
+
+ cropper_view_draw_handler = bpy.types.SpaceView3D.draw_handler_add(\
+ cropper_draw,(),'WINDOW','POST_VIEW')
+ cropper_ui_draw_handler = bpy.types.SpaceView3D.draw_handler_add(\
+ cropper_draw_ui,(),'WINDOW','POST_PIXEL')
+
+def unregister():
+ global cropper_view_draw_handler, cropper_ui_draw_handler
+
+ for c in classes:
+ bpy.utils.unregister_class(c)
+
+ bpy.types.SpaceView3D.draw_handler_remove(cropper_view_draw_handler,'WINDOW')
+ bpy.types.SpaceView3D.draw_handler_remove(cropper_ui_draw_handler,'WINDOW')
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved
+
+# Compiler Presets
+# ==============================================================================
+
+_linux_compiler="gcc -std=c99 -D_REENTRANT"
+_linux_linkgraphics="-lGL -lglfw3 -lX11 -lXxf86vm -lXrandr -lm -pthread -lXi -ldl"
+_linux_asan="-fsanitize=address"
+_linux_linksteam="-lsteam_api"
+_linux_folder="build.linux"
+_linux_server_folder="build.linux_server"
+
+_windows_compiler="i686-w64-mingw32-gcc"
+_windows_linkgraphics="-lglfw3dll -lopengl32 -lm -mwindows"
+_windows_asan=""
+_windows_linksteam="vg/dep/steam/steam_api.dll"
+_windows_folder="build.win32"
+
+_options_debugmode="-O0 -ggdb3 -fno-omit-frame-pointer"
+_options_release="-O3 -DVG_RELEASE"
+
+# Compiler lines
+# ==============================================================================
+
+_warnings="-Wall -Wno-unused-function -Wno-unused-variable"
+_include="-I. -I./vg/dep -I./vg/src"
+_library="-L. -L./vg/dep/glfw -L./vg/dep/steam"
+_epilogue="-Wl,-rpath=./"
+_ext=""
+
+# Compile scripts
+# ==============================================================================
+
+release(){
+ _linux_options=$_options_release
+ _windows_options=$_options_release
+}
+
+debug(){
+ _linux_options="$_linux_asan $_options_debugmode"
+ _windows_options="$_windows_asan $_options_debugmode"
+}
+debug
+
+compile_miniaudio(){
+
+ temp_options=$_options
+ _options="-O3"
+
+ _link="-lm"
+ _folder="."
+ _src="-c vg/dep/dr_soft/miniaudio_impl.c"
+ _dst="vg/dep/dr_soft/miniaudio_$1"
+ _ext=".o"
+ compile_x
+
+ _options=$temp_options
+}
+
+game() {
+ _compiler=$_linux_compiler
+ _options=$_linux_options
+
+ compile_miniaudio linux
+
+ # Game tools
+ _folder="$_linux_folder"
+ _ext=""
+ vg_compile_tools
+
+ # Main build
+ _link="$_linux_linkgraphics $_linux_linksteam"
+ _src="main.c vg/dep/glad/glad.c vg/dep/dr_soft/miniaudio_linux.o"
+ _dst="skaterift"
+ compile_x
+}
+
+game_windows() {
+ _compiler=$_windows_compiler
+ _options=$_windows_options
+
+ compile_miniaudio windows
+
+ # Game tools
+ _folder="$_windows_folder"
+ _ext=".exe"
+ vg_compile_tools
+
+ # Main build
+ _link="$_windows_linkgraphics $_windows_linksteam"
+ _src="main.c vg/dep/glad/glad.c vg/dep/dr_soft/miniaudio_windows.o"
+ _dst="skaterift"
+ compile_x
+}
+
+server() {
+ _compiler=$_linux_compiler
+ _options=$_linux_options
+ _link="-lm $_linux_linksteam"
+ _folder="$_linux_server_folder"
+ _src="server.c"
+ _dst="skaterift_server"
+ _ext=""
+
+ compile_x
+}
+
+all() {
+ tools
+ game
+ server
+}
+
+distribution(){
+ release
+ tools
+ game
+ game_windows
+ server
+}
+
+source vg/vg_build.sh
if( sv_scene == 0 )
{
- character_load( &player.mdl, "ch_outlaw" );
+ character_load( &player.mdl, "ch_default" );
character_init_ragdoll( &player.mdl );
world_load();
gpipeline.fov = freecam? 60.0f: 135.0f; /* 120 */
m4x4_projection( vg_pv, gpipeline.fov,
(float)vg_window_x / (float)vg_window_y,
- 0.1f, 2100.0f );
+ 0.02f, 2100.0f );
m4x4_mul( vg_pv, world_4x4, vg_pv );
--- /dev/null
+#ifndef NETWORK_H
+#define NETWORK_H
+
+#include "vg/vg_stdint.h"
+
+
+
+#endif /* NETWORK_H */
--- /dev/null
+#ifndef NETWORK_MSG_H
+#define NETWORK_MSG_H
+
+#include "vg/vg_stdint.h"
+
+#pragma pack(push,1)
+
+typedef struct netmsg_blank netmsg_blank;
+struct netmsg_blank
+{
+ u32 inetmsg_id;
+};
+enum{ k_inetmsg_blank = 0 };
+
+typedef struct netmsg_scores_request netmsg_scores_request;
+struct netmsg_scores_request
+{
+ u32 inetmsg_id;
+};
+enum{ k_inetmsg_scores_request = 1 };
+
+typedef struct netmsg_scores_info netmsg_scores_info;
+struct netmsg_scores_info
+{
+ u32 inetmsg_id;
+
+ u32 record_count;
+ struct netmsg_score_record
+ {
+ u32 trackid;
+
+ struct netmsg_score_entry
+ {
+ u64 steamid64;
+ u16 points, time;
+ }
+ top10[10];
+ }
+ scores[];
+};
+enum{ k_inetmsg_scores_info = 2 };
+
+#pragma pack(pop)
+#endif /* NETWORK_MSG_H */
player.in_air = 1;
float pstep = ktimestep*10.0f;
-
- float best_velocity_mod = 0.0f,
- best_velocity_delta = -9999.9f;
-
+ float best_velocity_delta = -9999.9f;
float k_bias = 0.96f;
v3f axis;
if( (land_delta < 0.0f) && (land_delta > best_velocity_delta) )
{
best_velocity_delta = land_delta;
- best_velocity_mod = vmod;
v3_copy( contact.pos, player.land_target );
pa[0] = wg->region[0][0] + (float)wg->cell_id[0] *k_gridscale;
pa[1] = (wg->region[0][1] + wg->region[1][1]) * 0.5f + k_gridscale;
pa[2] = wg->region[0][2] + (float)wg->cell_id[1] *k_gridscale;
+#if 0
pb[0] = pa[0];
pb[1] = pa[1];
pb[2] = pa[2] + k_gridscale;
pd[0] = pa[0] + k_gridscale;
pd[1] = pa[1];
pd[2] = pa[2];
-#if 0
/* if you want to draw the current cell */
vg_line( pa, pb, 0xff00ffff );
vg_line( pb, pc, 0xff00ffff );
v3_sub( next->pos, node->pos, dir );
v3_normalize( dir );
+#if 0
// Perpendicular vector
norm[0] = -dir[2];
norm[1] = 0.f;
norm[2] = dir[0];
+#endif
v3_muls( node->side, k_road_width, p2 );
v3_add( p2, node->pos, p2 );
--- /dev/null
+// Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
+
+/*
+ * This server application requires steamclient.so to be present in the
+ * executable directory. This is not provided by vg system, it must be
+ * downloaded via steamcmd. It will likely be somewhere in /usr/.steam/ ...
+ */
+
+#define _DEFAULT_SOURCE
+#include <unistd.h>
+#include <signal.h>
+
+volatile sig_atomic_t sig_stop;
+
+void inthandler( int signum )
+{
+ sig_stop = 1;
+}
+
+#define VG_SERVER
+#include "vg/vg.h"
+#include "vg/vg_steam.h"
+#include "vg/vg_steam_networking.h"
+#include "vg/vg_steam_http.h"
+#include "vg/vg_steam_auth.h"
+#include "network_msg.h"
+
+void *hSteamHTTP,
+ *hSteamNetworkingSockets;
+
+u8 steam_symetric_key[ k_nSteamEncryptedAppTicketSymmetricKeyLen ];
+HSteamNetPollGroup client_pollgroup;
+
+static void recieve_http( void *callresult, void *context )
+{
+ HTTPRequestCompleted_t *result = callresult;
+
+ HTTPRequestHandle request = result->m_hRequest;
+ u32 size = 0;
+
+ SteamAPI_ISteamHTTP_GetHTTPResponseBodySize( hSteamHTTP, request, &size );
+
+ u8 *buffer = malloc( size );
+ SteamAPI_ISteamHTTP_GetHTTPResponseBodyData(
+ hSteamHTTP, request, buffer, size );
+
+ buffer[size-1] = '\0';
+ vg_info( "%s\n", (char *)buffer );
+
+ free( buffer );
+ SteamAPI_ISteamHTTP_ReleaseHTTPRequest( hSteamHTTP, result->m_hRequest );
+}
+
+static void new_client_connecting( HSteamNetConnection client )
+{
+ EResult accept_status = SteamAPI_ISteamNetworkingSockets_AcceptConnection(
+ hSteamNetworkingSockets, client );
+
+ if( accept_status == k_EResultOK )
+ {
+ vg_success( "Accepted client (id: %u)\n", client );
+ SteamAPI_ISteamNetworkingSockets_SetConnectionPollGroup(
+ hSteamNetworkingSockets,
+ client, client_pollgroup );
+ }
+ else
+ {
+ vg_warn( "Error accepting client (id: %u)\n", client );
+ }
+}
+
+static void handle_steam_callback( CallbackMsg_t *msg )
+{
+ if( msg->m_iCallback == k_iSteamNetConnectionStatusChangedCallBack )
+ {
+ SteamNetConnectionStatusChangedCallback_t *info = (void *)msg->m_pubParam;
+ vg_info( " Connection status changed for %lu\n", info->m_hConn );
+
+ vg_info( " %s -> %s\n",
+ string_ESteamNetworkingConnectionState(info->m_info.m_eState),
+ string_ESteamNetworkingConnectionState(info->m_eOldState) );
+
+ if( info->m_info.m_eState==k_ESteamNetworkingConnectionState_Connecting )
+ {
+ new_client_connecting( info->m_hConn );
+ }
+ }
+ else if( msg->m_iCallback == k_iSteamNetAuthenticationStatus )
+ {
+ SteamNetAuthenticationStatus_t *info = (void *)msg->m_pubParam;
+ vg_info( " Authentication availibility: %s\n",
+ string_ESteamNetworkingAvailability(info->m_eAvail) );
+ vg_info( " %s\n", info->m_debugMsg );
+ }
+}
+
+static void poll_connections(void)
+{
+ SteamNetworkingMessage_t *messages[32];
+ int len;
+
+ while(1)
+ {
+ len = SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnPollGroup(
+ hSteamNetworkingSockets,
+ client_pollgroup, messages, vg_list_size(messages) );
+
+ if( len <= 0 )
+ return;
+
+ for( int i=0; i<len; i++ )
+ {
+ SteamNetworkingMessage_t *msg = messages[i];
+
+ if( msg->m_cbSize < sizeof(netmsg_blank) )
+ {
+ vg_warn( "Discarding message (too small: %d)\n",
+ msg->m_cbSize );
+ continue;
+ }
+
+ netmsg_blank *tmp = msg->m_pData;
+ if( tmp->inetmsg_id == k_inetmsg_scores_request )
+ {
+ vg_log( "Recieved score request, sending records. (id: %u)\n",
+ msg->m_conn );
+
+ /* Send back current scores */
+ u32 data_size = sizeof(netmsg_scores_info) +
+ 0*sizeof(struct netmsg_score_record);
+ netmsg_scores_info *return_info = malloc( data_size );
+
+ return_info->inetmsg_id = k_inetmsg_scores_info;
+ return_info->record_count = 0;
+
+ SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
+ hSteamNetworkingSockets, msg->m_conn,
+ return_info, data_size,
+ k_nSteamNetworkingSend_Reliable, NULL );
+ }
+
+ SteamAPI_SteamNetworkingMessage_t_Release( msg );
+ }
+ }
+}
+
+int main( int argc, char *argv[] )
+{
+ steamworks_ensure_txt( "2103940" );
+
+ signal( SIGINT, inthandler );
+
+ if( !vg_load_steam_symetric_key( "application_key", steam_symetric_key ) )
+ return 0;
+
+ if( !SteamGameServer_Init( 0, 27400, 27401, eServerModeAuthentication,
+ "1.0.0.0" ) )
+ {
+ vg_error( "SteamGameServer_Init failed\n" );
+ return 0;
+ }
+
+ void *hSteamGameServer = SteamAPI_SteamGameServer();
+ SteamAPI_ISteamGameServer_LogOnAnonymous( hSteamGameServer );
+
+ SteamAPI_ManualDispatch_Init();
+ HSteamPipe hsteampipe = SteamGameServer_GetHSteamPipe();
+
+ //hSteamHTTP = SteamAPI_SteamGameServerHTTP();
+ hSteamNetworkingSockets =
+ SteamAPI_SteamGameServerNetworkingSockets_SteamAPI();
+
+ /*
+ * Server code
+ */
+
+ vg_success( "Steamworks API running\n" );
+ steamworks_event_loop( hsteampipe, handle_steam_callback );
+
+ /*
+ * Create a listener
+ */
+
+ HSteamListenSocket listener;
+ SteamNetworkingIPAddr localAddr;
+ SteamAPI_SteamNetworkingIPAddr_Clear( &localAddr );
+ localAddr.m_port = 27402;
+
+ listener = SteamAPI_ISteamNetworkingSockets_CreateListenSocketIP(
+ hSteamNetworkingSockets, &localAddr, 0, NULL );
+ client_pollgroup = SteamAPI_ISteamNetworkingSockets_CreatePollGroup(
+ hSteamNetworkingSockets );
+
+#if 0
+ HTTPRequestHandle test_req = SteamAPI_ISteamHTTP_CreateHTTPRequest(
+ hSteamHTTP, k_EHTTPMethodGET,
+ "https://www.harrygodden.com/hello.txt" );
+
+ steam_async *call1 = steam_new_async();
+ call1->data = NULL;
+ call1->p_handler = recieve_http;
+ SteamAPI_ISteamHTTP_SendHTTPRequest( hSteamHTTP, test_req, &call1->id );
+#endif
+
+ while( !sig_stop )
+ {
+ steamworks_event_loop( hsteampipe, handle_steam_callback );
+ poll_connections();
+
+ usleep(100000);
+ }
+
+ SteamAPI_ISteamNetworkingSockets_DestroyPollGroup( hSteamNetworkingSockets,
+ client_pollgroup );
+ SteamAPI_ISteamNetworkingSockets_CloseListenSocket(
+ hSteamNetworkingSockets, listener );
+
+ vg_info( "Shutting down\n..." );
+ SteamGameServer_Shutdown();
+
+ return 0;
+}