Compare commits

..

22 Commits

Author SHA1 Message Date
Cameron Murphy Reikes b925dd70fe No angel screen for now, moar todo 1 year ago
Cameron Murphy Reikes 741ceb14f5 Merge remote-tracking branch 'origin/gles3' 1 year ago
Cameron Murphy Reikes 7605d37d72 Merge branch 'main' of https://github.com/creikey/rpgpt 1 year ago
Cameron Murphy Reikes dcf23ca8e4 Add angel and angel dialog, but can't talk to it yet 1 year ago
Cameron Murphy Reikes c45c5c4fb2 Significantly upgraded TODO with notes from people 1 year ago
Cameron Murphy Reikes e3118d2335 Make names into 'you' when it's the character in human readable prompt 1 year ago
Phillip Trudeau-Tavara bc1663006c Alpha-to-coverage foliage 1 year ago
Phillip Trudeau-Tavara 08df997396 Film grain, contrast, vignette, cross-processing 1 year ago
Phillip Trudeau-Tavara 75345ae684 WebGL2; update sokol; Web MSAA; AA Outlines 1 year ago
Phillip Trudeau-Tavara 12965a7818 Change engine title strings to "Dante's Cowboy" 1 year ago
Phillip Trudeau-Tavara 526856a112 Support toggling fullscreen on web 1 year ago
Phillip Trudeau-Tavara 8650329b7f Reduce console printouts 1 year ago
Phillip Trudeau-Tavara bfae0a25bc Create build_and_run_web.bat 1 year ago
Phillip Trudeau-Tavara 56187771ae Passthrough command line arguments to subscripts 1 year ago
Phillip Trudeau-Tavara c3511ba954 Accept command line arguments in build_web_common 1 year ago
Phillip Trudeau-Tavara 6c0a832f61 Link win32 libs in code; add /nologo /diagnostics:caret /noimplib /noexp 1 year ago
Phillip Trudeau-Tavara 92fc09d2d6 Set sample count to 1 on web and 4 on desktop 1 year ago
Phillip Trudeau-Tavara 68cdbaac08 Greatly improve & simplify assertions 1 year ago
Phillip Trudeau-Tavara d5cf3d9f90 Disable glGetError() and keep validation and asserts 1 year ago
Phillip Trudeau-Tavara 718a89a3af Oops teehee 1 year ago
Phillip Trudeau-Tavara 4ee067be9c Update README.md 1 year ago
Phillip Trudeau-Tavara 3df3e8e027 Add automated blender_export.bat script 1 year ago

2
.gitignore vendored

@ -109,3 +109,5 @@ modules.order
Module.symvers Module.symvers
Mkfile.old Mkfile.old
dkms.conf dkms.conf
emsdk/

@ -1,10 +1,10 @@
# rpgpt # [Dante's Cowboy - Wishlist now on Steam!](https://store.steampowered.com/app/2501370/Dantes_Cowboy)
RPG GPT. Short experience A fantasy western RPG with an immersive and natural dynamic dialogue system powered by GPT.
![Western Frontier](https://upload.wikimedia.org/wikipedia/commons/thumb/3/32/Distribution_of_US_Rural_Population_during_1900.pdf/page1-1280px-Distribution_of_US_Rural_Population_during_1900.pdf.jpg) ![Western Frontier](https://upload.wikimedia.org/wikipedia/commons/thumb/3/32/Distribution_of_US_Rural_Population_during_1900.pdf/page1-1280px-Distribution_of_US_Rural_Population_during_1900.pdf.jpg)
# Important Building Steps and Contribution Notes # Important Building Steps and Contribution Notes
Every time you checkin/clone the project, you have to unzip art.blend... If this is annoying to you, make a git hook Every time you checkin/clone the project, make sure to call `blender_export.bat` at least once! This will auto-extract `art\art.blend` and run `art\Exporter.py`, thereby baking, validating, and exporting all the assets and the level.
When editing Exporter.py in either the blender editor, or in a text editor in the repo, you have to continually make sure blender's internal version of the script doesn't go out of date with the actual script on disk, by either saving consistently from blender to disk if you're editing from blender, or by reloading from disk in the blend file before each commit. When editing Exporter.py in either the blender editor, or in a text editor in the repo, you have to continually make sure blender's internal version of the script doesn't go out of date with the actual script on disk, by either saving consistently from blender to disk if you're editing from blender, or by reloading from disk in the blend file before each commit.

Binary file not shown.

@ -6,6 +6,10 @@
{ {
filepath: "maninblack.png", filepath: "maninblack.png",
} }
@image angel:
{
filepath: "angel.png",
}
@image unread_triangle: @image unread_triangle:
{ {
filepath: "unread_triangle.png", filepath: "unread_triangle.png",
@ -22,6 +26,10 @@
{ {
filepath: "simple_text_chirp.wav", filepath: "simple_text_chirp.wav",
} }
@sound angel_grunt_0:
{
filepath: "angel_grunt_0.wav",
}
@sound grunt_0: @sound grunt_0:
{ {
filepath: "grunt_0.wav", filepath: "grunt_0.wav",

BIN
assets/angel.png (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

@ -32,6 +32,10 @@
{enum: Daniel, dialog: "Exactly what I'll do to you if you don't keep your mouth shut", to: Raphael, action: ACT_put_shotgun_away} {enum: Daniel, dialog: "Exactly what I'll do to you if you don't keep your mouth shut", to: Raphael, action: ACT_put_shotgun_away}
{enum: Raphael, dialog: "Y-y-y-yes sir.", to: Daniel} {enum: Raphael, dialog: "Y-y-y-yes sir.", to: Daniel}
{can_hear: [Devil, Angel]}
{enum: Devil, dialog: "You will fall!", to: Angel}
{enum: Angel, dialog: "Perhaps. And then I will rise as He has, from the corpse and ashes, the sun rises.", to: Devil}
/* /*
{can_hear: [WellDweller, Farmer, ManInBlack]}, {can_hear: [WellDweller, Farmer, ManInBlack]},
{enum: WellDweller, dialog: "What a fearful farm you live in, come down to the well, the grass is damper down here.", to: Farmer, mood: Scared, thoughts: "Nobody can take me from my well"}, {enum: WellDweller, dialog: "What a fearful farm you live in, come down to the well, the grass is damper down here.", to: Farmer, mood: Scared, thoughts: "Nobody can take me from my well"},

@ -0,0 +1,33 @@
@echo off
pushd %~dp0%\art
if not exist "art.blend" (
powershell Expand-Archive -Path art.zip -DestinationPath . || goto :error
)
set "blender="
if exist "%ProgramFiles%\Blender Foundation\Blender 3.5\blender.exe" (
echo Using Blender 3.5 detected
set "blender=%ProgramFiles%\Blender Foundation\Blender 3.5\blender.exe"
)
if exist "%ProgramFiles%\Blender Foundation\Blender 3.6\blender.exe" (
echo Using Blender 3.6 detected
set "blender=%ProgramFiles%\Blender Foundation\Blender 3.6\blender.exe"
)
if "%blender%" neq "" (
call "%blender%" --background art.blend --python Exporter.py || goto :error
) else (
goto :error
)
goto :success
:error
echo Blender export failed
:success
set "returncode=%ERRORLEVEL%"
popd
exit /B %returncode%

@ -1,5 +1,5 @@
@echo off @echo off
START /B remedybg.exe stop-debugging START /B remedybg.exe stop-debugging
call build_desktop_debug.bat call build_desktop_debug.bat %*
remedybg.exe start-debugging remedybg.exe start-debugging

@ -0,0 +1,7 @@
@echo off
call build_web_debug.bat %* || goto :EOF
START "" "http://localhost:8000"
pushd %~dp0%\build_web
python -m http.server
popd

@ -2,10 +2,18 @@
@REM https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170 @REM https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170
setlocal enableDelayedExpansion
set "do_blender_export=0"
set "do_codegen=0"
for %%A in (%*) do (
if "%%~A"=="blender_export" ( set "do_blender_export=1" )
if "%%~A"=="codegen" ( set "do_codegen=1" )
)
if "%do_blender_export%"=="1" ( call blender_export.bat || goto :error )
if "%do_codegen%"=="1" ( call run_codegen.bat || goto :error )
if "%1" == "codegen" ( call run_codegen.bat || goto :error ) else ( echo NOT RUNNING CODEGEN )
@REM start /B zig cc -DDEVTOOLS -Igen -Ithirdparty -lDbghelp -lGdi32 -lD3D11 -lOle32 -lwinhttp -gfull -gcodeview -o main_zig.exe main.c @REM start /B zig cc -DDEVTOOLS -Igen -Ithirdparty -lDbghelp -lGdi32 -lD3D11 -lOle32 -lwinhttp -gfull -gcodeview -o main_zig.exe main.c
cl /diagnostics:caret /DDEVTOOLS /Igen /Ithirdparty /Wall /FC /Zi /WX Dbghelp.lib winhttp.lib main.c || goto :error cl /nologo /diagnostics:caret /DDEVTOOLS /Igen /Ithirdparty /Wall /FC /Zi /WX main.c /link /noimplib /noexp || goto :error
goto :EOF goto :EOF

@ -1,12 +1,21 @@
call run_codegen.bat || goto :error setlocal enableDelayedExpansion
set "do_blender_export=0"
set "do_codegen=0"
for %%A in (%*) do (
if "%%~A"=="blender_export" ( set "do_blender_export=1" )
if "%%~A"=="codegen" ( set "do_codegen=1" )
)
if "%do_blender_export%"=="1" ( call blender_export.bat || goto :error )
if "%do_codegen%"=="1" ( call run_codegen.bat || goto :error )
copy marketing_page\favicon.ico %OUTPUT_FOLDER%\favicon.ico copy marketing_page\favicon.ico %OUTPUT_FOLDER%\favicon.ico
@REM copy main.c %OUTPUT_FOLDER%\main.c || goto :error @REM copy main.c %OUTPUT_FOLDER%\main.c || goto :error
@echo on @echo off
emcc ^ emcc ^
-sEXPORTED_FUNCTIONS=_main,_end_text_input,_stop_controlling_input,_start_controlling_input,_read_from_save_data,_dump_save_data,_is_receiving_text_input^ -sEXPORTED_FUNCTIONS=_main,_end_text_input,_stop_controlling_input,_start_controlling_input,_read_from_save_data,_dump_save_data,_is_receiving_text_input^
-sEXPORTED_RUNTIME_METHODS=ccall,cwrap^ -sEXPORTED_RUNTIME_METHODS=ccall,cwrap^
-s USE_WEBGL2=1^
-s INITIAL_MEMORY=62914560^ -s INITIAL_MEMORY=62914560^
-s ALLOW_MEMORY_GROWTH -s TOTAL_STACK=15728640^ -s ALLOW_MEMORY_GROWTH -s TOTAL_STACK=15728640^
%FLAGS%^ %FLAGS%^

@ -10,25 +10,16 @@ set FLAGS=-O0 -g -DDEVTOOLS
set OUTPUT_FOLDER=build_web set OUTPUT_FOLDER=build_web
if "%1" == "NO_VALIDATION" ( call build_web_common.bat %* || goto :error
echo Disabling graphics validation...
set FLAGS=%FLAGS% -DNDEBUG
)
call build_web_common.bat || goto :error
@echo off @echo off
if "%1" == "NO_VALIDATION" (
echo Validation turned off
) else (
echo If you want to turn graphics validation off to make web debug build faster, provide a command line argument called "NO_VALIDATION" to this build script
)
goto :success goto :success
:error :error
echo Failed to build echo Failed to build
:success :success
set "returncode=%ERRORLEVEL%"
popd popd
exit /B %ERRORLEVEL% exit /B %returncode%

@ -5,17 +5,17 @@ pushd %~dp0%
rmdir /S /q build_web_release rmdir /S /q build_web_release
mkdir build_web_release mkdir build_web_release
call run_codegen.bat || goto :error
set FLAGS=-O0 -DNDEBUG set FLAGS=-O0 -DNDEBUG
set OUTPUT_FOLDER=build_web_release set OUTPUT_FOLDER=build_web_release
call build_web_common.bat || goto :error call build_web_common.bat %* codegen || goto :error
goto :success goto :success
:error :error
echo Failed to build echo Failed to build
:success :success
set "returncode=%ERRORLEVEL%"
popd popd
exit /B %ERRORLEVEL% exit /B %returncode%

@ -29,6 +29,11 @@ ActionInfo actions[] = {
.description = "Do nothing", .description = "Do nothing",
NO_ARGUMENT, NO_ARGUMENT,
}, },
{
.name = "approach",
.description = "There has been an error, please report to the developer. No NPCs should be able to do this",
ARGUMENT("Expects the argument to be who you're approaching"),
},
{ {
.name = "join", .name = "join",
.description = "Joins somebody else's party, so you follow them everywhere", .description = "Joins somebody else's party, so you follow them everywhere",
@ -101,4 +106,9 @@ CharacterGen characters[] = {
.enum_name = "Passerby", .enum_name = "Passerby",
.prompt = CHARACTER_PROMPT_PREFIX("Random Passerby") "random person, just passing by", .prompt = CHARACTER_PROMPT_PREFIX("Random Passerby") "random person, just passing by",
}, },
{
.name = "Angel",
.enum_name = "Angel",
.prompt = CHARACTER_PROMPT_PREFIX("Angel") "mysterious, radiant, mystical creature the player first talks to. You guide the entire game: deciding on an objective for the player to fulfill until you believe they've learned their lesson, whatever that means to them.",
},
}; };

363
main.c

@ -21,11 +21,13 @@
#define DESKTOP #define DESKTOP
#define WINDOWS #define WINDOWS
#define SOKOL_GLCORE33 #define SOKOL_GLCORE33
#define SAMPLE_COUNT 4
#endif #endif
#if defined(__EMSCRIPTEN__) #if defined(__EMSCRIPTEN__)
#define WEB #define WEB
#define SOKOL_GLES2 #define SOKOL_GLES3
#define SAMPLE_COUNT 4
#endif #endif
#define DRWAV_ASSERT game_assert #define DRWAV_ASSERT game_assert
@ -41,8 +43,6 @@
#pragma warning(push, 3) #pragma warning(push, 3)
#include <Windows.h> #include <Windows.h>
#include <processthreadsapi.h>
#include <dbghelp.h>
#include <stdint.h> #include <stdint.h>
// https://developer.download.nvidia.com/devzone/devcenter/gamegraphics/files/OptimusRenderingPolicies.pdf // https://developer.download.nvidia.com/devzone/devcenter/gamegraphics/files/OptimusRenderingPolicies.pdf
@ -53,13 +53,15 @@ __declspec(dllexport) uint32_t AmdPowerXpressRequestHighPerformance = 0x00000001
#endif #endif
#define STRINGIZE(x) STRINGIZE2(x)
#define STRINGIZE2(x) #x
#include "buff.h" #include "buff.h"
#include "sokol_app.h" #include "sokol_app.h"
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4191) // unsafe function calling #pragma warning(disable : 4191) // unsafe function calling
#ifdef WEB
# include <GLES3/gl3.h>
# undef glGetError
# define glGetError() (GL_NO_ERROR)
#endif
#include "sokol_gfx.h" #include "sokol_gfx.h"
#pragma warning(pop) #pragma warning(pop)
#include "sokol_time.h" #include "sokol_time.h"
@ -365,6 +367,7 @@ float float_rand(float min, float max)
float scale = rand() / (float) RAND_MAX; /* [0, 1.0] */ float scale = rand() / (float) RAND_MAX; /* [0, 1.0] */
return min + scale * (max - min); /* [min, max] */ return min + scale * (max - min); /* [min, max] */
} }
// always randomizes pitch
void play_audio(AudioSample *sample, float volume) void play_audio(AudioSample *sample, float volume)
{ {
AudioPlayer *to_use = 0; AudioPlayer *to_use = 0;
@ -466,6 +469,7 @@ LPCWSTR windows_string(MD_String8 s)
#ifdef DESKTOP #ifdef DESKTOP
#ifdef WINDOWS #ifdef WINDOWS
#pragma warning(push, 3) #pragma warning(push, 3)
#pragma comment(lib, "WinHttp")
#include <WinHttp.h> #include <WinHttp.h>
#include <process.h> #include <process.h>
#pragma warning(pop) #pragma warning(pop)
@ -835,18 +839,15 @@ sg_image load_image(MD_String8 path)
{ {
.width = png_width, .width = png_width,
.height = png_height, .height = png_height,
.pixel_format = SG_PIXELFORMAT_RGBA8, .pixel_format = sapp_sgcontext().color_format,
.min_filter = SG_FILTER_LINEAR,
.num_mipmaps = 1, .num_mipmaps = 1,
.wrap_u = SG_WRAP_CLAMP_TO_EDGE,
.wrap_v = SG_WRAP_CLAMP_TO_EDGE,
.mag_filter = SG_FILTER_LINEAR,
.data.subimage[0][0] = .data.subimage[0][0] =
{ {
.ptr = pixels, .ptr = pixels,
.size = (size_t)(png_width * png_height * num_channels), .size = (size_t)(png_width * png_height * num_channels),
} }
}); });
loaded->image = to_return; loaded->image = to_return;
MD_ReleaseScratch(scratch); MD_ReleaseScratch(scratch);
return to_return; return to_return;
@ -1225,14 +1226,6 @@ Armature load_armature(MD_Arena *arena, MD_String8 binary_file, MD_String8 armat
.width = to_return.bones_texture_width, .width = to_return.bones_texture_width,
.height = to_return.bones_texture_height, .height = to_return.bones_texture_height,
.pixel_format = SG_PIXELFORMAT_RGBA8, .pixel_format = SG_PIXELFORMAT_RGBA8,
.min_filter = SG_FILTER_NEAREST,
.mag_filter = SG_FILTER_NEAREST,
// for webgl NPOT texures https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL
.wrap_u = SG_WRAP_CLAMP_TO_EDGE,
.wrap_v = SG_WRAP_CLAMP_TO_EDGE,
.wrap_w = SG_WRAP_CLAMP_TO_EDGE,
.usage = SG_USAGE_STREAM, .usage = SG_USAGE_STREAM,
}); });
@ -2530,7 +2523,7 @@ GameState load_from_string(MD_Arena *arena, MD_Arena *error_arena, MD_String8 da
.arena = temp.arena, .arena = temp.arena,
.error_arena = error_arena, .error_arena = error_arena,
}; };
GameState to_return = {0}; GameState to_return = { 0 };
ser_GameState(&ser, &to_return); ser_GameState(&ser, &to_return);
if(ser.cur_error.failed) if(ser.cur_error.failed)
{ {
@ -2654,26 +2647,34 @@ Shadow_State init_shadow_state();
static struct static struct
{ {
sg_pass_action clear_everything_pass_action; sg_pass_action clear_everything_pass_action;
sg_pass_action threedee_msaa_pass_action;
sg_pass_action clear_depth_buffer_pass_action; sg_pass_action clear_depth_buffer_pass_action;
sg_pipeline twodee_pip; sg_pipeline twodee_pip;
sg_bindings bind; sg_bindings bind;
sg_pipeline threedee_pip; sg_pipeline threedee_pip;
sg_pipeline threedee_alpha_blended_pip;
sg_pipeline armature_pip; sg_pipeline armature_pip;
sg_bindings threedee_bind; sg_bindings threedee_bind;
sg_image outline_pass_image; sg_image outline_pass_image;
sg_image outline_pass_resolve_image;
sg_pass outline_pass; sg_pass outline_pass;
sg_pipeline outline_mesh_pip; sg_pipeline outline_mesh_pip;
sg_pipeline outline_armature_pip; sg_pipeline outline_armature_pip;
sg_pass threedee_pass; // is a pass so I can do post processing in a shader sg_pass threedee_pass; // is a pass so I can do post processing in a shader
sg_image threedee_pass_image; sg_image threedee_pass_image;
sg_image threedee_pass_resolve_image;
sg_image threedee_pass_depth_image; sg_image threedee_pass_depth_image;
sg_pipeline twodee_outline_pip; sg_pipeline twodee_outline_pip;
sg_pipeline twodee_colorcorrect_pip; sg_pipeline twodee_colorcorrect_pip;
sg_sampler sampler_linear;
sg_sampler sampler_linear_border;
sg_sampler sampler_nearest;
Shadow_State shadows; Shadow_State shadows;
} state; } state;
@ -2688,7 +2689,9 @@ void create_screenspace_gfx_state()
MAYBE_DESTROY(state.threedee_pass, sg_destroy_pass); MAYBE_DESTROY(state.threedee_pass, sg_destroy_pass);
MAYBE_DESTROY(state.outline_pass_image, sg_destroy_image); MAYBE_DESTROY(state.outline_pass_image, sg_destroy_image);
MAYBE_DESTROY(state.outline_pass_resolve_image, sg_destroy_image);
MAYBE_DESTROY(state.threedee_pass_image, sg_destroy_image); MAYBE_DESTROY(state.threedee_pass_image, sg_destroy_image);
MAYBE_DESTROY(state.threedee_pass_resolve_image, sg_destroy_image);
MAYBE_DESTROY(state.threedee_pass_depth_image, sg_destroy_image); MAYBE_DESTROY(state.threedee_pass_depth_image, sg_destroy_image);
#undef MAYBE_DESTROY #undef MAYBE_DESTROY
@ -2702,7 +2705,7 @@ void create_screenspace_gfx_state()
.depth = { .depth = {
0 0
}, },
.sample_count = 1, .sample_count = SAMPLE_COUNT,
.layout = { .layout = {
.attrs = .attrs =
{ {
@ -2732,7 +2735,7 @@ void create_screenspace_gfx_state()
.depth = { .depth = {
.pixel_format = SG_PIXELFORMAT_NONE, .pixel_format = SG_PIXELFORMAT_NONE,
}, },
.sample_count = 1, .sample_count = SAMPLE_COUNT,
.layout = { .layout = {
.attrs = .attrs =
{ {
@ -2758,18 +2761,17 @@ void create_screenspace_gfx_state()
.render_target = true, .render_target = true,
.width = sapp_width(), .width = sapp_width(),
.height = sapp_height(), .height = sapp_height(),
.pixel_format = SG_PIXELFORMAT_RGBA8, .pixel_format = sapp_sgcontext().color_format,
.min_filter = SG_FILTER_LINEAR,
.mag_filter = SG_FILTER_LINEAR,
.wrap_u = SG_WRAP_CLAMP_TO_BORDER,
.wrap_v = SG_WRAP_CLAMP_TO_BORDER,
.border_color = SG_BORDERCOLOR_OPAQUE_WHITE,
.sample_count = 1,
.label = "outline-pass-render-target", .label = "outline-pass-render-target",
}; };
desc.sample_count = SAMPLE_COUNT;
state.outline_pass_image = sg_make_image(&desc); state.outline_pass_image = sg_make_image(&desc);
desc.sample_count = 1;
state.outline_pass_resolve_image = sg_make_image(&desc);
state.outline_pass = sg_make_pass(&(sg_pass_desc){ state.outline_pass = sg_make_pass(&(sg_pass_desc){
.color_attachments[0].image = state.outline_pass_image, .color_attachments[0].image = state.outline_pass_image,
.resolve_attachments[0].image = state.outline_pass_resolve_image,
.depth_stencil_attachment = { .depth_stencil_attachment = {
0 0
}, },
@ -2779,14 +2781,21 @@ void create_screenspace_gfx_state()
desc.sample_count = 1; desc.sample_count = 1;
desc.label = "threedee-pass-render-target"; desc.label = "threedee-pass-render-target";
desc.sample_count = SAMPLE_COUNT;
state.threedee_pass_image = sg_make_image(&desc); state.threedee_pass_image = sg_make_image(&desc);
desc.label = "threedee-pass-resolve-render-target";
desc.sample_count = 1;
state.threedee_pass_resolve_image = sg_make_image(&desc);
desc.label = "threedee-pass-depth-render-target"; desc.label = "threedee-pass-depth-render-target";
desc.pixel_format = sapp_depth_format(); desc.pixel_format = SG_PIXELFORMAT_DEPTH;
desc.sample_count = SAMPLE_COUNT;
state.threedee_pass_depth_image = sg_make_image(&desc); state.threedee_pass_depth_image = sg_make_image(&desc);
state.threedee_pass = sg_make_pass(&(sg_pass_desc){ state.threedee_pass = sg_make_pass(&(sg_pass_desc){
.color_attachments[0].image = state.threedee_pass_image, .color_attachments[0].image = state.threedee_pass_image,
.resolve_attachments[0].image = state.threedee_pass_resolve_image,
.depth_stencil_attachment = (sg_pass_attachment_desc){ .depth_stencil_attachment = (sg_pass_attachment_desc){
.image = state.threedee_pass_depth_image, .image = state.threedee_pass_depth_image,
.mip_level = 0, .mip_level = 0,
@ -3006,8 +3015,8 @@ Color blendalpha(Color c, float alpha)
// in pixels // in pixels
Vec2 img_size(sg_image img) Vec2 img_size(sg_image img)
{ {
sg_image_info info = sg_query_image_info(img); sg_image_desc desc = sg_query_image_desc(img);
return V2((float)info.width, (float)info.height); return V2((float)desc.width, (float)desc.height);
} }
#ifdef DEVTOOLS #ifdef DEVTOOLS
@ -3129,8 +3138,6 @@ LoadedFont load_font(MD_Arena *arena, MD_String8 font_filepath, float font_size)
.width = font_bitmap_width, .width = font_bitmap_width,
.height = font_bitmap_width, .height = font_bitmap_width,
.pixel_format = SG_PIXELFORMAT_RGBA8, .pixel_format = SG_PIXELFORMAT_RGBA8,
.min_filter = SG_FILTER_LINEAR,
.mag_filter = SG_FILTER_LINEAR,
.data.subimage[0][0] = .data.subimage[0][0] =
{ {
.ptr = font_bitmap_rgba, .ptr = font_bitmap_rgba,
@ -3158,6 +3165,7 @@ Armature player_armature = {0};
Armature farmer_armature = {0}; Armature farmer_armature = {0};
Armature shifted_farmer_armature = {0}; Armature shifted_farmer_armature = {0};
Armature man_in_black_armature = {0}; Armature man_in_black_armature = {0};
Armature angel_armature = {0};
// armatureanimations are processed once every visual frame from this list // armatureanimations are processed once every visual frame from this list
Armature *armatures[] = { Armature *armatures[] = {
@ -3165,6 +3173,7 @@ Armature *armatures[] = {
&farmer_armature, &farmer_armature,
&shifted_farmer_armature, &shifted_farmer_armature,
&man_in_black_armature, &man_in_black_armature,
&angel_armature,
}; };
Mesh mesh_player = {0}; Mesh mesh_player = {0};
@ -3205,6 +3214,7 @@ void init(void)
sg_setup(&(sg_desc) { sg_setup(&(sg_desc) {
.context = sapp_sgcontext(), .context = sapp_sgcontext(),
.buffer_pool_size = 512, .buffer_pool_size = 512,
.logger.func = slog_func,
}); });
stm_setup(); stm_setup();
saudio_setup(&(saudio_desc) { saudio_setup(&(saudio_desc) {
@ -3232,6 +3242,9 @@ void init(void)
man_in_black_armature = load_armature(persistent_arena, binary_file, MD_S8Lit("Man In Black")); man_in_black_armature = load_armature(persistent_arena, binary_file, MD_S8Lit("Man In Black"));
man_in_black_armature.image = image_man_in_black; man_in_black_armature.image = image_man_in_black;
angel_armature = load_armature(persistent_arena, binary_file, MD_S8Lit("Angel"));
angel_armature.image = image_angel;
binary_file = MD_LoadEntireFile(frame_arena, MD_S8Lit("assets/exported_3d/Farmer.bin")); binary_file = MD_LoadEntireFile(frame_arena, MD_S8Lit("assets/exported_3d/Farmer.bin"));
farmer_armature = load_armature(persistent_arena, binary_file, MD_S8Lit("Farmer.bin")); farmer_armature = load_armature(persistent_arena, binary_file, MD_S8Lit("Farmer.bin"));
@ -3362,29 +3375,38 @@ void init(void)
assert(desc); assert(desc);
shd = sg_make_shader(desc); shd = sg_make_shader(desc);
state.threedee_pip = sg_make_pipeline(&(sg_pipeline_desc){ {
sg_pipeline_desc threedee_pip_desc = {
.shader = shd, .shader = shd,
.layout = {.attrs = { .layout = {.attrs = {
[ATTR_threedee_vs_pos_in].format = SG_VERTEXFORMAT_FLOAT3, [ATTR_threedee_vs_pos_in].format = SG_VERTEXFORMAT_FLOAT3,
[ATTR_threedee_vs_uv_in].format = SG_VERTEXFORMAT_FLOAT2, [ATTR_threedee_vs_uv_in].format = SG_VERTEXFORMAT_FLOAT2,
}}, }},
.depth = { .depth = {
.pixel_format = sapp_depth_format(), .pixel_format = SG_PIXELFORMAT_DEPTH,
.compare = SG_COMPAREFUNC_LESS_EQUAL, .compare = SG_COMPAREFUNC_LESS_EQUAL,
.write_enabled = true, .write_enabled = true,
}, },
.colors[0].blend = (sg_blend_state){ .alpha_to_coverage_enabled = true,
.sample_count = SAMPLE_COUNT,
.colors[0].blend.enabled = false,
.label = "threedee",
};
state.threedee_pip = sg_make_pipeline(&threedee_pip_desc);
threedee_pip_desc.depth.write_enabled = false;
threedee_pip_desc.alpha_to_coverage_enabled = false;
threedee_pip_desc.colors[0].blend = (sg_blend_state){
// allow transparency // allow transparency
.enabled = true, .enabled = true,
.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA, .src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA,
.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, .dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
.op_rgb = SG_BLENDOP_ADD, .op_rgb = SG_BLENDOP_ADD,
.src_factor_alpha = SG_BLENDFACTOR_ONE, .src_factor_alpha = SG_BLENDFACTOR_SRC_ALPHA,
.dst_factor_alpha = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, .dst_factor_alpha = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
.op_alpha = SG_BLENDOP_ADD, .op_alpha = SG_BLENDOP_ADD,
}, },
.label = "threedee", state.threedee_alpha_blended_pip = sg_make_pipeline(&threedee_pip_desc);
}); }
desc = threedee_armature_shader_desc(sg_query_backend()); desc = threedee_armature_shader_desc(sg_query_backend());
assert(desc); assert(desc);
@ -3394,10 +3416,11 @@ void init(void)
{ {
.shader = shd, .shader = shd,
.depth = { .depth = {
.pixel_format = sapp_depth_format(), .pixel_format = SG_PIXELFORMAT_DEPTH,
.compare = SG_COMPAREFUNC_LESS_EQUAL, .compare = SG_COMPAREFUNC_LESS_EQUAL,
.write_enabled = true .write_enabled = true
}, },
.sample_count = SAMPLE_COUNT,
.layout = { .layout = {
.attrs = .attrs =
{ {
@ -3421,11 +3444,45 @@ void init(void)
state.clear_depth_buffer_pass_action = (sg_pass_action) state.clear_depth_buffer_pass_action = (sg_pass_action)
{ {
.colors[0] = { .action = SG_ACTION_LOAD }, .colors[0] = { .load_action = SG_LOADACTION_LOAD },
.depth = { .action = SG_ACTION_CLEAR, .value = 1.0f }, .depth = { .load_action = SG_LOADACTION_CLEAR, .clear_value = 1.0f },
}; };
state.clear_everything_pass_action = state.clear_depth_buffer_pass_action; state.clear_everything_pass_action = state.clear_depth_buffer_pass_action;
state.clear_everything_pass_action.colors[0] = (sg_color_attachment_action){ .action = SG_ACTION_CLEAR, .value = { clearcol.r, clearcol.g, clearcol.b, 1.0f } }; state.clear_everything_pass_action.colors[0] = (sg_color_attachment_action){ .load_action = SG_LOADACTION_CLEAR, .clear_value = { clearcol.r, clearcol.g, clearcol.b, 1.0f } };
state.threedee_msaa_pass_action = state.clear_everything_pass_action;
state.threedee_msaa_pass_action.colors[0].load_action = SG_LOADACTION_CLEAR;
state.threedee_msaa_pass_action.colors[0].store_action = SG_STOREACTION_DONTCARE;
state.sampler_linear = sg_make_sampler(&(sg_sampler_desc) {
.min_filter = SG_FILTER_LINEAR,
.mag_filter = SG_FILTER_LINEAR,
// .mipmap_filter = SG_FILTER_LINEAR,
.wrap_u = SG_WRAP_CLAMP_TO_EDGE,
.wrap_v = SG_WRAP_CLAMP_TO_EDGE,
// .max_anisotropy = 16,
.label = "sampler-linear",
});
state.sampler_linear_border = sg_make_sampler(&(sg_sampler_desc) {
.min_filter = SG_FILTER_LINEAR,
.mag_filter = SG_FILTER_LINEAR,
.wrap_u = SG_WRAP_CLAMP_TO_BORDER,
.wrap_v = SG_WRAP_CLAMP_TO_BORDER,
.border_color = SG_BORDERCOLOR_OPAQUE_WHITE,
.label = "sampler-linear-border",
});
state.sampler_nearest = sg_make_sampler(&(sg_sampler_desc) {
.min_filter = SG_FILTER_NEAREST,
.mag_filter = SG_FILTER_NEAREST,
// for webgl NPOT texures https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL
.wrap_u = SG_WRAP_CLAMP_TO_EDGE,
.wrap_v = SG_WRAP_CLAMP_TO_EDGE,
.wrap_w = SG_WRAP_CLAMP_TO_EDGE,
.label = "sampler-nearest",
});
} }
Vec2 screen_size() Vec2 screen_size()
@ -3716,9 +3773,16 @@ void flush_quad_batch()
state.bind.vertex_buffer_offsets[0] = sg_append_buffer(state.bind.vertex_buffers[0], &(sg_range) { cur_batch_data, cur_batch_data_index*sizeof(*cur_batch_data) }); state.bind.vertex_buffer_offsets[0] = sg_append_buffer(state.bind.vertex_buffers[0], &(sg_range) { cur_batch_data, cur_batch_data_index*sizeof(*cur_batch_data) });
state.bind.fs_images[SLOT_threedee_twodee_tex] = cur_batch_image; state.bind.fs.images[SLOT_threedee_twodee_tex] = cur_batch_image; // NOTE that this might get FUCKED if a custom pipeline is provided with more/less texture slots!!!
state.bind.fs.samplers[SLOT_threedee_fs_twodee_smp] = state.sampler_linear; // NOTE that this might get FUCKED if a custom pipeline is provided with more/less sampler slots!!!
sg_apply_bindings(&state.bind); sg_apply_bindings(&state.bind);
cur_batch_params.tex_size = img_size(cur_batch_image); cur_batch_params.tex_size = img_size(cur_batch_image);
cur_batch_params.screen_size = screen_size();
#if defined(SOKOL_GLCORE33) || defined(SOKOL_GLES3)
cur_batch_params.flip_and_swap_rgb = 0;
#else
cur_batch_params.flip_and_swap_rgb = 1;
#endif
sg_apply_uniforms(SG_SHADERSTAGE_FS, SLOT_threedee_twodee_fs_params, &SG_RANGE(cur_batch_params)); sg_apply_uniforms(SG_SHADERSTAGE_FS, SLOT_threedee_twodee_fs_params, &SG_RANGE(cur_batch_params));
cur_batch_params.tex_size = V2(0,0); // unsure if setting the tex_size to something nonzero fucks up the batching so I'm just resetting it back here cur_batch_params.tex_size = V2(0,0); // unsure if setting the tex_size to something nonzero fucks up the batching so I'm just resetting it back here
assert(cur_batch_data_index % FLOATS_PER_VERTEX == 0); assert(cur_batch_data_index % FLOATS_PER_VERTEX == 0);
@ -3731,10 +3795,11 @@ void flush_quad_batch()
typedef enum typedef enum
{ {
LAYER_TILEMAP, LAYER_INVALID,
LAYER_WORLD, LAYER_WORLD,
LAYER_UI, LAYER_UI,
LAYER_UI_FG, LAYER_UI_FG,
LAYER_UI_TEXTINPUT,
LAYER_SCREENSPACE_EFFECTS, LAYER_SCREENSPACE_EFFECTS,
LAYER_LAST LAYER_LAST
@ -3743,9 +3808,11 @@ typedef enum
typedef BUFF(char, 200) StacktraceElem; typedef BUFF(char, 200) StacktraceElem;
typedef BUFF(StacktraceElem, 16) StacktraceInfo; typedef BUFF(StacktraceElem, 16) StacktraceInfo;
#if 0 // #ifdef WINDOWS
#include <dbghelp.h>
#pragma comment(lib, "DbgHelp")
StacktraceInfo get_stacktrace() StacktraceInfo get_stacktrace()
{ {
#ifdef WINDOWS
StacktraceInfo to_return = {0}; StacktraceInfo to_return = {0};
void *stack[ARRLEN(to_return.data)] = {0}; void *stack[ARRLEN(to_return.data)] = {0};
int captured = CaptureStackBackTrace(0, ARRLEN(to_return.data), stack, 0); int captured = CaptureStackBackTrace(0, ARRLEN(to_return.data), stack, 0);
@ -3779,10 +3846,13 @@ StacktraceInfo get_stacktrace()
free(symbol); free(symbol);
} }
return to_return; return to_return;
}
#else #else
StacktraceInfo get_stacktrace()
{
return (StacktraceInfo){0}; return (StacktraceInfo){0};
#endif
} }
#endif
typedef struct DrawParams typedef struct DrawParams
{ {
@ -3965,7 +4035,7 @@ void line(Vec2 from, Vec2 to, float line_width, Color color)
} }
#ifdef DEVTOOLS #ifdef DEVTOOLS
bool show_devtools = true; bool show_devtools = false;
#ifdef PROFILING #ifdef PROFILING
extern bool profiling; extern bool profiling;
#else #else
@ -4204,6 +4274,7 @@ typedef struct TextParams
Color *colors; // color per character, if not null must be array of same length as text Color *colors; // color per character, if not null must be array of same length as text
bool do_clipping; bool do_clipping;
LoadedFont *use_font; // if null, uses default font LoadedFont *use_font; // if null, uses default font
Layer layer;
} TextParams; } TextParams;
// returns bounds. To measure text you can set dry run to true and get the bounds // returns bounds. To measure text you can set dry run to true and get the bounds
@ -4297,7 +4368,12 @@ AABB draw_text(TextParams t)
col = t.colors[i]; col = t.colors[i];
} }
draw_quad((DrawParams) { to_draw, font.image, font_atlas_region, col, t.clip_to, .layer = LAYER_UI_FG, .do_clipping = t.do_clipping }); Layer to_use = LAYER_UI_FG;
if(t.layer != LAYER_INVALID)
{
to_use = t.layer;
}
draw_quad((DrawParams) { to_draw, font.image, font_atlas_region, col, t.clip_to, .layer = to_use, .do_clipping = t.do_clipping });
} }
} }
} }
@ -4815,8 +4891,8 @@ Shadow_State init_shadow_state() {
shadows.pass_action = (sg_pass_action) { shadows.pass_action = (sg_pass_action) {
.colors[0] = { .colors[0] = {
.action = SG_ACTION_CLEAR, .load_action = SG_LOADACTION_CLEAR,
.value = { 1.0f, 1.0f, 1.0f, 1.0f } .clear_value = { 1.0f, 1.0f, 1.0f, 1.0f }
} }
}; };
@ -4826,17 +4902,13 @@ Shadow_State init_shadow_state() {
be pertinent to just dig into sokol and add the functionality we want later, be pertinent to just dig into sokol and add the functionality we want later,
but as a first pass, we will just do as the romans do. I.e. have both a colour but as a first pass, we will just do as the romans do. I.e. have both a colour
and depth component. - Canada Day 2023. and depth component. - Canada Day 2023.
TODO: with GLES3, depth only rendering passes are now supported
*/ */
sg_image_desc img_desc = { sg_image_desc img_desc = {
.render_target = true, .render_target = true,
.width = SHADOW_MAP_DIMENSION, .width = SHADOW_MAP_DIMENSION,
.height = SHADOW_MAP_DIMENSION, .height = SHADOW_MAP_DIMENSION,
.pixel_format = SG_PIXELFORMAT_RGBA8, .pixel_format = sapp_sgcontext().color_format,
.min_filter = SG_FILTER_LINEAR,
.mag_filter = SG_FILTER_LINEAR,
.wrap_u = SG_WRAP_CLAMP_TO_BORDER,
.wrap_v = SG_WRAP_CLAMP_TO_BORDER,
.border_color = SG_BORDERCOLOR_OPAQUE_WHITE,
.sample_count = 1, .sample_count = 1,
.label = "shadow-map-color-image" .label = "shadow-map-color-image"
}; };
@ -4867,7 +4939,7 @@ Shadow_State init_shadow_state() {
.compare = SG_COMPAREFUNC_LESS_EQUAL, .compare = SG_COMPAREFUNC_LESS_EQUAL,
.write_enabled = true, .write_enabled = true,
}, },
.colors[0].pixel_format = SG_PIXELFORMAT_RGBA8, .colors[0].pixel_format = sapp_sgcontext().color_format,
.label = "shadow-map-pipeline" .label = "shadow-map-pipeline"
}; };
@ -4875,7 +4947,7 @@ Shadow_State init_shadow_state() {
desc.label = "armature-shadow-map-pipeline"; desc.label = "armature-shadow-map-pipeline";
desc.shader = sg_make_shader(threedee_armature_shadow_mapping_shader_desc(sg_query_backend())); desc.shader = sg_make_shader(threedee_armature_shadow_mapping_shader_desc(sg_query_backend()));
sg_vertex_attr_desc skeleton_vertex_attrs[] = { sg_vertex_attr_state skeleton_vertex_attrs[] = {
[ATTR_threedee_vs_skeleton_pos_in].format = SG_VERTEXFORMAT_FLOAT3, [ATTR_threedee_vs_skeleton_pos_in].format = SG_VERTEXFORMAT_FLOAT3,
[ATTR_threedee_vs_skeleton_uv_in].format = SG_VERTEXFORMAT_FLOAT2, [ATTR_threedee_vs_skeleton_uv_in].format = SG_VERTEXFORMAT_FLOAT2,
[ATTR_threedee_vs_skeleton_indices_in].format = SG_VERTEXFORMAT_USHORT4N, [ATTR_threedee_vs_skeleton_indices_in].format = SG_VERTEXFORMAT_USHORT4N,
@ -5075,12 +5147,22 @@ void actually_draw_thing(DrawnThing *it, Mat4 light_space_matrix, bool for_outli
{ {
if(for_outline) if(for_outline)
sg_apply_pipeline(state.outline_mesh_pip); sg_apply_pipeline(state.outline_mesh_pip);
else if (it->alpha_blend)
sg_apply_pipeline(state.threedee_alpha_blended_pip);
else else
sg_apply_pipeline(state.threedee_pip); sg_apply_pipeline(state.threedee_pip);
sg_bindings bindings = {0}; sg_bindings bindings = {0};
bindings.fs_images[SLOT_threedee_tex] = it->mesh->image; bindings.fs.images[SLOT_threedee_tex] = it->mesh->image;
if(!for_outline) if(for_outline)
bindings.fs_images[SLOT_threedee_shadow_map] = state.shadows.color_img; {
bindings.fs.samplers[SLOT_threedee_fs_outline_smp] = state.sampler_linear;
}
else
{
bindings.fs.images[SLOT_threedee_shadow_map] = state.shadows.color_img;
bindings.fs.samplers[SLOT_threedee_fs_shadow_smp] = state.sampler_linear_border;
bindings.fs.samplers[SLOT_threedee_fs_smp] = state.sampler_linear;
}
bindings.vertex_buffers[0] = it->mesh->loaded_buffer; bindings.vertex_buffers[0] = it->mesh->loaded_buffer;
sg_apply_bindings(&bindings); sg_apply_bindings(&bindings);
@ -5106,10 +5188,19 @@ void actually_draw_thing(DrawnThing *it, Mat4 light_space_matrix, bool for_outli
else else
sg_apply_pipeline(state.armature_pip); sg_apply_pipeline(state.armature_pip);
sg_bindings bindings = {0}; sg_bindings bindings = {0};
bindings.vs_images[SLOT_threedee_bones_tex] = it->armature->bones_texture; bindings.vs.images[SLOT_threedee_bones_tex] = it->armature->bones_texture;
bindings.fs_images[SLOT_threedee_tex] = it->armature->image; bindings.vs.samplers[SLOT_threedee_vs_skeleton_smp] = state.sampler_nearest;
if(!for_outline) bindings.fs.images[SLOT_threedee_tex] = it->armature->image;
bindings.fs_images[SLOT_threedee_shadow_map] = state.shadows.color_img; if(for_outline)
{
bindings.fs.samplers[SLOT_threedee_fs_outline_smp] = state.sampler_linear;
}
else
{
bindings.fs.images[SLOT_threedee_shadow_map] = state.shadows.color_img;
bindings.fs.samplers[SLOT_threedee_fs_shadow_smp] = state.sampler_linear_border;
bindings.fs.samplers[SLOT_threedee_fs_smp] = state.sampler_linear;
}
bindings.vertex_buffers[0] = it->armature->loaded_buffer; bindings.vertex_buffers[0] = it->armature->loaded_buffer;
sg_apply_bindings(&bindings); sg_apply_bindings(&bindings);
@ -5253,7 +5344,8 @@ void flush_all_drawn_things(Vec3 light_dir, Vec3 cam_pos, Vec3 cam_facing, Vec3
if(it->mesh) if(it->mesh)
{ {
sg_bindings bindings = {0}; sg_bindings bindings = {0};
bindings.fs_images[SLOT_threedee_tex] = it->mesh->image; bindings.fs.images[SLOT_threedee_tex] = it->mesh->image;
bindings.fs.samplers[SLOT_threedee_fs_shadow_mapping_smp] = state.sampler_linear;
bindings.vertex_buffers[0] = it->mesh->loaded_buffer; bindings.vertex_buffers[0] = it->mesh->loaded_buffer;
sg_apply_bindings(&bindings); sg_apply_bindings(&bindings);
@ -5278,8 +5370,10 @@ void flush_all_drawn_things(Vec3 light_dir, Vec3 cam_pos, Vec3 cam_facing, Vec3
if(it->armature) if(it->armature)
{ {
sg_bindings bindings = {0}; sg_bindings bindings = {0};
bindings.vs_images[SLOT_threedee_bones_tex] = it->armature->bones_texture; bindings.vs.images[SLOT_threedee_bones_tex] = it->armature->bones_texture;
bindings.fs_images[SLOT_threedee_tex] = it->armature->image; bindings.vs.samplers[SLOT_threedee_vs_skeleton_smp] = state.sampler_nearest;
bindings.fs.images[SLOT_threedee_tex] = it->armature->image;
bindings.fs.samplers[SLOT_threedee_fs_shadow_mapping_smp] = state.sampler_linear;
bindings.vertex_buffers[0] = it->armature->loaded_buffer; bindings.vertex_buffers[0] = it->armature->loaded_buffer;
sg_apply_bindings(&bindings); sg_apply_bindings(&bindings);
@ -5305,8 +5399,8 @@ void flush_all_drawn_things(Vec3 light_dir, Vec3 cam_pos, Vec3 cam_facing, Vec3
{ {
sg_begin_pass(state.outline_pass, &(sg_pass_action) { sg_begin_pass(state.outline_pass, &(sg_pass_action) {
.colors[0] = { .colors[0] = {
.action = SG_ACTION_CLEAR, .load_action = SG_LOADACTION_CLEAR,
.value = { 0.0f, 0.0f, 0.0f, 0.0f }, .clear_value = { 0.0f, 0.0f, 0.0f, 0.0f },
} }
}); });
@ -5323,7 +5417,7 @@ void flush_all_drawn_things(Vec3 light_dir, Vec3 cam_pos, Vec3 cam_facing, Vec3
// actually draw, IMPORTANT after this drawn_this_frame is zeroed out! // actually draw, IMPORTANT after this drawn_this_frame is zeroed out!
{ {
sg_begin_pass(state.threedee_pass, &state.clear_everything_pass_action); sg_begin_pass(state.threedee_pass, &state.threedee_msaa_pass_action);
// draw meshes // draw meshes
SLICE_ITER(DrawnThing, drawn_this_frame) SLICE_ITER(DrawnThing, drawn_this_frame)
@ -5570,6 +5664,8 @@ void frame(void)
to_use = &farmer_armature; to_use = &farmer_armature;
else if(it->npc_kind == NPC_Raphael) else if(it->npc_kind == NPC_Raphael)
to_use = &man_in_black_armature; to_use = &man_in_black_armature;
else if(it->npc_kind == NPC_Angel)
to_use = &angel_armature;
else else
assert(false); assert(false);
@ -5662,8 +5758,8 @@ void frame(void)
flush_all_drawn_things(light_dir, cam_pos, facing, right); flush_all_drawn_things(light_dir, cam_pos, facing, right);
// draw the 3d render // draw the 3d render
draw_quad((DrawParams){quad_at(V2(0.0, screen_size().y), screen_size()), IMG(state.threedee_pass_image), WHITE, .layer = LAYER_WORLD, .custom_pipeline = state.twodee_colorcorrect_pip }); draw_quad((DrawParams){quad_at(V2(0.0, screen_size().y), screen_size()), IMG(state.threedee_pass_resolve_image), WHITE, .layer = LAYER_WORLD, .custom_pipeline = state.twodee_colorcorrect_pip });
draw_quad((DrawParams){quad_at(V2(0.0, screen_size().y), screen_size()), IMG(state.outline_pass_image), WHITE, .custom_pipeline = state.twodee_outline_pip, .layer = LAYER_UI}); draw_quad((DrawParams){quad_at(V2(0.0, screen_size().y), screen_size()), IMG(state.outline_pass_resolve_image), WHITE, .custom_pipeline = state.twodee_outline_pip, .layer = LAYER_UI});
// 2d drawing TODO move this to when the drawing is flushed. // 2d drawing TODO move this to when the drawing is flushed.
sg_begin_default_pass(&state.clear_depth_buffer_pass_action, sapp_width(), sapp_height()); sg_begin_default_pass(&state.clear_depth_buffer_pass_action, sapp_width(), sapp_height());
@ -5671,15 +5767,15 @@ void frame(void)
// @Place(text input drawing) // @Place(text input drawing)
#ifdef DESKTOP #ifdef DESKTOP
draw_quad((DrawParams){quad_at(V2(0,screen_size().y), screen_size()), IMG(image_white_square), blendalpha(BLACK, text_input_fade*0.3f), .layer = LAYER_UI_FG}); draw_quad((DrawParams){quad_at(V2(0,screen_size().y), screen_size()), IMG(image_white_square), blendalpha(BLACK, text_input_fade*0.3f), .layer = LAYER_UI_TEXTINPUT});
Vec2 edge_of_text = MulV2F(screen_size(), 0.5f); Vec2 edge_of_text = MulV2F(screen_size(), 0.5f);
if(text_input_buffer_length > 0) if(text_input_buffer_length > 0)
{ {
AABB bounds = draw_centered_text((TextParams){false, MD_S8(text_input_buffer, text_input_buffer_length), MulV2F(screen_size(), 0.5f), blendalpha(WHITE, text_input_fade), 1.0f, .use_font = &font_for_text_input}); AABB bounds = draw_centered_text((TextParams){false, MD_S8(text_input_buffer, text_input_buffer_length), MulV2F(screen_size(), 0.5f), blendalpha(WHITE, text_input_fade), 1.0f, .use_font = &font_for_text_input, .layer = LAYER_UI_TEXTINPUT});
edge_of_text = bounds.lower_right; edge_of_text = bounds.lower_right;
} }
Vec2 cursor_center = V2(edge_of_text.x,screen_size().y/2.0f); Vec2 cursor_center = V2(edge_of_text.x,screen_size().y/2.0f);
draw_quad((DrawParams){quad_centered(cursor_center, V2(3.0f, 80.0f)), IMG(image_white_square), blendalpha(WHITE, text_input_fade * (sinf((float)elapsed_time*8.0f)/2.0f + 0.5f)), .layer = LAYER_UI_FG}); draw_quad((DrawParams){quad_centered(cursor_center, V2(3.0f, 80.0f)), IMG(image_white_square), blendalpha(WHITE, text_input_fade * (sinf((float)elapsed_time*8.0f)/2.0f + 0.5f)), .layer = LAYER_UI_TEXTINPUT});
#endif #endif
// Draw Tilemap draw tilemap tilemap drawing // Draw Tilemap draw tilemap tilemap drawing
@ -5877,10 +5973,8 @@ void frame(void)
static bool player_in_combat = false; static bool player_in_combat = false;
float speed_target = 1.0f; float speed_target = 1.0f;
gs.stopped_time = cur_unread_entity != 0; gs.stopped_time = cur_unread_entity != 0 || (!gs.no_angel_screen);
if(gs.stopped_time) speed_target = 0.0f; if(gs.stopped_time) speed_target = 0.0f;
// pausing the game // pausing the game
speed_factor = Lerp(speed_factor, unwarped_dt*10.0f, speed_target); speed_factor = Lerp(speed_factor, unwarped_dt*10.0f, speed_target);
@ -6851,6 +6945,76 @@ ISANERROR("Don't know how to do this stuff on this platform.")
draw_centered_text((TextParams){false, MD_S8Lit("The AI server is having technical difficulties..."), text_center, WHITE, 1.0f }); draw_centered_text((TextParams){false, MD_S8Lit("The AI server is having technical difficulties..."), text_center, WHITE, 1.0f });
} }
// angel screen
gs.no_angel_screen = true;
{
static float visible = 1.0f;
bool should_be_visible = !gs.no_angel_screen;
visible = Lerp(visible, unwarped_dt*2.0f, should_be_visible ? 1.0f : 0.0f);
Entity *angel_entity = 0;
ENTITIES_ITER(gs.entities)
{
if(it->is_npc && it->npc_kind == NPC_Angel)
{
assert(!angel_entity);
angel_entity = it;
}
}
assert(angel_entity);
if(should_be_visible) gs.player->talking_to = frome(angel_entity);
draw_quad((DrawParams) {quad_at(V2(0,screen_size().y), screen_size()), IMG(image_white_square), blendalpha(BLACK, visible), .layer = LAYER_UI_FG});
static MD_String8List to_say = {0};
static double cur_characters = 0;
if(to_say.node_count == 0)
{
to_say = split_by_word(persistent_arena, MD_S8Lit("You've been asleep for a long long time..."));
cur_characters = 0;
}
MD_String8 cur_word = {0};
MD_String8Node *cur_word_node = 0;
double chars_said = cur_characters;
for(MD_String8Node *cur = to_say.first; cur; cur = cur->next)
{
if((int)chars_said < cur->string.size)
{
cur_word = cur->string;
cur_word_node = cur;
break;
}
chars_said -= (double)cur->string.size;
}
if(!cur_word.str)
{
cur_word = to_say.last->string;
cur_word_node = to_say.last;
}
cur_characters += unwarped_dt*ANGEL_CHARACTERS_PER_SEC;
chars_said += unwarped_dt*ANGEL_CHARACTERS_PER_SEC;
if(chars_said > cur_word.size && cur_word_node->next)
{
play_audio(&sound_angel_grunt_0, 1.0f);
}
assert(cur_word_node);
MD_String8Node *prev_next = cur_word_node->next;
cur_word_node->next = 0;
MD_String8 without_unsaid = MD_S8ListJoin(frame_arena, to_say, &(MD_StringJoin){.mid = MD_S8Lit(" ")});
cur_word_node->next = prev_next;
draw_centered_text((TextParams){false, without_unsaid, V2(screen_size().x*0.5f, screen_size().y*0.75f), blendalpha(WHITE, visible), 1.0f, .use_font = &font_for_text_input});
draw_centered_text((TextParams){false, MD_S8Lit("(Press E to speak)"), V2(screen_size().x*0.5f, screen_size().y*0.25f), blendalpha(WHITE, visible*0.5f), 0.8f, .use_font = &font_for_text_input});
if(pressed.interact)
{
begin_text_input();
}
}
// win screen // win screen
{ {
static float visible = 0.0f; static float visible = 0.0f;
@ -6937,7 +7101,7 @@ ISANERROR("Don't know how to do this stuff on this platform.")
{ {
Vec2 depth_size = V2(200.0f, 200.0f); Vec2 depth_size = V2(200.0f, 200.0f);
draw_quad((DrawParams){quad_at(V2(screen_size().x - depth_size.x, screen_size().y), depth_size), IMG(state.shadows.color_img), WHITE, .layer = LAYER_UI_FG}); draw_quad((DrawParams){quad_at(V2(screen_size().x - depth_size.x, screen_size().y), depth_size), IMG(state.shadows.color_img), WHITE, .layer = LAYER_UI_FG});
draw_quad((DrawParams){quad_at(V2(0.0, screen_size().y/2.0f), MulV2F(screen_size(), 0.1f)), IMG(state.outline_pass_image), WHITE, .layer = LAYER_UI_FG}); draw_quad((DrawParams){quad_at(V2(0.0, screen_size().y/2.0f), MulV2F(screen_size(), 0.1f)), IMG(state.outline_pass_resolve_image), WHITE, .layer = LAYER_UI_FG});
Vec3 view_cam_pos = MulM4V4(InvGeneralM4(view), V4(0,0,0,1)).xyz; Vec3 view_cam_pos = MulM4V4(InvGeneralM4(view), V4(0,0,0,1)).xyz;
//if(view_cam_pos.y >= 4.900f) // causes nan if not true... not good... //if(view_cam_pos.y >= 4.900f) // causes nan if not true... not good...
@ -7040,6 +7204,7 @@ ISANERROR("Don't know how to do this stuff on this platform.")
Vec2 *points = d.quad.points; Vec2 *points = d.quad.points;
threedee_twodee_fs_params_t params = { threedee_twodee_fs_params_t params = {
.tint = d.tint, .tint = d.tint,
.time = (float)fmod(elapsed_time, 100),
}; };
params.alpha_clip_threshold = d.alpha_clip_threshold; params.alpha_clip_threshold = d.alpha_clip_threshold;
if (d.do_clipping) if (d.do_clipping)
@ -7098,10 +7263,10 @@ ISANERROR("Don't know how to do this stuff on this platform.")
}; };
// convert to uv space // convert to uv space
sg_image_info info = sg_query_image_info(d.image); sg_image_desc desc = sg_query_image_desc(d.image);
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
tex_coords[i] = DivV2(tex_coords[i], V2((float)info.width, (float)info.height)); tex_coords[i] = DivV2(tex_coords[i], V2((float)desc.width, (float)desc.height));
} }
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
@ -7221,9 +7386,31 @@ void event(const sapp_event *e)
} }
#endif #endif
if (e->type == SAPP_EVENTTYPE_KEY_DOWN && e->key_code == SAPP_KEYCODE_F11) if (e->type == SAPP_EVENTTYPE_KEY_DOWN &&
(e->key_code == SAPP_KEYCODE_F11 ||
e->key_code == SAPP_KEYCODE_ENTER && ((e->modifiers & SAPP_MODIFIER_ALT) || (e->modifiers & SAPP_MODIFIER_SHIFT))))
{ {
#ifdef DESKTOP
sapp_toggle_fullscreen(); sapp_toggle_fullscreen();
#else
EM_ASM({
var elem = document.documentElement;
if (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement)
{
if (document.exitFullscreen) document.exitFullscreen();
else if (document.webkitExitFullscreen) document.webkitExitFullscreen();
else if (document.mozCancelFullScreen) document.mozCancelFullScreen();
else if (document.msExitFullscreen) document.msExitFullscreen();
}
else
{
if (elem.requestFullscreen) elem.requestFullscreen();
else if (elem.webkitRequestFullscreen) elem.webkitRequestFullscreen();
else if (elem.mozRequestFullScreen) elem.mozRequestFullScreen();
else if (elem.msRequestFullscreen) elem.msRequestFullscreen();
}
});
#endif
} }
#ifdef DEVTOOLS #ifdef DEVTOOLS
@ -7447,13 +7634,13 @@ sapp_desc sokol_main(int argc, char* argv[])
.frame_cb = frame, .frame_cb = frame,
.cleanup_cb = cleanup, .cleanup_cb = cleanup,
.event_cb = event, .event_cb = event,
.sample_count = 1, // bumping this back to 4 is troublesome for web, because there's a mismatch in sample counts. Perhaps we must upgrade to gles3, in doing so, we should upgrade to the newest sokol gfx. .sample_count = 1,
.width = 800, .width = 800,
.height = 600, .height = 600,
//.gl_force_gles2 = true, not sure why this was here in example, look into .window_title = "Dante's Cowboy",
.window_title = "RPGPT",
.win32_console_attach = true, .win32_console_attach = true,
.win32_console_create = true, .win32_console_create = true,
.icon.sokol_default = true, .icon.sokol_default = true,
.logger.func = slog_func,
}; };
} }

@ -205,6 +205,11 @@ void chunk_from_s8(TextChunk *into, MD_String8 from)
into->text_length = (int)from.size; into->text_length = (int)from.size;
} }
typedef struct
{
NpcKind who_to_kill;
} GameObjective;
typedef struct Entity typedef struct Entity
{ {
bool exists; bool exists;
@ -284,6 +289,8 @@ typedef struct GameState {
uint64_t tick; uint64_t tick;
bool won; bool won;
bool no_angel_screen;
// processing may still occur after time has stopped on the gamestate, // processing may still occur after time has stopped on the gamestate,
bool stopped_time; bool stopped_time;
@ -365,6 +372,18 @@ MD_String8 make_json_node(MD_Arena *arena, MessageType type, MD_String8 content)
return to_return; return to_return;
} }
MD_String8 npc_to_human_readable(Entity *me, NpcKind kind)
{
if(me->npc_kind == kind)
{
return MD_S8Lit("You");
}
else
{
return MD_S8CString(characters[kind].name);
}
}
// outputs json which is parsed by the server // outputs json which is parsed by the server
MD_String8 generate_chatgpt_prompt(MD_Arena *arena, GameState *gs, Entity *e, CanTalkTo can_talk_to) MD_String8 generate_chatgpt_prompt(MD_Arena *arena, GameState *gs, Entity *e, CanTalkTo can_talk_to)
{ {
@ -427,24 +446,29 @@ MD_String8 generate_chatgpt_prompt(MD_Arena *arena, GameState *gs, Entity *e, Ca
{ {
switch(it->action_taken) switch(it->action_taken)
{ {
#define HUMAN(kind) MD_S8VArg(npc_to_human_readable(e, kind))
case ACT_none: case ACT_none:
break; break;
case ACT_join: case ACT_join:
AddFmt("%s joined %s\n", characters[it->context.author_npc_kind].name, characters[it->action_argument.targeting].name); AddFmt("%.*s joined %.*s\n", HUMAN(it->context.author_npc_kind), HUMAN(it->action_argument.targeting));
break; break;
case ACT_leave: case ACT_leave:
AddFmt("%s left their party\n", characters[it->context.author_npc_kind].name); AddFmt("%.*s left their party\n", HUMAN(it->context.author_npc_kind));
break; break;
case ACT_aim_shotgun: case ACT_aim_shotgun:
AddFmt("%s aimed their shotgun at %s\n", characters[it->context.author_npc_kind].name, characters[it->action_argument.targeting].name); AddFmt("%.*s aimed their shotgun at %.*s\n", HUMAN(it->context.author_npc_kind), HUMAN(it->action_argument.targeting));
break; break;
case ACT_fire_shotgun: case ACT_fire_shotgun:
AddFmt("%s fired their shotgun at %s, brutally murdering them.\n", characters[it->context.author_npc_kind].name, characters[it->action_argument.targeting].name); AddFmt("%.*s fired their shotgun at %.*s, brutally murdering them.\n", HUMAN(it->context.author_npc_kind), HUMAN(it->action_argument.targeting));
break; break;
case ACT_put_shotgun_away: case ACT_put_shotgun_away:
AddFmt("%s holstered their shotgun, no longer threatening anybody\n", characters[it->context.author_npc_kind].name); AddFmt("%.*s holstered their shotgun, no longer threatening anybody\n", HUMAN(it->context.author_npc_kind));
break; break;
} case ACT_approach:
AddFmt("%.*s approached %.*s\n", HUMAN(it->context.author_npc_kind), HUMAN(it->action_argument.targeting));
break;
#undef HUMAN
}
} }
if(it->speech.text_length > 0) if(it->speech.text_length > 0)
{ {

@ -1,22 +1,22 @@
@echo on @echo off
echo Running codegen... @REM echo Running codegen...
if exist gen\ ( if exist gen\ (
echo "Codegen folder already exists, not deleting because that messes with vscode intellisense..." @REM echo "Codegen folder already exists, not deleting because that messes with vscode intellisense..."
) else ( ) else (
mkdir gen mkdir gen
) )
@REM shaders @REM shaders
thirdparty\sokol-shdc.exe --input threedee.glsl --output gen\threedee.glsl.h --slang glsl100:hlsl5:metal_macos:glsl330 || goto :error thirdparty\sokol-shdc.exe --input threedee.glsl --output gen\threedee.glsl.h --slang glsl300es:hlsl5:glsl330 || goto :error
@REM metadesk codegen @REM metadesk codegen
cl /Ithirdparty /W3 /Zi /WX codegen.c || goto :error cl /nologo /diagnostics:caret /Ithirdparty /W3 /Zi /WX codegen.c || goto :error
@REM zig cc -Ithirdparty -gfull -gcodeview codegen.c -o codegen.exe || goto error @REM zig cc -Ithirdparty -gfull -gcodeview codegen.c -o codegen.exe || goto error
codegen || goto :error codegen || goto :error
@REM cl /Ithirdparty /Igen /W3 /Zi /WX maketraining.c || goto :error @REM cl /nologo /diagnostics:caret /Ithirdparty /Igen /W3 /Zi /WX maketraining.c || goto :error
@REM maketraining || goto :error @REM maketraining || goto :error
goto :EOF goto :EOF

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -118,7 +118,6 @@ SOKOL_API_IMPL sg_context_desc sapp_sgcontext(void) {
desc.color_format = (sg_pixel_format) sapp_color_format(); desc.color_format = (sg_pixel_format) sapp_color_format();
desc.depth_format = (sg_pixel_format) sapp_depth_format(); desc.depth_format = (sg_pixel_format) sapp_depth_format();
desc.sample_count = sapp_sample_count(); desc.sample_count = sapp_sample_count();
desc.gl.force_gles2 = sapp_gles2();
desc.metal.device = sapp_metal_get_device(); desc.metal.device = sapp_metal_get_device();
desc.metal.renderpass_descriptor_cb = sapp_metal_get_renderpass_descriptor; desc.metal.renderpass_descriptor_cb = sapp_metal_get_renderpass_descriptor;
desc.metal.drawable_cb = sapp_metal_get_drawable; desc.metal.drawable_cb = sapp_metal_get_drawable;

@ -82,7 +82,8 @@ uniform skeleton_vs_params {
vec2 bones_tex_size; vec2 bones_tex_size;
}; };
uniform sampler2D bones_tex; uniform texture2D bones_tex;
uniform sampler vs_skeleton_smp;
float decode_normalized_float32(vec4 v) float decode_normalized_float32(vec4 v)
{ {
@ -110,7 +111,7 @@ void main() {
{ {
for(int col = 0; col < 4; col++) for(int col = 0; col < 4; col++)
{ {
bone_mat[col][row] = decode_normalized_float32(texture(bones_tex, vec2((0.5 + col*4 + row)/bones_tex_size.x, y_coord))); bone_mat[col][row] = decode_normalized_float32(texture(sampler2D(bones_tex, vs_skeleton_smp), vec2((0.5 + col*4 + row)/bones_tex_size.x, y_coord)));
} }
} }
@ -172,8 +173,10 @@ void main() {
@fs fs @fs fs
uniform sampler2D tex; uniform texture2D tex;
uniform sampler2D shadow_map; uniform texture2D shadow_map;
uniform sampler fs_smp;
uniform samplerShadow fs_shadow_smp;
uniform fs_params { uniform fs_params {
int shadow_map_dimension; int shadow_map_dimension;
@ -193,7 +196,7 @@ float decodeDepth(vec4 rgba) {
return dot(rgba, vec4(1.0, 1.0/255.0, 1.0/65025.0, 1.0/16581375.0)); return dot(rgba, vec4(1.0, 1.0/255.0, 1.0/65025.0, 1.0/16581375.0));
} }
float do_shadow_sample(sampler2D shadowMap, vec2 uv, float scene_depth, float n_dot_l) { float do_shadow_sample(texture2D shadowMap, vec2 uv, float scene_depth, float n_dot_l) {
{ {
//WebGL does not support GL_CLAMP_TO_BORDER, or border colors at all it seems, so we have to check explicitly. //WebGL does not support GL_CLAMP_TO_BORDER, or border colors at all it seems, so we have to check explicitly.
//This will probably slow down other versions which do support texture borders, but the current system does //This will probably slow down other versions which do support texture borders, but the current system does
@ -201,7 +204,7 @@ float do_shadow_sample(sampler2D shadowMap, vec2 uv, float scene_depth, float n_
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0)
return 1.0; return 1.0;
} }
float map_depth = decodeDepth(texture(shadowMap, uv)); float map_depth = decodeDepth(texture(sampler2D(shadowMap, fs_shadow_smp), uv));
// float bias = max(0.03f * (1.0f - n_dot_l), 0.005f); // float bias = max(0.03f * (1.0f - n_dot_l), 0.005f);
// bias = clamp(bias, 0.0, 0.01); // bias = clamp(bias, 0.0, 0.01);
@ -216,7 +219,7 @@ float do_shadow_sample(sampler2D shadowMap, vec2 uv, float scene_depth, float n_
} }
float bilinear_shadow_sample(sampler2D shadowMap, vec2 uv, int texture_width, int texture_height, float scene_depth_light_space, float n_dot_l) { float bilinear_shadow_sample(texture2D shadowMap, vec2 uv, int texture_width, int texture_height, float scene_depth_light_space, float n_dot_l) {
vec2 texture_dim = vec2(float(texture_width), float(texture_height)); vec2 texture_dim = vec2(float(texture_width), float(texture_height));
vec2 texel_dim = vec2(1.0 / float(texture_width ), 1.0 / float(texture_height)); vec2 texel_dim = vec2(1.0 / float(texture_width ), 1.0 / float(texture_height));
@ -244,7 +247,7 @@ float bilinear_shadow_sample(sampler2D shadowMap, vec2 uv, int texture_width, in
return result; return result;
} }
float calculate_shadow_factor(sampler2D shadowMap, vec4 light_space_fragment_position, float n_dot_l) { float calculate_shadow_factor(texture2D shadowMap, vec4 light_space_fragment_position, float n_dot_l) {
float shadow = 1.0; float shadow = 1.0;
vec3 projected_coords = light_space_fragment_position.xyz / light_space_fragment_position.w; vec3 projected_coords = light_space_fragment_position.xyz / light_space_fragment_position.w;
@ -275,7 +278,7 @@ float calculate_shadow_factor(sampler2D shadowMap, vec4 light_space_fragment_pos
} }
void main() { void main() {
vec4 col = texture(tex, uv); vec4 col = texture(sampler2D(tex, fs_smp), uv);
bool alpha_blend = bool(alpha_blend_int); bool alpha_blend = bool(alpha_blend_int);
@ -292,11 +295,6 @@ void main() {
//col.rgb = vec3(desertness, 0, 0); //col.rgb = vec3(desertness, 0, 0);
if(col.a < 0.1 && !alpha_blend)
{
discard;
}
else
{ {
vec3 normal = normalize(cross(dFdx(world_space_frag_pos.xyz), dFdy(world_space_frag_pos.xyz))); vec3 normal = normalize(cross(dFdx(world_space_frag_pos.xyz), dFdy(world_space_frag_pos.xyz)));
@ -307,23 +305,21 @@ void main() {
float lighting_factor = shadow_factor * n_dot_l; float lighting_factor = shadow_factor * n_dot_l;
lighting_factor = lighting_factor * 0.5 + 0.5; lighting_factor = lighting_factor * 0.5 + 0.5;
if(alpha_blend) if (!alpha_blend)
{
frag_color = vec4(col.rgb*lighting_factor, col.a);
}
else
{ {
frag_color = vec4(col.rgb*lighting_factor, 1.0); float _Cutoff = 0.75; // Change this! it is tuned for existing bushes and TreeLayer leaves 2023-08-23
col.a = (col.a - _Cutoff) / max(fwidth(col.a), 0.0001) + 0.5;
} }
//frag_color = vec4(col.rgb, 1.0);
frag_color = vec4(col.rgb*lighting_factor, col.a);
} }
} }
@end @end
@fs fs_shadow_mapping @fs fs_shadow_mapping
uniform sampler2D tex; uniform texture2D tex;
uniform sampler fs_shadow_mapping_smp;
in vec3 pos; in vec3 pos;
in vec2 uv; in vec2 uv;
@ -341,7 +337,7 @@ vec4 encodeDepth(float v) {
} }
void main() { void main() {
vec4 col = texture(tex, uv); vec4 col = texture(sampler2D(tex, fs_shadow_mapping_smp), uv);
if(col.a < 0.5) if(col.a < 0.5)
{ {
discard; discard;
@ -366,7 +362,9 @@ void main() {
@end @end
@fs fs_twodee @fs fs_twodee
uniform sampler2D twodee_tex; uniform texture2D twodee_tex;
uniform sampler fs_twodee_smp;
uniform twodee_fs_params { uniform twodee_fs_params {
vec4 tint; vec4 tint;
@ -375,8 +373,12 @@ uniform twodee_fs_params {
vec2 clip_lr; vec2 clip_lr;
float alpha_clip_threshold; float alpha_clip_threshold;
float time;
vec2 tex_size; vec2 tex_size;
vec2 screen_size;
float flip_and_swap_rgb;
}; };
in vec2 uv; in vec2 uv;
@ -387,7 +389,10 @@ out vec4 frag_color;
void main() { void main() {
// clip space is from [-1,1] [left, right]of screen on X, and [-1,1] [bottom, top] of screen on Y // clip space is from [-1,1] [left, right]of screen on X, and [-1,1] [bottom, top] of screen on Y
if(pos.x < clip_ul.x || pos.x > clip_lr.x || pos.y < clip_lr.y || pos.y > clip_ul.y) discard; if(pos.x < clip_ul.x || pos.x > clip_lr.x || pos.y < clip_lr.y || pos.y > clip_ul.y) discard;
frag_color = texture(twodee_tex, uv) * tint; vec2 real_uv = uv;
if (flip_and_swap_rgb > 0) real_uv.y = 1 - real_uv.y;
frag_color = texture(sampler2D(twodee_tex, fs_twodee_smp), real_uv) * tint;
if (flip_and_swap_rgb > 0) frag_color.rgb = frag_color.bgr;
if(frag_color.a <= alpha_clip_threshold) if(frag_color.a <= alpha_clip_threshold)
{ {
discard; discard;
@ -397,7 +402,9 @@ void main() {
@end @end
@fs fs_twodee_outline @fs fs_twodee_outline
uniform sampler2D twodee_tex; uniform texture2D twodee_tex;
uniform sampler fs_twodee_outline_smp;
uniform twodee_fs_params { uniform twodee_fs_params {
vec4 tint; vec4 tint;
@ -406,8 +413,12 @@ uniform twodee_fs_params {
vec2 clip_lr; vec2 clip_lr;
float alpha_clip_threshold; float alpha_clip_threshold;
float time;
vec2 tex_size; vec2 tex_size;
vec2 screen_size;
float flip_and_swap_rgb;
}; };
in vec2 uv; in vec2 uv;
@ -419,30 +430,44 @@ void main() {
// clip space is from [-1,1] [left, right]of screen on X, and [-1,1] [bottom, top] of screen on Y // clip space is from [-1,1] [left, right]of screen on X, and [-1,1] [bottom, top] of screen on Y
if(pos.x < clip_ul.x || pos.x > clip_lr.x || pos.y < clip_lr.y || pos.y > clip_ul.y) discard; if(pos.x < clip_ul.x || pos.x > clip_lr.x || pos.y < clip_lr.y || pos.y > clip_ul.y) discard;
float left = texture(twodee_tex, uv + vec2(-1, 0)/tex_size).a; vec2 real_uv = uv;
float right = texture(twodee_tex, uv + vec2(1, 0)/tex_size).a; if (flip_and_swap_rgb > 0) real_uv.y = 1 - real_uv.y;
float up = texture(twodee_tex, uv + vec2(0, 1)/tex_size).a;
float down = texture(twodee_tex, uv + vec2(0, -1)/tex_size).a; // 5-tap tent filter: centre, left, right, up, down
float c = texture(sampler2D(twodee_tex, fs_twodee_outline_smp), real_uv).a;
if( float l = texture(sampler2D(twodee_tex, fs_twodee_outline_smp), real_uv + vec2(-1, 0)/tex_size).a;
false float r = texture(sampler2D(twodee_tex, fs_twodee_outline_smp), real_uv + vec2(+1, 0)/tex_size).a;
|| left > 0.1 && right < 0.1 float u = texture(sampler2D(twodee_tex, fs_twodee_outline_smp), real_uv + vec2(0, +1)/tex_size).a;
|| left < 0.1 && right > 0.1 float d = texture(sampler2D(twodee_tex, fs_twodee_outline_smp), real_uv + vec2(0, -1)/tex_size).a;
|| up < 0.1 && down > 0.1
|| up > 0.1 && down < 0.1 // if centre pixel is ~1, it is inside a shape.
) // if centre pixel is ~0, it is outside a shape.
{ // if it is in the middle, it is near an MSAA-resolved edge.
frag_color = vec4(1.0); // we parallel-compute the inside AND outside glows, and then lerp using c.
} float lerp_t = c;
else
{ // buffer is linear-space to be ACES-corrected later, but MSAA happens in gamma space;
frag_color = vec4(0.0); // I want a gamma-space blend; so I cheaply do pow(x, 2) by computing x*x.
} c *= c; l *= l; r *= r; u *= u; d *= d;
float accum_o = (c + l + r + u + d);
float accum_i = 5 - (c + l + r + u + d);
accum_o = 0.3 * accum_o;
accum_i = 0.3 * accum_i;
accum_o = clamp(accum_o, 0, 1);
accum_i = clamp(accum_i, 0, 1);
accum_o = sqrt(accum_o); // cheap gamma-undo
accum_i = sqrt(accum_i); // cheap gamma-undo
float accum = mix(accum_o, accum_i, lerp_t);
frag_color = vec4(1, 1, 1, accum);
} }
@end @end
@fs fs_twodee_color_correction @fs fs_twodee_color_correction
uniform sampler2D twodee_tex; uniform texture2D twodee_tex;
uniform sampler fs_twodee_color_correction_smp;
uniform twodee_fs_params { uniform twodee_fs_params {
vec4 tint; vec4 tint;
@ -451,8 +476,12 @@ uniform twodee_fs_params {
vec2 clip_lr; vec2 clip_lr;
float alpha_clip_threshold; float alpha_clip_threshold;
float time;
vec2 tex_size; vec2 tex_size;
vec2 screen_size;
float flip_and_swap_rgb;
}; };
in vec2 uv; in vec2 uv;
@ -473,10 +502,32 @@ void main() {
// clip space is from [-1,1] [left, right]of screen on X, and [-1,1] [bottom, top] of screen on Y // clip space is from [-1,1] [left, right]of screen on X, and [-1,1] [bottom, top] of screen on Y
if(pos.x < clip_ul.x || pos.x > clip_lr.x || pos.y < clip_lr.y || pos.y > clip_ul.y) discard; if(pos.x < clip_ul.x || pos.x > clip_lr.x || pos.y < clip_lr.y || pos.y > clip_ul.y) discard;
vec4 col = texture(twodee_tex, uv); vec2 real_uv = uv;
if (flip_and_swap_rgb > 0) real_uv.y = 1 - real_uv.y;
vec4 col = texture(sampler2D(twodee_tex, fs_twodee_color_correction_smp), real_uv);
if (flip_and_swap_rgb > 0) col.rgb = col.bgr;
col.rgb = acesFilm(col.rgb); col.rgb = acesFilm(col.rgb);
// Film grain
vec2 grain_uv = gl_FragCoord.xy / screen_size.xy;
float x = grain_uv.x * grain_uv.y * time * 24 + 100.0;
vec3 noise = vec3(mod((mod(x, 13.0) + 1.0) * (mod(x, 123.0) + 1.0), 0.01)) * 100.0;
col.rgb += (noise - 0.5) * 0.05;
col.rgb *= 0.95;
// Hard-clip contrast levels
float min = 11; float max = 204;
col.rgb -= min/255;
col.rgb *= 255/(max-min);
// Vignette
col.rgb *= clamp(1.5 - length(gl_FragCoord.xy / screen_size.xy - vec2(0.5)), 0, 1);
// Cross-process
float cross_process_strength = 0.5;
col.rg *= (col.rg * ((-cross_process_strength) * col.rg + (-1.5 * (-cross_process_strength))) + (0.5 * (-cross_process_strength) + 1));
col.b *= (col.b * ((+cross_process_strength) * col.b + (-1.5 * (+cross_process_strength))) + (0.5 * (+cross_process_strength) + 1));
col.rgb = clamp(col.rgb, 0, 1);
frag_color = col; frag_color = col;
} }
@end @end
@ -484,7 +535,8 @@ void main() {
@fs fs_outline @fs fs_outline
uniform sampler2D tex; uniform texture2D tex;
uniform sampler fs_outline_smp;
in vec3 pos; in vec3 pos;
in vec2 uv; in vec2 uv;
@ -495,7 +547,7 @@ in vec4 world_space_frag_pos;
out vec4 frag_color; out vec4 frag_color;
void main() { void main() {
vec4 col = texture(tex, uv); vec4 col = texture(sampler2D(tex, fs_outline_smp), uv);
if(col.a < 0.5) if(col.a < 0.5)
{ {
discard; discard;

@ -1,9 +1,29 @@
Urgent: Urgent:
- REALLY look into characters not being able to shoot eachother
- Tag memories from drama as permanent so they're never forgotten and always seed character behavior - Tag memories from drama as permanent so they're never forgotten and always seed character behavior
- gman character that gives you randomized goals such as (kill so and so) or (befriend blank) or (get john to go to other room), and decides itself with gpt when you're done with the game, when you've 'learned your lesson'. - gman character that gives you randomized goals such as (kill so and so) or (befriend blank) or (get john to go to other room), and decides itself with gpt when you're done with the game, when you've 'learned your lesson'.
- room system where characters can go to rooms. camera constrained to room bounds, and know which rooms are near them to go to - room system where characters can go to rooms. camera constrained to room bounds, and know which rooms are near them to go to
- make them understand they're holding their shotgun more
- Fix everything about the shotgun, put shotgun away
- can't interact with characters while they're thinking
- fix stencil image being resized working
- bubbles collide with eachother so they can't overlap
- set the game in oregon (suggestion by phillip)
- nocodegen instead of codegen argument
- camera pans to who is speaking and acting
- E keyboard hints (tutorializing)
- dot dot dot speech bubble to show that they heard your request, but are ignoring you.
Long distance: Long distance:
- Design character creator - Design character creator
- Let ChatGPT file bug reports with something like !BugReport(This shouldn't be happening, developer. I killed them and they're still alive)
- Cylindrical colliders for the people
- System where I can upload any AI interaction into gpt playground and inspect the conversation - System where I can upload any AI interaction into gpt playground and inspect the conversation
- Incrementally higher resolution system for all textures, configured in a #define. Also flips the images at build time - Incrementally higher resolution system for all textures, configured in a #define. Also flips the images at build time
- Stop time when you talk to people
- Much higher move accel, almost instantaneously goes to
- Imgui Button doesn't move enough when highlighted
- Higher res text instead of text scaling
- Make space and shift also interact
- Maybe walk by default and shift to run

@ -6,6 +6,7 @@
#define PLAYER_SPEED 0.15f // in meters per second #define PLAYER_SPEED 0.15f // in meters per second
#define PERCEPTION_HEARING_RAGE (TILE_SIZE*4.0f) #define PERCEPTION_HEARING_RAGE (TILE_SIZE*4.0f)
#define CHARACTERS_PER_SEC 45.0f #define CHARACTERS_PER_SEC 45.0f
#define ANGEL_CHARACTERS_PER_SEC 35.0f
#define PROPAGATE_ACTIONS_RADIUS 10.0f #define PROPAGATE_ACTIONS_RADIUS 10.0f
#define SWORD_SWIPE_RADIUS (TILE_SIZE*3.0f) #define SWORD_SWIPE_RADIUS (TILE_SIZE*3.0f)
#define ARROW_SPEED 200.0f #define ARROW_SPEED 200.0f

@ -1,43 +1,24 @@
#pragma once #pragma once
#include <stdio.h> #include <stdio.h>
#include <stdbool.h>
#ifdef WEB #define STRINGIZE(x) STRINGIZE2(x)
#include <signal.h> #define STRINGIZE2(x) #x
#define game_debugbreak() raise(SIGTRAP)
#define game_assert_4127_push
#define game_assert_4127_pop
#ifdef WEB
#define assert_impl(cond, str) ((cond) || (EM_ASM({ assert(0, UTF8ToString($0) + UTF8ToString($1)); }, (__func__), (str)), 0))
#elif defined(DESKTOP) #elif defined(DESKTOP)
#define game_debugbreak() __debugbreak() #define assert_impl(cond, str) ((cond) || (fputs("Assertion failed: " __FUNCTION__ str "\n", stderr), __debugbreak(), 0))
#define game_assert_4127_push __pragma(warning(push)) __pragma(warning(disable:4127))
#define game_assert_4127_pop __pragma(warning(pop))
#else #else
#error "Don't know how to assert for current platform configuration" #error "Don't know how to assert for current platform configuration"
#define game_debugbreak() (void)(0)
#endif #endif
static void assert_impl(const char *func, const char *file, long line, const char *expression)
{
fprintf(stderr, "Assert fail in %s(%s:%ld):\n \"%s\"\n", func, file, line, expression);
}
#ifdef NDEBUG #ifdef NDEBUG
#define game_assert(cond) game_assert_4127_push do { (void)0; } while (0) game_assert_4127_pop #define game_assert(cond) ((void)0)
#else #else
#define game_assert(cond) game_assert_4127_push do { \ #define game_assert(cond) assert_impl(cond, "(" __FILE__ ":" STRINGIZE(__LINE__) "): \"" #cond "\"")
if (!(cond)) { \
assert_impl(__func__, __FILE__, __LINE__, #cond); \
game_debugbreak(); \
} \
} while (0) game_assert_4127_pop
#endif #endif
#ifdef assert #ifdef assert
#undef assert #undef assert
#endif #endif

@ -3,7 +3,7 @@
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>AI RPG</title> <title>Dante's Cowboy</title>
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<style type="text/css"> <style type="text/css">

Loading…
Cancel
Save