--- /dev/null
+mkdir -p ext
+echo gcc -ggdb3 -Wall -fsanitize=address -rdynamic csRadar.c -o csRadar -lm -ldl
+gcc -ggdb3 -Wall -fsanitize=address -rdynamic csRadar.c -o csRadar -lm -ldl
+
+echo -ggdb3 -Wall -fsanitize=address -fpic -shared -o ext/csRadarFree.so ext_csr_free.c -lm
+gcc -ggdb3 -Wall -fsanitize=address -fpic -shared -o ext/csRadarFree.so ext_csr_free.c -lm
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-#include <time.h>
-#include <stdarg.h>
-
-
-#include <unistd.h>
-
-// CSR lib
-#include "csrLog.h"
-#include "csrOpt.h"
-#include "csrTypes.h"
-#include "csrMath.h"
-#include "csrMem.h"
-#include "csrIO.h"
-#include "csrComb.h"
-
-// Valve formats
-#include "vdf.h"
-#include "vpk.h"
-#include "vfilesys.h"
-
-#include "vmdl.h"
-#include "vmf.h"
-
-// CSR main
-#include "csr32f.h"
-#include "csrDraw.h"
-
-#define CSR_VERSION "0.0.1"
+#define VALVE_IMPLEMENTATION
+#define CSR_EXECUTABLE
+#include "csRadar.h"
// gcc -Wall -fsanitize=address csRadar.c -o csRadar -lm
int main( int argc, char *argv[] )
{
- char *arg;
- char *strings[ 20 ];
- int num_strings = 0;
-
- float padding = 128.f;
- u32 resolution = 1024;
- int write_txt = 1;
- char output_path[ 512 ]; // Full path eg. /home/harry/my_map.vmf
- char vmf_name[ 128 ]; // Just the base name eg. my_map
+ csr_api api =
+ {
+ .padding = 128.f,
+ .resolution = 1024,
+ .write_txt = 1,
+ .api_version = csr_api_version,
+ .sampling_mode = k_EMSAA_RGSS
+ };
+
int output_set = 0;
- EMSAA sampling_mode = k_EMSAA_RGSS;
+ char *extension = NULL;
+ char *arg;
while( csr_argp( argc, argv ) )
{
if( (arg = csr_arg()) )
{
- if( num_strings == 20 )
+ if( api.num_strings == 20 )
{
log_error( "Too many arguments! Max 20\n" );
goto IL_CSR_EXIT;
}
- strings[ num_strings ++ ] = arg;
+ api.strings[ api.num_strings ++ ] = arg;
}
if( (arg = csr_opt_arg( 'o' )) )
{
- strcpy( output_path, arg );
- csr_path_winunix( output_path );
+ strcpy( api.output_path, arg );
+ csr_path_winunix( api.output_path );
output_set = 1;
}
if( (arg = csr_opt_arg( 'r' )) )
{
- resolution = atoi( arg );
+ api.resolution = atoi( arg );
}
if( (arg = csr_long_opt_arg( "padding" )) )
{
- padding = atof( arg );
+ api.padding = atof( arg );
}
if( (arg = csr_long_opt_arg( "multi-sample" )) )
{
if( !strcmp( arg, "none" ))
{
- sampling_mode = k_EMSAA_none;
+ api.sampling_mode = k_EMSAA_none;
}
else if( !strcmp( arg, "rgss" ))
{
- sampling_mode = k_EMSAA_RGSS;
+ api.sampling_mode = k_EMSAA_RGSS;
}
else if( !strcmp( arg, "2x" ))
{
- sampling_mode = k_EMSAA_2x2;
+ api.sampling_mode = k_EMSAA_2x2;
}
else if( !strcmp( arg, "8r" ))
{
- sampling_mode = k_EMSAA_8R;
+ api.sampling_mode = k_EMSAA_8R;
}
else
{
goto IL_CSR_EXIT;
}
}
+
+ if( (arg = csr_long_opt_arg( "extension" )) )
+ {
+ extension = arg;
+ }
if( csr_opt( 'v' ) || csr_long_opt( "version" ) )
{
- printf( "csRadar version: " CSR_VERSION "\n" );
+ printf( "csRadar build: %u, api_version: %u\n", csr_build, csr_api_version );
goto IL_CSR_EXIT;
}
" -o <output> Specify output name/path\n"
" --padding=128 When cropping radar, add padding units to border\n"
//" --standard-layers Use standard TAR layers/groups\n"
+ " --write-normals Enable normals as an output stream\n"
+ " --write-origins Enable entity origins as an output stream\n"
" --no-txt Don't create matching radar txt\n"
" --multi-sample=RGSS [ none, 2x, rgss, 8r ]\n"
" --extension=TAR Use an extension binary instead\n"
}
}
- if( num_strings )
+ if( api.num_strings )
{
- vmf_map *map = vmf_init( strings[0] );
-
- if( map )
+ // Path handling
+ if( !output_set )
{
- // Path handling
- if( !output_set )
- {
- strcpy( output_path, strings[0] );
- csr_stripext( output_path );
- }
-
- char *base_name;
- if( !(base_name = csr_findext( output_path, '/' ) ))
- {
- base_name = output_path;
- }
-
- strcpy( vmf_name, base_name );
-
- log_info( "output_path: '%s'\n", output_path );
- log_info( "vmf_name: '%s'\n", vmf_name );
-
- // Main
- csr_target target;
-
- csr_create_target( &target, resolution, resolution, sampling_mode );
- csr_rt_clear( &target );
-
- csr_use_program( &target, frag_gbuffer );
-
- // Compute bounds
- csr_filter filter =
- {
- .classname = NULL,
- .visgroup = NULL,
- .compute_bounds_only = 1
- };
+ strcpy( api.output_path, api.strings[0] );
+ csr_stripext( api.output_path );
+ }
+
+ char *base_name;
+ if( !(base_name = csr_findext( api.output_path, '/' ) ))
+ {
+ base_name = api.output_path;
+ }
+
+ strcpy( api.vmf_name, base_name );
+
+ log_info( "output_path: '%s'\n", api.output_path );
+ log_info( "vmf_name: '%s'\n", api.vmf_name );
+
+ api.map = vmf_init( api.strings[0] );
+ if( api.map )
+ {
+ if( !extension )
+ extension = "csRadarFree";
+
+ csr_so ext = csr_libopen( extension );
- // One pass for fitting, second pass for drawing
- for( int i = 0; i < 2; i ++ )
+ if( ext )
{
- if( num_strings == 1 )
- {
- // Draw everything
- draw_vmf_group( &target, map, map->root, &filter, NULL, NULL );
- csr_rt_save_buffers( &target, output_path, "all" );
- }
- else
- {
- // Draw groups
- for( int i = 1; i < num_strings; i ++ )
- {
- filter.visgroup = strings[ i ];
-
- draw_vmf_group( &target, map, map->root, &filter, NULL, NULL );
- csr_rt_save_buffers( &target, output_path, strings[i] );
-
- csr_rt_clear( &target );
- }
- }
+ void (*csr_ext_main)(csr_api *);
+ void (*csr_ext_exit)(csr_api *);
- if( i == 0 )
+ csr_ext_main = csr_get_proc( ext, "csr_ext_main" );
+ csr_ext_exit = csr_get_proc( ext, "csr_ext_exit" );
+
+ if( csr_ext_main && csr_ext_exit )
{
- filter.compute_bounds_only = 0;
- csr_auto_fit( &target, padding );
- vmf_load_models( map );
+ csr_ext_main( &api );
+
+ // Do other
+
+ csr_ext_exit( &api );
}
else
{
- float prog = 0.f;
- csr_prog_begin( "Rendering" );
- for(;;)
- {
- if( prog > 1.f )
- break;
-
- csr_prog_update( prog );
- usleep( 20000 );
-
- prog += 0.01f;
- }
-
- csr_prog_end();
+ csr_liberr();
}
+
+ csr_libclose( ext );
}
-
- if( write_txt )
+ else
{
- char txt_path[ 512 ];
-
- strcpy( txt_path, output_path );
- strcat( txt_path, ".txt" );
-
- csr_write_txt( txt_path, vmf_name, &target );
+ csr_liberr();
}
- csr_rt_free( &target );
- vmf_free( map );
+ vmf_free( api.map );
}
else
{
--- /dev/null
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#include <stdarg.h>
+
+// CSR lib
+#include "csrLog.h" // Y
+#include "csrOpt.h" // Y
+#include "csrTypes.h" // Y
+#include "csrMath.h" // Y
+#include "csrMem.h" // Y
+#include "csrIO.h" // Y
+#include "csrComb.h" // Y
+#include "csrPlatform.h" // Y
+
+// Valve formats
+#include "vdf.h" // Y
+#include "vpk.h" // Y
+#include "vfilesys.h" // Y
+
+#include "vmdl.h" // Y
+#include "vmf.h" // Y
+
+// Drawing
+#ifdef CSR_EXECUTABLE
+ #include "csr32f.h"
+//#include "csrTga.h"
+#endif
+
+#include "csrDraw.h" // Y
+
+static const u32 csr_build = 3;
+static const u32 csr_api_version = 1;
+
+typedef struct csr_api csr_api;
+struct csr_api
+{
+ // Floating arguments from main's argv
+ char *strings[ 20 ];
+ int num_strings;
+
+ float padding;
+ u32 resolution;
+ int write_txt;
+ char output_path[ 512 ]; // Full path eg. /home/harry/my_map.vmf
+ char vmf_name[ 128 ]; // Just the base name eg. my_map
+ EMSAA sampling_mode;
+
+ // Main API interface
+ vmf_map *map;
+ csr_target target;
+
+ u32 api_version;
+};
+
+#ifndef CSR_EXECUTABLE
+static int csr_init( csr_api *api )
+{
+ if( api->api_version > csr_api_version )
+ {
+ log_warn( "API Version out of date. Host: %u, Plugin: %u\n", api->api_version, csr_api_version );
+ return 0;
+ }
+
+ return 1;
+}
+#endif
+// Copyright (C) 2021 Harry Godden (hgn)
+
+// API
+//=======================================================================================================================
+
+// Algorithm 1: Generate non-repeating combinations of size M in set of N
+// Usage:
+// int p[3];
+// hgn_comb_init( 3, p );
+//
+// do
+// {
+// something with p[0], p[1], p[2]
+// }
+// while( hgn_comb( 3, 5, p ) );
+//
+// Output of p each iteration:
+// 0 1 2
+// 0 1 3
+// 0 1 4
+// 0 2 3
+// 0 2 4
+// 0 3 4
+// 1 2 3
+// 1 2 4
+// 1 3 4
+// 2 3 4
+
+void csr_comb_init( int const M, int p[] );
+int csr_comb( int M, int N, int p[] );
+
+// Implementation
+//=======================================================================================================================
+
+#ifdef CSR_EXECUTABLE
+
void csr_comb_init( int const M, int p[] )
{
for( int i = 0; i < M; i ++ )
}
return 0;
}
+
+#endif
-typedef struct csr_frag csr_frag;
+// Copyright (C) 2021 Harry Godden (hgn)
+
+// Extremely simple software renderer. Only supports orthographic
+//=======================================================================================================================
+
typedef struct csr_target csr_target;
typedef struct csr_filter csr_filter;
+typedef struct csr_shader csr_shader;
typedef enum EMSAA EMSAA;
-typedef void (* csr_frag_shader)( v4f, vmf_vert[3], float, float, float );
+typedef void (* csr_frag_program)( void *, vmf_vert[3], float, float, float );
+typedef void (* csr_frag_clear)( void * );
+
+// API
+//=======================================================================================================================
+
+// Create a render target. Resolution, msaa, and shader must be known at this point!
+void csr_create_target( csr_target *rt, u32 x, u32 y, EMSAA aa, csr_shader *shader );
+void csr_rt_clear( csr_target *rt );
+void csr_rt_free( csr_target *rt );
+
+// Refit bounds so that it is square, and crops to center with padding
+void csr_auto_fit( csr_target *rt, float padding );
+
+// Run this after bounds have been adjusted on the RT to update the size of the msaa
+// Auto fit will call this.
+void csr_update_subsamples( csr_target *rt );
+
+// Write CS:GO radar txt
+void csr_write_txt( char const *path, const char *name, csr_target *rt );
+
+// Render calls
+// ------------
+
+// Render a finalzied triangle into target. Coordinates are world space
+void simple_raster( csr_target *rt, vmf_vert tri[3] );
+
+// Draw a batch of triangles with an affine world transformation
+void csr_draw( csr_target *rt, vmf_vert *triangles, u32 triangle_count, m4x3f transform );
+
+// Draw VMF with filtering options. Will automatically branch into instances
+// You should call this with the last two recursive arguments (prev,inst), set to NULL
+//
+// Filter is optional, it can be st to NULL to just render everything.
+void csr_vmf_render( csr_target *rt, vmf_map *map, vdf_node *root, csr_filter *filter, m4x3f prev, m4x3f inst );
+
+// Obsolete
+void csr_rt_save_buffers( csr_target *rt, const char *basename, const char *subname );
+
+// Implementation
+//=======================================================================================================================
+
+struct csr_shader
+{
+ u32 stride;
+ csr_frag_program frag;
+ csr_frag_clear clear;
+};
+
+struct csr_target
+{
+ void *colour;
+ float *depth;
+
+ u32 x, y;
+ boxf bounds;
+ float scale;
+
+ v2f subsamples[ 8 ];
+ int num_samples;
+ v2f *sample_src;
+
+ csr_shader *shader;
+};
+
+struct csr_filter
+{
+ const char *visgroup; // Limit to this visgroup only
+ const char *classname; // Limit to this exact classname. will not draw world
+
+ int compute_bounds_only;
+};
+
+enum EMSAA
+{
+ k_EMSAA_none,
+ k_EMSAA_2x2,
+ k_EMSAA_RGSS,
+ k_EMSAA_8R
+};
+
+#ifdef CSR_EXECUTABLE
// MSAA patterns
v2f csr_msaa_1[] =
{ -0x0.3p0f, 0x0.5p0f }
};
-struct csr_frag
-{
- v4f colour;
- float depth;
-};
-
-struct csr_target
-{
- csr_frag *fragments;
-
- u32 x, y;
- boxf bounds;
- float scale;
-
- v2f subsamples[ 8 ];
- int num_samples;
- v2f *sample_src;
-
- csr_frag_shader shader;
-};
-
-void csr_use_program( csr_target *rt, csr_frag_shader shader )
-{
- rt->shader = shader;
-}
-struct csr_filter
-{
- const char *visgroup; // Limit to this visgroup only
- const char *classname; // Limit to this exact classname. will not draw world
-
- int compute_bounds_only;
-};
-
-enum EMSAA
-{
- k_EMSAA_none,
- k_EMSAA_2x2,
- k_EMSAA_RGSS,
- k_EMSAA_8R
-};
-
-void csr_create_target( csr_target *rt, u32 x, u32 y, EMSAA aa )
+void csr_create_target( csr_target *rt, u32 x, u32 y, EMSAA aa, csr_shader *shader )
{
rt->x = x;
rt->y = y;
break;
}
- rt->fragments = (csr_frag *)csr_malloc( x*y*sizeof(csr_frag)*rt->num_samples );
+ rt->shader = shader;
+ rt->depth = (float *)csr_malloc( x*y*rt->num_samples * sizeof(float) );
+ rt->colour = csr_malloc( x * y * rt->shader->stride * rt->num_samples );
v3_fill( rt->bounds[0], INFINITY );
v3_fill( rt->bounds[1], -INFINITY );
void csr_rt_free( csr_target *rt )
{
- free( rt->fragments );
+ free( rt->depth );
+ free( rt->colour );
}
void csr_rt_clear( csr_target *rt )
{
for( u32 i = 0; i < rt->x*rt->y*rt->num_samples; i ++ )
{
- v4_zero( rt->fragments[ i ].colour );
- rt->fragments[i].depth = 0.f;
+ rt->shader->clear( rt->colour + i * rt->shader->stride );
+ rt->depth[i] = 0.f;
}
}
{
// Correct aspect ratio to be square
float dx, dy, l, cx, cy;
+
dx = rt->bounds[1][0] - rt->bounds[0][0];
dy = rt->bounds[1][1] - rt->bounds[0][1];
fclose( write_ptr );
}
-void frag_gbuffer( v4f frag_colour, vmf_vert tri[3], float bca, float bcb, float bcc )
-{
- v3_muls( tri[0].co, bca, frag_colour );
- v3_muladds( frag_colour, tri[1].co, bcb, frag_colour );
- v3_muladds( frag_colour, tri[2].co, bcc, frag_colour );
-}
-
void simple_raster( csr_target *rt, vmf_vert tri[3] )
{
// Very very simplified rasterizing algorithm
for( u32 px = start_x; px <= end_x; px ++ )
{
- csr_frag *frag = &rt->fragments[ (py * rt->y + px) * rt->num_samples ];
+ u32 sample_index = (py * rt->y + px) * rt->num_samples;
+
+ void *frag = rt->colour + sample_index*rt->shader->stride;
+ float *depth = &rt->depth[ sample_index ];
trace_origin[0] = csr_lerpf( rt->bounds[0][0], rt->bounds[1][0], (float)px/(float)rt->x );
float hit = (tri[0].co[2] * bca + tri[1].co[2] * bcb + tri[2].co[2] * bcc) +16385.f;
- if( hit > frag[i].depth )
+ if( hit > depth[i] )
{
- frag[i].depth = hit;
- rt->shader( frag[i].colour, tri, bca, bcb, bcc );
+ depth[i] = hit;
+ rt->shader->frag( frag+i*rt->shader->stride, tri, bca, bcb, bcc );
}
}
}
}
}
-void draw_vmf_group( csr_target *rt, vmf_map *map, vdf_node *root, csr_filter *filter, m4x3f prev, m4x3f inst )
+void csr_vmf_render( csr_target *rt, vmf_map *map, vdf_node *root, csr_filter *filter, m4x3f prev, m4x3f inst )
{
m4x3f transform = M4X3_IDENTITY;
vmf_solid solid;
m4x3_identity( model );
vmf_entity_transform( ent, model );
- draw_vmf_group( rt, map, map->cache[ ent->user1 ].root, filter, transform, model );
+ csr_vmf_render( rt, map, map->cache[ ent->user1 ].root, filter, transform, model );
}
else
{
solidgen_ctx_free( &solid );
}
+// Obsolete
void csr_rt_save_buffers( csr_target *rt, const char *basename, const char *subname )
{
char output[ 512 ];
for( int x = 0; x < rt->y; x ++ )
{
float *dst = &image[ (l*1024+x)*3 ];
- csr_frag *src = &rt->fragments[ ((1023-l)*1024+x)*rt->num_samples ];
+ void *src = rt->colour + ((1023-l)*1024+x) * rt->num_samples * rt->shader->stride;
- v3_zero( dst );
- v3_muls( src[0].colour, contrib, dst );
+ v3_muls( (float *)src, contrib, dst );
for( int j = 1; j < rt->num_samples; j ++ )
{
- v3_muladds( dst, src[j].colour, contrib, dst );
+ v3_muladds( dst, (float *)(src + j*rt->shader->stride), contrib, dst );
}
}
}
free( image );
}
+
+#endif
+// Copyright (C) 2021 Harry Godden (hgn)
+
// Low level disk reading
//=======================================================================================================================
+// Read binary, or text assets. _s variants also give size in bytes
+void *csr_asset_read_s( const char *path, i64 *size );
+void *csr_asset_read( const char *path );
+char *csr_textasset_read_s( const char *path, i64 *size );
+char *csr_textasset_read( const char *name );
+
+i64 fs_file_size( FILE *fileptr );
+
+// Path handling
+// -------------
+
+// Find file path extension, returns NULL if no ext (0x00)
+char *csr_findext( char *path, char const delim );
+
+// gets rid of extension on string only left with (folder)+filename
+void csr_stripext( char *path );
+
+int csr_path_is_abs( char const *path );
+
+// Convert windows paths to unix.. sortof ( \something\\blahblah .. ) -> /something/blahblah/
+// Does not handle drive letters, idea is to increase windows compatibility will the other functions above
+void csr_path_winunix( char *path );
+
+// Implementation
+//=======================================================================================================================
+
+#ifdef CSR_EXECUTABLE
+
i64 fs_file_size( FILE *fileptr )
{
fseek( fileptr, 0, SEEK_END );
return fs_disk_load_text( name, &size );
}
-// Find file path extension, returns NULL if no ext (0x00)
char *csr_findext( char *path, char const delim )
{
char *c, *ptr;
return ptr;
}
-// gets rid of extension on string only left with folder/filename
void csr_stripext( char *path )
{
char *point, *start;
}
}
-// Convert windows paths to unix-ish ( \something\\blahblah .. ) -> /something/blahblah/
void csr_path_winunix( char *path )
{
char *idx, *wr;
#endif
}
-#ifdef _WIN32
- #define GetWorkingDir _getcwd
-#else
- #define GetWorkingDir getcwd
#endif
+// Copyright (C) 2021 Harry Godden (hgn)
+
// Logging with colour
// ======================================================================================
+void log_success( const char *fmt, ... );
+void log_info( const char *fmt, ... );
+void log_warn( const char *fmt, ... );
+void log_error( const char *fmt, ... );
+
+#ifdef CSR_EXECUTABLE
+
#define KNRM "\x1B[0m"
#define KRED "\x1B[31m"
#define KGRN "\x1B[32m"
#define KCYN "\x1B[36m"
#define KWHT "\x1B[37m"
-#define LOG_TYPE_DEV 0
-#define LOG_TYPE_INFO 1
-#define LOG_TYPE_ALLOC 2
-#define LOG_TYPE_FREE 3
-#define LOG_TYPE_SUCCESS 4
-#define LOG_TYPE_ERROR 5
-#define LOG_TYPE_WARN 6
-
-void(*CSR_LOG_REDIR_STDOUT)(int, const char*) = NULL;
-int CSR_LOG_ENABLE_STDOUT = 1;
-
-void csr_log_out( FILE *f, int type, const char* prefix, const char* fmt, ... )
-{
- if( CSR_LOG_ENABLE_STDOUT )
- {
- fprintf( f, "%s", prefix );
- va_list args;
- va_start( args, fmt );
- vfprintf( f, fmt, args );
- va_end( args );
- fprintf( f, KNRM ); // reset
- }
-
- // Send to a seperate logging function
- if( CSR_LOG_REDIR_STDOUT )
- {
- char buffer[ 512 ];
- va_list args;
- va_start( args, fmt );
- vsnprintf( buffer, 512, fmt, args );
- va_end( args );
- CSR_LOG_REDIR_STDOUT( type, buffer );
- }
-}
+#define CSR_LOG_WRITE( FILE, PREFIX ) \
+ fprintf( FILE, PREFIX ); \
+ va_list args; \
+ va_start( args, fmt ); \
+ vfprintf( FILE, fmt, args ); \
+ va_end( args ); \
+ fprintf( FILE, KNRM );
-#define log_dev(FMT, ...) csr_log_out( stdout, LOG_TYPE_DEV, (KNRM " dev" KWHT "| " KNRM), FMT, ##__VA_ARGS__ )
-#define log_info(FMT, ...) csr_log_out( stdout, LOG_TYPE_INFO, (KNRM " info" KWHT "| " KNRM), FMT, ##__VA_ARGS__ )
-#define log_alloc(FMT, ...) csr_log_out( stdout, LOG_TYPE_ALLOC, (KCYN " alloc" KWHT "| " KNRM), FMT, ##__VA_ARGS__ )
-#define log_free(FMT, ...) csr_log_out( stdout, LOG_TYPE_FREE, (KMAG " free" KWHT "| " KNRM), FMT, ##__VA_ARGS__ )
-#define log_success(FMT, ...) csr_log_out( stdout, LOG_TYPE_SUCCESS, (KGRN "success" KWHT "| " KGRN), FMT, ##__VA_ARGS__ )
-#define log_error(FMT, ...) csr_log_out( stderr, LOG_TYPE_ERROR, (KRED " error" KWHT "| " KRED), FMT, ##__VA_ARGS__ )
-#define log_warn(FMT, ...) csr_log_out( stdout, LOG_TYPE_WARN, (KYEL " warn" KWHT "| " KYEL), FMT, ##__VA_ARGS__ )
-
-#define log_init log_alloc
-#define log_dealloc log_free
+void log_success( const char *fmt, ... ) { CSR_LOG_WRITE( stdout, (KGRN "success" KWHT "| " KGRN) ); }
+void log_info( const char *fmt, ... ) { CSR_LOG_WRITE( stdout, (KNRM " info" KWHT "| " KNRM) ); }
+void log_warn( const char *fmt, ... ) { CSR_LOG_WRITE( stdout, (KYEL " warn" KWHT "| " KYEL) ); }
+void log_error( const char *fmt, ... ) { CSR_LOG_WRITE( stderr, (KRED " error" KWHT "| " KRED) ); }
+// TODO: Remove this?
const char *csr_prog_msg;
void csr_prog_begin( const char *msg )
{
csr_prog_update( 1.f );
printf( "\n" );
}
+
+#endif
+// Copyright (C) 2021 Harry Godden (hgn)
+
// Util
// ==================================================================================================================
+#define CSR_INLINE static inline
#define CSR_PIf 3.14159265358979323846264338327950288f
// Simple min/max replacements
-float csr_minf( float a, float b )
+CSR_INLINE float csr_minf( float a, float b )
{
return a < b? a: b;
}
-float csr_maxf( float a, float b )
+CSR_INLINE float csr_maxf( float a, float b )
{
return a > b? a: b;
}
-int csr_min( int a, int b )
+CSR_INLINE int csr_min( int a, int b )
{
return a < b? a: b;
}
-int csr_max( int a, int b )
+CSR_INLINE int csr_max( int a, int b )
{
return a > b? a: b;
}
// Convert double precision vec3 into single
-void v3d_v3f( double a[3], float b[3] )
+CSR_INLINE void v3d_v3f( double a[3], float b[3] )
{
b[0] = a[0];
b[1] = a[1];
}
// Convert degrees to radians
-float csr_rad( float deg )
+CSR_INLINE float csr_rad( float deg )
{
return deg * CSR_PIf / 180.0f;
}
// Vector 2
// ==================================================================================================================
-void v2_copy( v2f a, v2f b )
+CSR_INLINE void v2_copy( v2f a, v2f b )
{
b[0] = a[0]; b[1] = a[1];
}
-void v2_minv( v2f a, v2f b, v2f dest )
+CSR_INLINE void v2_minv( v2f a, v2f b, v2f dest )
{
dest[0] = csr_minf(a[0], b[0]);
dest[1] = csr_minf(a[1], b[1]);
}
-void v2_maxv( v2f a, v2f b, v2f dest )
+CSR_INLINE void v2_maxv( v2f a, v2f b, v2f dest )
{
dest[0] = csr_maxf(a[0], b[0]);
dest[1] = csr_maxf(a[1], b[1]);
}
-void v2_sub( v2f a, v2f b, v2f d )
+CSR_INLINE void v2_sub( v2f a, v2f b, v2f d )
{
d[0] = a[0]-b[0]; d[1] = a[1]-b[1];
}
-float v2_cross( v2f a, v2f b )
+CSR_INLINE float v2_cross( v2f a, v2f b )
{
return a[0] * b[1] - a[1] * b[0];
}
-void v2_add( v2f a, v2f b, v2f d )
+CSR_INLINE void v2_add( v2f a, v2f b, v2f d )
{
d[0] = a[0]+b[0]; d[1] = a[1]+b[1];
}
-void v2_muls( v2f a, float s, v2f d )
+CSR_INLINE void v2_muls( v2f a, float s, v2f d )
{
d[0] = a[0]*s; d[1] = a[1]*s;
}
-void v2_mul( v2f a, v2f b, v2f d )
+CSR_INLINE void v2_mul( v2f a, v2f b, v2f d )
{
d[0] = a[0]*b[0]; d[1] = a[1]*b[1];
}
// Vector 3
// ==================================================================================================================
-void v3_zero( v3f a )
+CSR_INLINE void v3_zero( v3f a )
{
a[0] = 0.f; a[1] = 0.f; a[2] = 0.f;
}
-void v3_copy( v3f a, v3f b )
+CSR_INLINE void v3_copy( v3f a, v3f b )
{
b[0] = a[0]; b[1] = a[1]; b[2] = a[2];
}
-void v3_add( v3f a, v3f b, v3f d )
+CSR_INLINE void v3_add( v3f a, v3f b, v3f d )
{
d[0] = a[0]+b[0]; d[1] = a[1]+b[1]; d[2] = a[2]+b[2];
}
-void v3_sub( v3f a, v3f b, v3f d )
+CSR_INLINE void v3_sub( v3f a, v3f b, v3f d )
{
d[0] = a[0]-b[0]; d[1] = a[1]-b[1]; d[2] = a[2]-b[2];
}
-void v3_mul( v3f a, v3f b, v3f d )
+CSR_INLINE void v3_mul( v3f a, v3f b, v3f d )
{
d[0] = a[0]*b[0]; d[1] = a[1]*b[1]; d[2] = a[2]*b[2];
}
-void v3_div( v3f a, v3f b, v3f d )
+CSR_INLINE void v3_div( v3f a, v3f b, v3f d )
{
d[0] = a[0]/b[0]; d[1] = a[1]/b[1]; d[2] = a[2]/b[2];
}
-void v3_muls( v3f a, float s, v3f d )
+CSR_INLINE void v3_muls( v3f a, float s, v3f d )
{
d[0] = a[0]*s; d[1] = a[1]*s; d[2] = a[2]*s;
}
-void v3_divs( v3f a, float s, v3f d )
+CSR_INLINE void v3_divs( v3f a, float s, v3f d )
{
d[0] = a[0]/s; d[1] = a[1]/s; d[2] = a[2]/s;
}
-void v3_muladds( v3f a, v3f b, float s, v3f d )
+CSR_INLINE void v3_muladds( v3f a, v3f b, float s, v3f d )
{
d[0] = a[0]+b[0]*s; d[1] = a[1]+b[1]*s; d[2] = a[2]+b[2]*s;
}
-float v3_dot( v3f a, v3f b )
+CSR_INLINE float v3_dot( v3f a, v3f b )
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
-void v3_cross( v3f a, v3f b, v3f d )
+CSR_INLINE void v3_cross( v3f a, v3f b, v3f d )
{
d[0] = a[1] * b[2] - a[2] * b[1];
d[1] = a[2] * b[0] - a[0] * b[2];
d[2] = a[0] * b[1] - a[1] * b[0];
}
-float v3_length2( v3f a )
+CSR_INLINE float v3_length2( v3f a )
{
return v3_dot( a, a );
}
-float v3_length( v3f a )
+CSR_INLINE float v3_length( v3f a )
{
return sqrtf( v3_length2( a ) );
}
-float v3_dist2( v3f a, v3f b )
+CSR_INLINE float v3_dist2( v3f a, v3f b )
{
v3f delta;
v3_sub( a, b, delta );
return v3_length2( delta );
}
-float v3_dist( v3f a, v3f b )
+CSR_INLINE float v3_dist( v3f a, v3f b )
{
return sqrtf( v3_dist2( a, b ) );
}
-void v3_normalize( v3f a )
+CSR_INLINE void v3_normalize( v3f a )
{
v3_muls( a, 1.f / v3_length( a ), a );
}
-float csr_lerpf( float a, float b, float t )
+CSR_INLINE float csr_lerpf( float a, float b, float t )
{
return a + t*(b-a);
}
-void v3_lerp( v3f a, v3f b, float t, v3f d )
+CSR_INLINE void v3_lerp( v3f a, v3f b, float t, v3f d )
{
d[0] = a[0] + t*(b[0]-a[0]);
d[1] = a[1] + t*(b[1]-a[1]);
d[2] = a[2] + t*(b[2]-a[2]);
}
-void v3_minv( v3f a, v3f b, v3f dest )
+CSR_INLINE void v3_minv( v3f a, v3f b, v3f dest )
{
dest[0] = csr_minf(a[0], b[0]);
dest[1] = csr_minf(a[1], b[1]);
dest[2] = csr_minf(a[2], b[2]);
}
-void v3_maxv( v3f a, v3f b, v3f dest )
+CSR_INLINE void v3_maxv( v3f a, v3f b, v3f dest )
{
dest[0] = csr_maxf(a[0], b[0]);
dest[1] = csr_maxf(a[1], b[1]);
dest[2] = csr_maxf(a[2], b[2]);
}
-float v3_minf( v3f a )
+CSR_INLINE float v3_minf( v3f a )
{
return csr_minf( csr_minf( a[0], a[1] ), a[2] );
}
-float v3_maxf( v3f a )
+CSR_INLINE float v3_maxf( v3f a )
{
return csr_maxf( csr_maxf( a[0], a[1] ), a[2] );
}
-void v3_fill( v3f a, float v )
+CSR_INLINE void v3_fill( v3f a, float v )
{
a[0] = v;
a[1] = v;
// Vector 4
// ==================================================================================================================
-void v4_copy( v4f a, v4f b )
+CSR_INLINE void v4_copy( v4f a, v4f b )
{
b[0] = a[0]; b[1] = a[1]; b[2] = a[2]; b[3] = a[3];
}
-void v4_zero( v4f a )
+CSR_INLINE void v4_zero( v4f a )
{
a[0] = 0.f; a[1] = 0.f; a[2] = 0.f; a[3] = 0.f;
}
// Matrix 3x3
//======================================================================================================
-void m3x3_inv_transpose( m3x3f src, m3x3f dest )
+CSR_INLINE void m3x3_inv_transpose( m3x3f src, m3x3f dest )
{
float a = src[0][0], b = src[0][1], c = src[0][2],
d = src[1][0], e = src[1][1], f = src[1][2],
dest[2][2] = (a*e-d*b)*det;
}
-void m3x3_mulv( m3x3f m, v3f v, v3f d )
+CSR_INLINE void m3x3_mulv( m3x3f m, v3f v, v3f d )
{
v3f res;
{ 0.0f, 0.0f, 1.0f, },\
{ 0.0f, 0.0f, 0.0f }}
-void m4x3_to_3x3( m4x3f a, m3x3f b )
+CSR_INLINE void m4x3_to_3x3( m4x3f a, m3x3f b )
{
v3_copy( a[0], b[0] );
v3_copy( a[1], b[1] );
v3_copy( a[2], b[2] );
}
-void m4x3_copy( m4x3f a, m4x3f b )
+CSR_INLINE void m4x3_copy( m4x3f a, m4x3f b )
{
v3_copy( a[0], b[0] );
v3_copy( a[1], b[1] );
v3_copy( a[3], b[3] );
}
-void m4x3_identity( m4x3f a )
+CSR_INLINE void m4x3_identity( m4x3f a )
{
m4x3f id = M4X3_IDENTITY;
m4x3_copy( id, a );
}
-void m4x3_mul( m4x3f a, m4x3f b, m4x3f d )
+CSR_INLINE void m4x3_mul( m4x3f a, m4x3f b, m4x3f d )
{
float
a00 = a[0][0], a01 = a[0][1], a02 = a[0][2],
d[3][2] = a02*b30 + a12*b31 + a22*b32 + a32;
}
-void m4x3_mulv( m4x3f m, v3f v, v3f d )
+CSR_INLINE void m4x3_mulv( m4x3f m, v3f v, v3f d )
{
v3f res;
// Affine transforms
-void m4x3_translate( m4x3f m, v3f v )
+CSR_INLINE void m4x3_translate( m4x3f m, v3f v )
{
v3_muladds( m[3], m[0], v[0], m[3] );
v3_muladds( m[3], m[1], v[1], m[3] );
v3_muladds( m[3], m[2], v[2], m[3] );
}
-void m4x3_scale( m4x3f m, float s )
+CSR_INLINE void m4x3_scale( m4x3f m, float s )
{
v3_muls( m[0], s, m[0] );
v3_muls( m[1], s, m[1] );
v3_muls( m[2], s, m[2] );
}
-void m4x3_rotate_x( m4x3f m, float angle )
+CSR_INLINE void m4x3_rotate_x( m4x3f m, float angle )
{
m4x3f t = M4X3_IDENTITY;
float c, s;
m4x3_mul( m, t, m );
}
-void m4x3_rotate_y( m4x3f m, float angle )
+CSR_INLINE void m4x3_rotate_y( m4x3f m, float angle )
{
m4x3f t = M4X3_IDENTITY;
float c, s;
m4x3_mul( m, t, m );
}
-void m4x3_rotate_z( m4x3f m, float angle )
+CSR_INLINE void m4x3_rotate_z( m4x3f m, float angle )
{
m4x3f t = M4X3_IDENTITY;
float c, s;
}
// Warning: These functions are unoptimized..
-void m4x3_expand_aabb_point( m4x3f m, boxf box, v3f point )
+CSR_INLINE void m4x3_expand_aabb_point( m4x3f m, boxf box, v3f point )
{
v3f v;
m4x3_mulv( m, point, v );
v3_maxv( box[1], v, box[1] );
}
-void box_concat( boxf a, boxf b )
+CSR_INLINE void box_concat( boxf a, boxf b )
{
v3_minv( a[0], b[0], a[0] );
v3_maxv( a[1], b[1], a[1] );
}
-void box_copy( boxf a, boxf b )
+CSR_INLINE void box_copy( boxf a, boxf b )
{
v3_copy( a[0], b[0] );
v3_copy( a[1], b[1] );
}
-void m4x3_transform_aabb( m4x3f m, boxf box )
+CSR_INLINE void m4x3_transform_aabb( m4x3f m, boxf box )
{
v3f a; v3f b;
// Planes (double precision)
// ==================================================================================================================
-void tri_to_plane( double a[3], double b[3], double c[3], double p[4] )
+CSR_INLINE void tri_to_plane( double a[3], double b[3], double c[3], double p[4] )
{
double edge0[3];
double edge1[3];
p[2] = p[2] / l;
}
-int plane_intersect( double a[4], double b[4], double c[4], double p[4] )
+CSR_INLINE int plane_intersect( double a[4], double b[4], double c[4], double p[4] )
{
double const epsilon = 1e-8f;
return 1;
}
-double plane_polarity( double p[4], double a[3] )
+CSR_INLINE double plane_polarity( double p[4], double a[3] )
{
return
(a[0] * p[0] + a[1] * p[1] + a[2] * p[2])
-#ifndef CSR_MEM_H
-#define CSR_MEM_H
+// Copyright (C) 2021 Harry Godden (hgn)
-#include "csrTypes.h"
+// Memory API
+// ==================================================================================================================
+
+// Malloc call wrapper that will exit if out of memory (similar to xalloc)
+void *csr_malloc( size_t size );
+void *csr_calloc( size_t size );
+
+// Dynamic arrays (inspired by stb_stretchy_buffer)
+// ------------------------------------------------
+
+// Reserve x elements of size to this buffer. Must assign back (like realloc)
+__attribute__((warn_unused_result))
+void *csr_sb_reserve( void *arr, u32 amt, u32 esize );
+
+// Get index of next free data and increment count by 1
+void *csr_sb_use( void *arr );
+
+// Increment count by amt
+void csr_sb_inc( void *arr, u32 amt );
+
+u32 csr_sb_count( void *arr );
+void csr_sb_free( void *arr );
+
+// Does not clear memory / capacity, but resets count to 0
+void csr_sb_clear( void *arr );
+
+// Internal
+void *csr_sb_raw( void *arr );
+u32 csr_sb_cap( void *arr );
+
+// djb2 - Dan Bernstein
+unsigned long djb2( unsigned char const *str );
+
+// Implementation
+// ==================================================================================================================
+
+#ifdef CSR_EXECUTABLE
void *csr_malloc( size_t size )
{
raw[1] += amt;
}
-__attribute__((warn_unused_result))
void *csr_sb_reserve( void *arr, u32 amt, u32 esize )
{
u32 cap = arr? csr_sb_cap( arr ): 0;
+// Copyright (C) 2021 Harry Godden (hgn)
+
+#ifdef CSR_EXECUTABLE
+
// Supported:
// -abc
// -a value
return NULL;
}
+
+#endif
--- /dev/null
+// Copyright (C) 2021 Harry Godden (hgn)
+
+// Cross platform (windows/unix) dynamic linking wrapper
+//=======================================================================================================================
+
+#ifdef CSR_EXECUTABLE
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+ #define CSR_WINDOWS
+ #include <libloaderapi.h>
+ typedef HWMODULE csr_so;
+#else
+ #define CSR_UNIX
+ #include <dlfcn.h>
+ typedef void *csr_so;
+#endif
+
+csr_so csr_libopen( const char *name )
+{
+ char path[ 512 ];
+ strcpy( path, "ext/" );
+ strcat( path, name );
+
+ #ifdef CSR_UNIX
+ strcat( path, ".so" );
+ #else
+ strcat( path, ".dll" );
+ #endif
+
+ log_info( "Loading dynamic library (%s)\n", path );
+
+ #ifdef CSR_UNIX
+ return dlopen( path, RTLD_NOW );
+ #else
+ return LoadLibrary( path );
+ #endif
+}
+
+void *csr_get_proc( csr_so so, const char *name )
+{
+ #ifdef CSR_UNIX
+ return dlsym( so, name );
+ #else
+ return (void *)GetProcAddress( so, name );
+ #endif
+}
+
+void csr_libclose( csr_so so )
+{
+ #ifdef CSR_UNIX
+ dlclose( so );
+ #else
+ FreeLibrary( so );
+ #endif
+}
+
+void csr_liberr(void)
+{
+ #ifdef CSR_UNIX
+ log_error( "Could not load that DLL (%s)\n", dlerror() );
+ #else
+ log_error( "Could not load that DLL (Windows unkown)\n" );
+ #endif
+}
+
+#endif
--- /dev/null
+// Copyright (C) 2021 Harry Godden (hgn)
+
+// Basic buffers-only version of csRadar
+//=======================================================================================================================
+
+#include "csRadar.h"
+
+// GBuffer shader
+void frag_gbuffer( void *dest, vmf_vert tri[3], float bca, float bcb, float bcc );
+void frag_gbuffer_clear( void *dest );
+
+csr_shader shader_gbuffer =
+{
+ .stride = sizeof(float)*8, // (origin) x,y, (actual height) z
+ .frag = frag_gbuffer,
+ .clear = frag_gbuffer_clear
+};
+
+// Main drawing function
+void draw_buffers( csr_api *api, int bounds_only );
+
+// Extension implementation
+// =========================================================================================================
+
+// API ENTRY
+void csr_ext_main( csr_api *api )
+{
+ if( !csr_init( api ) )
+ return;
+
+ csr_create_target( &api->target, api->resolution, api->resolution, api->sampling_mode, &shader_gbuffer );
+ csr_rt_clear( &api->target );
+
+ // Compute bounds, collect models
+ draw_buffers( api, 1 );
+ csr_auto_fit( &api->target, api->padding );
+ vmf_load_models( api->map );
+
+ // Draw everything
+ draw_buffers( api, 0 );
+}
+
+void csr_ext_exit( csr_api *api )
+{
+ csr_rt_free( &api->target );
+}
+
+void draw_buffers( csr_api *api, int bounds_only )
+{
+ csr_filter filter = { .compute_bounds_only = bounds_only };
+ vmf_map *map = api->map;
+
+ if( api->num_strings == 1 )
+ {
+ // Draw everything
+ csr_vmf_render( &api->target, map, map->root, &filter, NULL, NULL );
+
+ if( !bounds_only )
+ {
+ csr_rt_save_buffers( &api->target, api->output_path, "all" );
+ }
+ }
+ else
+ {
+ // Draw groups
+ for( int i = 1; i < api->num_strings; i ++ )
+ {
+ filter.visgroup = api->strings[ i ];
+ csr_vmf_render( &api->target, map, map->root, &filter, NULL, NULL );
+
+ if( !bounds_only )
+ {
+ csr_rt_save_buffers( &api->target, api->output_path, api->strings[i] );
+ //csr_rt_save_c32f( ... );
+ //csr_rt_save_tga( ... );
+
+ // tar_write_dds( ... );
+
+ csr_rt_clear( &api->target );
+ }
+ }
+ }
+}
+
+void frag_gbuffer( void *dest, vmf_vert tri[3], float bca, float bcb, float bcc )
+{
+ float *dest_colour = (float *)dest;
+
+ v3_muls( tri[0].co, bca, dest_colour );
+ v3_muladds( dest_colour, tri[1].co, bcb, dest_colour );
+ v3_muladds( dest_colour, tri[2].co, bcc, dest_colour );
+
+ // TODO: Normal map
+}
+
+void frag_gbuffer_clear( void *dest )
+{
+ float *dest_colour = (float *)dest;
+ v3_zero( dest_colour );
+}
+// This software is not affiliated with Valve Corporation
+// We are not affiliated, associated, authorized, endorsed by, or in any way officially
+// connected with Valve Corporation, or any of its subsidiaries or its affiliates.
+//
+// All trademarks are property of their respective owners
+
+// VDF aka Keyvalue text format parser / writer
+
#define vdf_foreach( NODE, STR, AS ) \
int __vdf_it_##AS = 0; \
vdf_node * AS;\
const char * AS;\
while( (AS = kv_iter( NODE, STR, &__kv_it_##AS )) )
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <ctype.h>
// TYPES
// ==================================================================================================================
// INTERNAL API
// ==================================================================================================================
+#ifdef VALVE_IMPLEMENTATION
// Add keyvalue pair to node
void vdf_kv_append( vdf_node *p, const char *k, const char *v );
// Formatting
void vdf_out_indent( const int n, FILE *file );
+#endif
+
// IMPLEMENTATION
// ==================================================================================================================
u32 user1;
};
+#ifdef VALVE_IMPLEMENTATION
+
vdf_node *vdf_next( vdf_node *node, const char *name, int *it )
{
if( !node )
{
vdf_out( node, -1, 0, stdout );
}
+
+#endif
+// This software is not affiliated with Valve Corporation
+// We are not affiliated, associated, authorized, endorsed by, or in any way officially
+// connected with Valve Corporation, or any of its subsidiaries or its affiliates.
+//
+// All trademarks are property of their respective owners
+
// Abstract Valve file system
//=======================================================================================================================
+// Initialize game directories / pakfile
+void fs_set_gameinfo( const char *path );
+void fs_exit(void);
+
+// Read asset as binary in full. Will search VPK, then searchpaths, or return NULL if not found
+char *valve_fs_get( const char *path );
+
+// Implementation
+//=======================================================================================================================
+
+#ifdef VALVE_IMPLEMENTATION
+
struct valve_filesystem
{
char gamedir[ 512 ];
return NULL;
}
+
+#endif
+// This software is not affiliated with Valve Corporation
+// We are not affiliated, associated, authorized, endorsed by, or in any way officially
+// connected with Valve Corporation, or any of its subsidiaries or its affiliates.
+//
+// All trademarks are property of their respective owners
+
+typedef struct mdl_mesh mdl_mesh_t;
+
+// High level API
+//=======================================================================================================================
+
+// Load model from vfs
+int mdl_from_find_files( const char *mdlname, mdl_mesh_t *ctx );
+void mdl_free( mdl_mesh_t *m );
+
+// Set ctx to blank / 0,0
+void mdl_error( mdl_mesh_t *m );
+
+// Implementation
+//=======================================================================================================================
+
+struct mdl_mesh
+{
+ u16 *indices;
+ u32 num_indices;
+
+ float *vertices;
+ u32 num_vertices;
+
+ // Bounding box
+ boxf bounds;
+};
+
+#ifdef VALVE_IMPLEMENTATION
+
// VVD
//=======================================================================================================================
//StudioMDL constants
#pragma pack(pop)
-typedef struct
-{
- u16 *indices;
- u32 num_indices;
-
- float *vertices;
- u32 num_vertices;
-
- // Bounding box
- boxf bounds;
-}
-mdl_mesh_t;
-
void mdl_free( mdl_mesh_t *m )
{
free( m->indices );
return 1;
}
+
+#endif
-#define SOLID_MAX_SIDES 512
-#define VMF_FLAG_IS_PROP 0x1
-#define VMF_FLAG_IS_INSTANCE 0x2
-#define VMF_FLAG_BRUSH_ENT 0x4
+// This software is not affiliated with Valve Corporation
+// We are not affiliated, associated, authorized, endorsed by, or in any way officially
+// connected with Valve Corporation, or any of its subsidiaries or its affiliates.
+//
+// All trademarks are property of their respective owners
typedef struct vmf_solid vmf_solid;
typedef struct vmf_vert vmf_vert;
typedef enum ESolidResult ESolidResult;
+// API
+//=======================================================================================================================
+
+// Load vmf from disk
+vmf_map *vmf_init( const char *path );
+void vmf_free( vmf_map *map );
+
+// Solidgen API ~ Converting brushes into meshes
+// ---------------------------------------------
+void solidgen_ctx_init( vmf_solid *ctx );
+void solidgen_ctx_reset( vmf_solid *ctx );
+void solidgen_ctx_free( vmf_solid *ctx );
+void solidgen_bounds( vmf_solid *ctx, boxf box );
+
+ESolidResult solidgen_push( vmf_solid *ctx, vdf_node *node );
+
+// General VMF
+// -----------
+int solid_has_displacement( vdf_node *node );
+int vmf_class_is_prop( vdf_node *ent );
+
+// Build the list of all models used in this map, including instances
+void vmf_index_models( vmf_map *map );
+
+// Loads all models that have the resource flagged with need_load
+void vmf_load_models( vmf_map *map );
+
+// Create matrix describing this entities transform
+void vmf_entity_transform( vdf_node *ent, m4x3f mat );
+
+u32 vmf_visgroup_id( vdf_node *root, const char *name );
+int vmf_visgroup_match( vdf_node *ent, u32 target );
+
+// Currently unused
+//void vmf_addbisector( double p[4] );
+//void vmf_clearbisectors( void );
+//void vmf_ignore_mat( const char *material );
+//void vmf_clearignore( void );
+
+// Implementation
+//=======================================================================================================================
+
+#define SOLID_MAX_SIDES 512
+#define VMF_FLAG_IS_PROP 0x1
+#define VMF_FLAG_IS_INSTANCE 0x2
+#define VMF_FLAG_BRUSH_ENT 0x4
+
enum ESolidResult
{
k_ESolidResult_valid,
m4x3f transform;
};
-// IMPLEMENTATION
+#ifdef VALVE_IMPLEMENTATION
void solidgen_ctx_reset( vmf_solid *ctx )
{
return 0;
}
+
+#endif
+// This software is not affiliated with Valve Corporation
+// We are not affiliated, associated, authorized, endorsed by, or in any way officially
+// connected with Valve Corporation, or any of its subsidiaries or its affiliates.
+//
+// All trademarks are property of their respective owners
+
+// Valve pak file directory reader
+
// VPK
//=======================================================================================================================
+typedef struct VPKHeader VPKHeader;
+typedef struct VPKDirectoryEntry VPKDirectoryEntry;
+
+// API
+// ---
+
+// There is no load function, reading the header file as binary is enough.
+VPKDirectoryEntry *vpk_find( VPKHeader *self, const char *asset );
+void vpk_free( VPKHeader *self );
+
#pragma pack(push, 1)
-typedef struct
+struct VPKHeader
{
u32 Signature;
u32 Version;
u32 ArchiveMD5SectionSize;
u32 OtherMD5SectionSize;
u32 SignatureSectionSize;
-}
-VPKHeader;
+};
-typedef struct
+struct VPKDirectoryEntry
{
u32 CRC;
u16 PreloadBytes;
u32 EntryOffset;
u32 EntryLength;
u16 Terminator;
-}
-VPKDirectoryEntry;
+};
#pragma pack(pop)
+#ifdef VALVE_IMPLEMENTATION
+
void vpk_free( VPKHeader *self )
{
free( self );
return NULL;
}
+
+#endif