Compare commits
21 Commits
89a7cab44c
...
f780a14406
Author | SHA1 | Date |
---|---|---|
Cameron Murphy Reikes | f780a14406 | 2 years ago |
Cameron Murphy Reikes | 8ac5b43a59 | 2 years ago |
Cameron Murphy Reikes | 4da8973998 | 2 years ago |
Cameron Murphy Reikes | 60cb8661aa | 2 years ago |
Cameron Murphy Reikes | d190594b38 | 2 years ago |
Cameron Murphy Reikes | 291235e992 | 2 years ago |
Cameron Murphy Reikes | 9275927cc7 | 2 years ago |
Cameron Murphy Reikes | cb661bd98f | 2 years ago |
Cameron Murphy Reikes | 1fa9e497d1 | 2 years ago |
Cameron Murphy Reikes | d570a7db21 | 2 years ago |
root | eb2bf3b996 | 2 years ago |
Cameron Murphy Reikes | b537b38bb0 | 2 years ago |
Cameron Murphy Reikes | 170de8f748 | 2 years ago |
Cameron Murphy Reikes | 8727b0f3f6 | 2 years ago |
Cameron Murphy Reikes | a7b3a6c0a3 | 2 years ago |
Cameron Murphy Reikes | 5565c75423 | 2 years ago |
Cameron Murphy Reikes | b4603a8a2c | 2 years ago |
Cameron Murphy Reikes | 78ce158cd8 | 2 years ago |
Cameron Murphy Reikes | 86fa62ce1d | 2 years ago |
Cameron Murphy Reikes | dc05af2834 | 2 years ago |
Cameron Murphy Reikes | 2feb571c1d | 2 years ago |
@ -0,0 +1,4 @@
|
||||
@Cosmetic - places where cosmetics could be added
|
||||
@Robust - things to do to increase robustness of program
|
||||
@BeforeShip - important things to handle before seriously shipping
|
||||
no checkin - without the space between no and checkin, should never appear in commits, use a pre commit hook for this
|
@ -0,0 +1,4 @@
|
||||
@REM for whitebox
|
||||
call shadergen.bat
|
||||
set compileopts=/Zi /DDEBUG /DLL /OUT:flight_dll /LD
|
||||
call build_msvc.bat
|
@ -0,0 +1,30 @@
|
||||
@echo off
|
||||
|
||||
@REM what all the compile flags mean: https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170
|
||||
|
||||
|
||||
set OPUSLIB=%~dp0thirdparty\opus\win32\VS2015\x64\Release\opus.lib
|
||||
|
||||
if not exist %OPUSLIB% (
|
||||
ECHO ERROR Couldn't find %OPUSLIB% compile opus by opening the visual studio project in win32\VS2015 and building the release setting
|
||||
)
|
||||
|
||||
setlocal enabledelayedexpansion enableextensions
|
||||
pushd thirdparty\Chipmunk2D\src
|
||||
set MUNKSRC=
|
||||
for %%x in (*.c) do set MUNKSRC=!MUNKSRC! thirdparty\Chipmunk2D\src\%%x
|
||||
popd
|
||||
|
||||
@REM /DENET_DEBUG=1^
|
||||
clang -target x86_64-pc-windows-elf -c^
|
||||
-I"thirdparty" -I"thirdparty\minilzo" -I"thirdparty\enet\include" -I"thirdparty\Chipmunk2D\include\chipmunk" -I"thirdparty\Chipmunk2D\include" -I"thirdparty\opus\include" -I"thirdparty\opus\src"^
|
||||
%MUNKSRC%
|
||||
|
||||
rmdir /S /Q elf_objects
|
||||
mkdir elf_objects
|
||||
move *.o elf_objects
|
||||
|
||||
@REM main.c gamestate.c server.c debugdraw.c^
|
||||
@REM thirdparty\minilzo\minilzo.c^
|
||||
@REM %OPUSLIB%
|
||||
@REM thirdparty\enet\callbacks.c thirdparty\enet\compress.c thirdparty\enet\host.c thirdparty\enet\list.c thirdparty\enet\packet.c thirdparty\enet\peer.c thirdparty\enet\protocol.c thirdparty\enet\win32.c Ws2_32.lib winmm.lib^
|
@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
mkdir thirdparty/opus/build
|
||||
cd thirdparty/opus/build
|
||||
cmake ..
|
||||
cmake --build .
|
||||
cd -
|
||||
mkdir -p thirdparty/opus/build || exit 1
|
||||
cd thirdparty/opus/build || exit 1
|
||||
cmake .. || exit 1
|
||||
cmake --build . || exit 1
|
||||
cd - || exit 1
|
||||
|
||||
gcc -o flight_server -Wall -O2 -DNDEBUG -DRELEASE -Ithirdparty -Ithirdparty/opus/include -Ithirdparty/enet/include -Ithirdparty/minilzo -Ithirdparty/Chipmunk2D/include -Ithirdparty/Chipmunk2D/include/chipmunk server_main.c server.c debugdraw.c gamestate.c sokol_impl.c thirdparty/minilzo/minilzo.c thirdparty/enet/*.c thirdparty/Chipmunk2D/src/*.c -lm -lpthread -ldl thirdparty/opus/build/libopus.a
|
||||
gcc -o flight_server -Wall -O2 -DNDEBUG -DRELEASE -Ithirdparty -Ithirdparty/opus/include -Ithirdparty/enet/include -Ithirdparty/minilzo -Ithirdparty/Chipmunk2D/include -Ithirdparty/Chipmunk2D/include/chipmunk server_main.c server.c debugdraw.c gamestate.c sokol_impl.c thirdparty/minilzo/minilzo.c thirdparty/enet/*.c thirdparty/Chipmunk2D/src/*.c -lm -lpthread -ldl thirdparty/opus/build/libopus.a || exit 1
|
||||
|
Binary file not shown.
@ -0,0 +1,145 @@
|
||||
@module horizontal_lightning
|
||||
|
||||
@vs vs
|
||||
in vec4 coord;
|
||||
out vec2 texUV;
|
||||
void main() {
|
||||
gl_Position = vec4(coord.xy, 0.0, 1.0);
|
||||
texUV = coord.zw;
|
||||
}
|
||||
@end
|
||||
|
||||
@fs fs
|
||||
uniform uniforms {
|
||||
float iTime;
|
||||
float alpha;
|
||||
};
|
||||
in vec2 texUV;
|
||||
out vec4 fragColor;
|
||||
vec4 permute(vec4 t) {
|
||||
return t * (t * 34.0 + 133.0);
|
||||
}
|
||||
|
||||
// Gradient set is a normalized expanded rhombic dodecahedron
|
||||
vec3 grad(float hash) {
|
||||
|
||||
// Random vertex of a cube, +/- 1 each
|
||||
vec3 cube = mod(floor(hash / vec3(1.0, 2.0, 4.0)), 2.0) * 2.0 - 1.0;
|
||||
|
||||
// Random edge of the three edges connected to that vertex
|
||||
// Also a cuboctahedral vertex
|
||||
// And corresponds to the face of its dual, the rhombic dodecahedron
|
||||
vec3 cuboct = cube;
|
||||
int selected_edge =int(hash / 16.0) ;
|
||||
if(selected_edge == 0)
|
||||
cuboct.x = 0.0;
|
||||
if(selected_edge == 1)
|
||||
cuboct.y = 0.0;
|
||||
if(selected_edge == 2)
|
||||
cuboct.z = 0.0;
|
||||
|
||||
// In a funky way, pick one of the four points on the rhombic face
|
||||
float type = mod(floor(hash / 8.0), 2.0);
|
||||
vec3 rhomb = (1.0 - type) * cube + type * (cuboct + cross(cube, cuboct));
|
||||
|
||||
// Expand it so that the new edges are the same length
|
||||
// as the existing ones
|
||||
vec3 grad = cuboct * 1.22474487139 + rhomb;
|
||||
|
||||
// To make all gradients the same length, we only need to shorten the
|
||||
// second type of vector. We also put in the whole noise scale constant.
|
||||
// The compiler should reduce it into the existing floats. I think.
|
||||
grad *= (1.0 - 0.042942436724648037 * type) * 3.5946317686139184;
|
||||
|
||||
return grad;
|
||||
}
|
||||
|
||||
// BCC lattice split up into 2 cube lattices
|
||||
vec4 bccNoiseDerivativesPart(vec3 X) {
|
||||
vec3 b = floor(X);
|
||||
vec4 i4 = vec4(X - b, 2.5);
|
||||
|
||||
// Pick between each pair of oppposite corners in the cube.
|
||||
vec3 v1 = b + floor(dot(i4, vec4(.25)));
|
||||
vec3 v2 = b + vec3(1, 0, 0) + vec3(-1, 1, 1) * floor(dot(i4, vec4(-.25, .25, .25, .35)));
|
||||
vec3 v3 = b + vec3(0, 1, 0) + vec3(1, -1, 1) * floor(dot(i4, vec4(.25, -.25, .25, .35)));
|
||||
vec3 v4 = b + vec3(0, 0, 1) + vec3(1, 1, -1) * floor(dot(i4, vec4(.25, .25, -.25, .35)));
|
||||
|
||||
// Gradient hashes for the four vertices in this half-lattice.
|
||||
vec4 hashes = permute(mod(vec4(v1.x, v2.x, v3.x, v4.x), 289.0));
|
||||
hashes = permute(mod(hashes + vec4(v1.y, v2.y, v3.y, v4.y), 289.0));
|
||||
hashes = mod(permute(mod(hashes + vec4(v1.z, v2.z, v3.z, v4.z), 289.0)), 48.0);
|
||||
|
||||
// Gradient extrapolations & kernel function
|
||||
vec3 d1 = X - v1; vec3 d2 = X - v2; vec3 d3 = X - v3; vec3 d4 = X - v4;
|
||||
vec4 a = max(0.75 - vec4(dot(d1, d1), dot(d2, d2), dot(d3, d3), dot(d4, d4)), 0.0);
|
||||
vec4 aa = a * a; vec4 aaaa = aa * aa;
|
||||
vec3 g1 = grad(hashes.x); vec3 g2 = grad(hashes.y);
|
||||
vec3 g3 = grad(hashes.z); vec3 g4 = grad(hashes.w);
|
||||
vec4 extrapolations = vec4(dot(d1, g1), dot(d2, g2), dot(d3, g3), dot(d4, g4));
|
||||
|
||||
// Derivatives of the noise
|
||||
vec3 derivative = -8.0 * mat4x3(d1, d2, d3, d4) * (aa * a * extrapolations)
|
||||
+ mat4x3(g1, g2, g3, g4) * aaaa;
|
||||
|
||||
// Return it all as a vec4
|
||||
return vec4(derivative, dot(aaaa, extrapolations));
|
||||
}
|
||||
|
||||
|
||||
// Gives X and Y a triangular alignment, and lets Z move up the main diagonal.
|
||||
// Might be good for terrain, or a time varying X/Y plane. Z repeats.
|
||||
vec4 bccNoiseDerivatives_XYBeforeZ(vec3 X) {
|
||||
|
||||
// Not a skew transform.
|
||||
mat3 orthonormalMap = mat3(
|
||||
0.788675134594813, -0.211324865405187, -0.577350269189626,
|
||||
-0.211324865405187, 0.788675134594813, -0.577350269189626,
|
||||
0.577350269189626, 0.577350269189626, 0.577350269189626);
|
||||
|
||||
X = orthonormalMap * X;
|
||||
vec4 result = bccNoiseDerivativesPart(X) + bccNoiseDerivativesPart(X + 144.5);
|
||||
|
||||
return vec4(result.xyz * orthonormalMap, result.w);
|
||||
}
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 uv = texUV;
|
||||
vec2 p = uv;
|
||||
uv = uv * 2. -1.;
|
||||
|
||||
float tickle = 0.001*1000*iTime;
|
||||
vec3 offset = vec3(cos(tickle), sin(tickle), 0.0);
|
||||
vec3 p3 = vec3(p, 0.0) + offset;
|
||||
|
||||
vec3 noise_input = vec3(p3*25.0+12.0);
|
||||
//float intensity = noise(noise_input);
|
||||
float intensity = 0.0;
|
||||
intensity += bccNoiseDerivatives_XYBeforeZ(noise_input).w*0.4;
|
||||
intensity += bccNoiseDerivatives_XYBeforeZ(noise_input*0.55).w*0.7;
|
||||
intensity += bccNoiseDerivatives_XYBeforeZ(noise_input*0.44).w*0.8;
|
||||
|
||||
|
||||
float t = clamp((uv.x * -uv.x * 0.16) + 0.15, 0., 1.);
|
||||
//fragColor.rgb = vec3(t);
|
||||
|
||||
float dist = length(uv);
|
||||
|
||||
//float y = abs( dist - 0.5 - intensity * 0.1);
|
||||
float y = abs(uv.y/1.5 - intensity * 0.1);
|
||||
|
||||
float g = pow(y, 0.2);
|
||||
|
||||
vec3 col = vec3(2.0, 1.8, 0.5);
|
||||
col = col * -g + col;
|
||||
col = col * col;
|
||||
col = col * col;
|
||||
|
||||
fragColor.rgb = col;
|
||||
fragColor.a = ((col.r + col.g + col.b)/3.0) * alpha;
|
||||
}
|
||||
@end
|
||||
|
||||
@program program vs fs
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,4 @@
|
||||
set EXECUTABLE=x64\Debug\Flight.exe
|
||||
|
||||
START /b %EXECUTABLE% host=true replay_inputs_from=input_go_up.bin
|
||||
%EXECUTABLE% replay_inputs_from=input_go_down.bin
|
@ -0,0 +1,144 @@
|
||||
@module lightning
|
||||
|
||||
@vs vs
|
||||
in vec4 coord;
|
||||
out vec2 texUV;
|
||||
void main() {
|
||||
gl_Position = vec4(coord.xy, 0.0, 1.0);
|
||||
texUV = coord.zw;
|
||||
}
|
||||
@end
|
||||
|
||||
@fs fs
|
||||
uniform uniforms {
|
||||
float iTime;
|
||||
};
|
||||
in vec2 texUV;
|
||||
out vec4 fragColor;
|
||||
vec4 permute(vec4 t) {
|
||||
return t * (t * 34.0 + 133.0);
|
||||
}
|
||||
|
||||
// Gradient set is a normalized expanded rhombic dodecahedron
|
||||
vec3 grad(float hash) {
|
||||
|
||||
// Random vertex of a cube, +/- 1 each
|
||||
vec3 cube = mod(floor(hash / vec3(1.0, 2.0, 4.0)), 2.0) * 2.0 - 1.0;
|
||||
|
||||
// Random edge of the three edges connected to that vertex
|
||||
// Also a cuboctahedral vertex
|
||||
// And corresponds to the face of its dual, the rhombic dodecahedron
|
||||
vec3 cuboct = cube;
|
||||
int selected_edge =int(hash / 16.0) ;
|
||||
if(selected_edge == 0)
|
||||
cuboct.x = 0.0;
|
||||
if(selected_edge == 1)
|
||||
cuboct.y = 0.0;
|
||||
if(selected_edge == 2)
|
||||
cuboct.z = 0.0;
|
||||
|
||||
// In a funky way, pick one of the four points on the rhombic face
|
||||
float type = mod(floor(hash / 8.0), 2.0);
|
||||
vec3 rhomb = (1.0 - type) * cube + type * (cuboct + cross(cube, cuboct));
|
||||
|
||||
// Expand it so that the new edges are the same length
|
||||
// as the existing ones
|
||||
vec3 grad = cuboct * 1.22474487139 + rhomb;
|
||||
|
||||
// To make all gradients the same length, we only need to shorten the
|
||||
// second type of vector. We also put in the whole noise scale constant.
|
||||
// The compiler should reduce it into the existing floats. I think.
|
||||
grad *= (1.0 - 0.042942436724648037 * type) * 3.5946317686139184;
|
||||
|
||||
return grad;
|
||||
}
|
||||
|
||||
// BCC lattice split up into 2 cube lattices
|
||||
vec4 bccNoiseDerivativesPart(vec3 X) {
|
||||
vec3 b = floor(X);
|
||||
vec4 i4 = vec4(X - b, 2.5);
|
||||
|
||||
// Pick between each pair of oppposite corners in the cube.
|
||||
vec3 v1 = b + floor(dot(i4, vec4(.25)));
|
||||
vec3 v2 = b + vec3(1, 0, 0) + vec3(-1, 1, 1) * floor(dot(i4, vec4(-.25, .25, .25, .35)));
|
||||
vec3 v3 = b + vec3(0, 1, 0) + vec3(1, -1, 1) * floor(dot(i4, vec4(.25, -.25, .25, .35)));
|
||||
vec3 v4 = b + vec3(0, 0, 1) + vec3(1, 1, -1) * floor(dot(i4, vec4(.25, .25, -.25, .35)));
|
||||
|
||||
// Gradient hashes for the four vertices in this half-lattice.
|
||||
vec4 hashes = permute(mod(vec4(v1.x, v2.x, v3.x, v4.x), 289.0));
|
||||
hashes = permute(mod(hashes + vec4(v1.y, v2.y, v3.y, v4.y), 289.0));
|
||||
hashes = mod(permute(mod(hashes + vec4(v1.z, v2.z, v3.z, v4.z), 289.0)), 48.0);
|
||||
|
||||
// Gradient extrapolations & kernel function
|
||||
vec3 d1 = X - v1; vec3 d2 = X - v2; vec3 d3 = X - v3; vec3 d4 = X - v4;
|
||||
vec4 a = max(0.75 - vec4(dot(d1, d1), dot(d2, d2), dot(d3, d3), dot(d4, d4)), 0.0);
|
||||
vec4 aa = a * a; vec4 aaaa = aa * aa;
|
||||
vec3 g1 = grad(hashes.x); vec3 g2 = grad(hashes.y);
|
||||
vec3 g3 = grad(hashes.z); vec3 g4 = grad(hashes.w);
|
||||
vec4 extrapolations = vec4(dot(d1, g1), dot(d2, g2), dot(d3, g3), dot(d4, g4));
|
||||
|
||||
// Derivatives of the noise
|
||||
vec3 derivative = -8.0 * mat4x3(d1, d2, d3, d4) * (aa * a * extrapolations)
|
||||
+ mat4x3(g1, g2, g3, g4) * aaaa;
|
||||
|
||||
// Return it all as a vec4
|
||||
return vec4(derivative, dot(aaaa, extrapolations));
|
||||
}
|
||||
|
||||
|
||||
// Gives X and Y a triangular alignment, and lets Z move up the main diagonal.
|
||||
// Might be good for terrain, or a time varying X/Y plane. Z repeats.
|
||||
vec4 bccNoiseDerivatives_XYBeforeZ(vec3 X) {
|
||||
|
||||
// Not a skew transform.
|
||||
mat3 orthonormalMap = mat3(
|
||||
0.788675134594813, -0.211324865405187, -0.577350269189626,
|
||||
-0.211324865405187, 0.788675134594813, -0.577350269189626,
|
||||
0.577350269189626, 0.577350269189626, 0.577350269189626);
|
||||
|
||||
X = orthonormalMap * X;
|
||||
vec4 result = bccNoiseDerivativesPart(X) + bccNoiseDerivativesPart(X + 144.5);
|
||||
|
||||
return vec4(result.xyz * orthonormalMap, result.w);
|
||||
}
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 uv = texUV;
|
||||
vec2 p = uv;
|
||||
uv = uv * 2. -1.;
|
||||
|
||||
|
||||
float tickle = 0.001*1000*iTime;
|
||||
vec3 offset = vec3(cos(tickle), sin(tickle), 0.0);
|
||||
vec3 p3 = vec3(p, 0.0) + offset;
|
||||
|
||||
vec3 noise_input = vec3(p3*25.0+12.0);
|
||||
//float intensity = noise(noise_input);
|
||||
float intensity = 0.0;
|
||||
intensity += bccNoiseDerivatives_XYBeforeZ(noise_input).w*0.4;
|
||||
intensity += bccNoiseDerivatives_XYBeforeZ(noise_input*0.55).w*0.7;
|
||||
intensity += bccNoiseDerivatives_XYBeforeZ(noise_input*0.44).w*0.8;
|
||||
|
||||
|
||||
float t = clamp((uv.x * -uv.x * 0.16) + 0.15, 0., 1.);
|
||||
//fragColor.rgb = vec3(t);
|
||||
|
||||
float dist = length(uv);
|
||||
|
||||
float y = abs(dist - 0.5 - intensity * 0.1);
|
||||
|
||||
float g = pow(y, 0.2);
|
||||
|
||||
vec3 col = vec3(1.50, 1.48, 1.78);
|
||||
col = col * -g + col;
|
||||
col = col * col;
|
||||
col = col * col;
|
||||
|
||||
fragColor.rgb = col;
|
||||
fragColor.a = (col.r + col.g + col.b)/3.0;
|
||||
}
|
||||
@end
|
||||
|
||||
@program program vs fs
|
@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
systemctl stop flight
|
||||
./build_linux_server_release.sh
|
||||
cp flight.service /etc/systemd/system/
|
||||
systemctl enable flight
|
||||
systemctl start flight
|
||||
systemctl restart flight
|
||||
systemctl stop flight || exit 1
|
||||
./build_linux_server_release.sh || exit 1
|
||||
cp flight.service /etc/systemd/system/ || exit 1
|
||||
systemctl enable flight || exit 1
|
||||
systemctl start flight || exit 1
|
||||
systemctl restart flight || exit 1
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 7.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 240 B |
@ -1,9 +1,15 @@
|
||||
git push
|
||||
call build_release.bat
|
||||
call update_server.bat
|
||||
tar.exe -a -c -f releases\flight-nonumber.zip flight_release.exe loaded LICENSE.txt
|
||||
git push || goto :error
|
||||
call build_release.bat || goto :error
|
||||
call update_server.bat || goto :error
|
||||
tar.exe -a -c -f releases\flight-nonumber.zip flight_release.exe loaded LICENSE.txt || goto :error
|
||||
echo "Now test flight-nonumber and make sure it works. Once everything is confirmed to be working:"
|
||||
echo "1. Increment the GIT_RELEASE_TAG in buildsettings.h"
|
||||
echo "2. Add everything to git and commit"
|
||||
echo "3. Tag the new commit the _exact same_ as the previously mentioned GIT_RELEASE_TAG"
|
||||
echo "4. Push everything, then update all the servers (@TODO make this a script that works for multiple servers)"
|
||||
echo "4. Push everything, then update all the servers (@TODO make this a script that works for multiple servers)"
|
||||
|
||||
goto :EOF
|
||||
|
||||
:error
|
||||
echo Failed to release with error %errorlevel%
|
||||
exit /b %errorlevel%
|
@ -0,0 +1,845 @@
|
||||
#if defined(SOKOL_IMPL) && !defined(SOKOL_ARGS_IMPL)
|
||||
#define SOKOL_ARGS_IMPL
|
||||
#endif
|
||||
#ifndef SOKOL_ARGS_INCLUDED
|
||||
/*
|
||||
sokol_args.h -- cross-platform key/value arg-parsing for web and native
|
||||
|
||||
Project URL: https://github.com/floooh/sokol
|
||||
|
||||
Do this:
|
||||
#define SOKOL_IMPL or
|
||||
#define SOKOL_ARGS_IMPL
|
||||
before you include this file in *one* C or C++ file to create the
|
||||
implementation.
|
||||
|
||||
Optionally provide the following defines with your own implementations:
|
||||
|
||||
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
|
||||
SOKOL_ARGS_API_DECL - public function declaration prefix (default: extern)
|
||||
SOKOL_API_DECL - same as SOKOL_ARGS_API_DECL
|
||||
SOKOL_API_IMPL - public function implementation prefix (default: -)
|
||||
|
||||
If sokol_args.h is compiled as a DLL, define the following before
|
||||
including the declaration or implementation:
|
||||
|
||||
SOKOL_DLL
|
||||
|
||||
On Windows, SOKOL_DLL will define SOKOL_ARGS_API_DECL as __declspec(dllexport)
|
||||
or __declspec(dllimport) as needed.
|
||||
|
||||
OVERVIEW
|
||||
========
|
||||
sokol_args.h provides a simple unified argument parsing API for WebAssembly and
|
||||
native apps.
|
||||
|
||||
When running as WebAssembly app, arguments are taken from the page URL:
|
||||
|
||||
https://floooh.github.io/tiny8bit/kc85.html?type=kc85_3&mod=m022&snapshot=kc85/jungle.kcc
|
||||
|
||||
The same arguments provided to a command line app:
|
||||
|
||||
kc85 type=kc85_3 mod=m022 snapshot=kc85/jungle.kcc
|
||||
|
||||
ARGUMENT FORMATTING
|
||||
===================
|
||||
On the web platform, arguments must be formatted as a valid URL query string
|
||||
with 'percent encoding' used for special characters.
|
||||
|
||||
Strings are expected to be UTF-8 encoded (although sokol_args.h doesn't
|
||||
contain any special UTF-8 handling). See below on how to obtain
|
||||
UTF-8 encoded argc/argv values on Windows when using WinMain() as
|
||||
entry point.
|
||||
|
||||
On native platforms the following rules must be followed:
|
||||
|
||||
Arguments have the general form
|
||||
|
||||
key=value
|
||||
|
||||
Key/value pairs are separated by 'whitespace', valid whitespace
|
||||
characters are space and tab.
|
||||
|
||||
Whitespace characters in front and after the separating '=' character
|
||||
are ignored:
|
||||
|
||||
key = value
|
||||
|
||||
...is the same as
|
||||
|
||||
key=value
|
||||
|
||||
The 'key' string must be a simple string without escape sequences or whitespace.
|
||||
|
||||
Currently 'single keys' without values are not allowed, but may be
|
||||
in the future.
|
||||
|
||||
The 'value' string can be quoted, and quoted value strings can contain
|
||||
whitespace:
|
||||
|
||||
key = 'single-quoted value'
|
||||
key = "double-quoted value"
|
||||
|
||||
Single-quoted value strings can contain double quotes, and vice-versa:
|
||||
|
||||
key = 'single-quoted value "can contain double-quotes"'
|
||||
key = "double-quoted value 'can contain single-quotes'"
|
||||
|
||||
Note that correct quoting can be tricky on some shells, since command
|
||||
shells may remove quotes, unless they're escaped.
|
||||
|
||||
Value strings can contain a small selection of escape sequences:
|
||||
|
||||
\n - newline
|
||||
\r - carriage return
|
||||
\t - tab
|
||||
\\ - escaped backslash
|
||||
|
||||
(more escape codes may be added in the future).
|
||||
|
||||
CODE EXAMPLE
|
||||
============
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// initialize sokol_args with default parameters
|
||||
sargs_setup(&(sargs_desc){
|
||||
.argc = argc,
|
||||
.argv = argv
|
||||
});
|
||||
|
||||
// check if a key exists...
|
||||
if (sargs_exists("bla")) {
|
||||
...
|
||||
}
|
||||
|
||||
// get value string for key, if not found, return empty string ""
|
||||
const char* val0 = sargs_value("bla");
|
||||
|
||||
// get value string for key, or default string if key not found
|
||||
const char* val1 = sargs_value_def("bla", "default_value");
|
||||
|
||||
// check if a key matches expected value
|
||||
if (sargs_equals("type", "kc85_4")) {
|
||||
...
|
||||
}
|
||||
|
||||
// check if a key's value is "true", "yes" or "on"
|
||||
if (sargs_boolean("joystick_enabled")) {
|
||||
...
|
||||
}
|
||||
|
||||
// iterate over keys and values
|
||||
for (int i = 0; i < sargs_num_args(); i++) {
|
||||
printf("key: %s, value: %s\n", sargs_key_at(i), sargs_value_at(i));
|
||||
}
|
||||
|
||||
// lookup argument index by key string, will return -1 if key
|
||||
// is not found, sargs_key_at() and sargs_value_at() will return
|
||||
// an empty string for invalid indices
|
||||
int index = sargs_find("bla");
|
||||
printf("key: %s, value: %s\n", sargs_key_at(index), sargs_value_at(index));
|
||||
|
||||
// shutdown sokol-args
|
||||
sargs_shutdown();
|
||||
}
|
||||
|
||||
WINMAIN AND ARGC / ARGV
|
||||
=======================
|
||||
On Windows with WinMain() based apps, getting UTF8-encoded command line
|
||||
arguments is a bit more complicated:
|
||||
|
||||
First call GetCommandLineW(), this returns the entire command line
|
||||
as UTF-16 string. Then call CommandLineToArgvW(), this parses the
|
||||
command line string into the usual argc/argv format (but in UTF-16).
|
||||
Finally convert the UTF-16 strings in argv[] into UTF-8 via
|
||||
WideCharToMultiByte().
|
||||
|
||||
See the function _sapp_win32_command_line_to_utf8_argv() in sokol_app.h
|
||||
for example code how to do this (if you're using sokol_app.h, it will
|
||||
already convert the command line arguments to UTF-8 for you of course,
|
||||
so you can plug them directly into sokol_app.h).
|
||||
|
||||
API DOCUMENTATION
|
||||
=================
|
||||
void sargs_setup(const sargs_desc* desc)
|
||||
Initialize sokol_args, desc contains the following configuration
|
||||
parameters:
|
||||
int argc - the main function's argc parameter
|
||||
char** argv - the main function's argv parameter
|
||||
int max_args - max number of key/value pairs, default is 16
|
||||
int buf_size - size of the internal string buffer, default is 16384
|
||||
|
||||
Note that on the web, argc and argv will be ignored and the arguments
|
||||
will be taken from the page URL instead.
|
||||
|
||||
sargs_setup() will allocate 2 memory chunks: one for keeping track
|
||||
of the key/value args of size 'max_args*8', and a string buffer
|
||||
of size 'buf_size'.
|
||||
|
||||
void sargs_shutdown(void)
|
||||
Shutdown sokol-args and free any allocated memory.
|
||||
|
||||
bool sargs_isvalid(void)
|
||||
Return true between sargs_setup() and sargs_shutdown()
|
||||
|
||||
bool sargs_exists(const char* key)
|
||||
Test if a key arg exists.
|
||||
|
||||
const char* sargs_value(const char* key)
|
||||
Return value associated with key. Returns an empty
|
||||
string ("") if the key doesn't exist.
|
||||
|
||||
const char* sargs_value_def(const char* key, const char* default)
|
||||
Return value associated with key, or the provided default
|
||||
value if the value doesn't exist.
|
||||
|
||||
bool sargs_equals(const char* key, const char* val);
|
||||
Return true if the value associated with key matches
|
||||
the 'val' argument.
|
||||
|
||||
bool sargs_boolean(const char* key)
|
||||
Return true if the value string of 'key' is one
|
||||
of 'true', 'yes', 'on'.
|
||||
|
||||
int sargs_find(const char* key)
|
||||
Find argument by key name and return its index, or -1 if not found.
|
||||
|
||||
int sargs_num_args(void)
|
||||
Return number of key/value pairs.
|
||||
|
||||
const char* sargs_key_at(int index)
|
||||
Return the key name of argument at index. Returns empty string if
|
||||
is index is outside range.
|
||||
|
||||
const char* sargs_value_at(int index)
|
||||
Return the value of argument at index. Returns empty string
|
||||
if index is outside range.
|
||||
|
||||
|
||||
MEMORY ALLOCATION OVERRIDE
|
||||
==========================
|
||||
You can override the memory allocation functions at initialization time
|
||||
like this:
|
||||
|
||||
void* my_alloc(size_t size, void* user_data) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void my_free(void* ptr, void* user_data) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
...
|
||||
sargs_setup(&(sargs_desc){
|
||||
// ...
|
||||
.allocator = {
|
||||
.alloc = my_alloc,
|
||||
.free = my_free,
|
||||
.user_data = ...,
|
||||
}
|
||||
});
|
||||
...
|
||||
|
||||
If no overrides are provided, malloc and free will be used.
|
||||
|
||||
This only affects memory allocation calls done by sokol_args.h
|
||||
itself though, not any allocations in OS libraries.
|
||||
|
||||
TODO
|
||||
====
|
||||
- parsing errors?
|
||||
|
||||
LICENSE
|
||||
=======
|
||||
|
||||
zlib/libpng license
|
||||
|
||||
Copyright (c) 2018 Andre Weissflog
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the
|
||||
use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software in a
|
||||
product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not
|
||||
be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
#define SOKOL_ARGS_INCLUDED (1)
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h> // size_t
|
||||
|
||||
#if defined(SOKOL_API_DECL) && !defined(SOKOL_ARGS_API_DECL)
|
||||
#define SOKOL_ARGS_API_DECL SOKOL_API_DECL
|
||||
#endif
|
||||
#ifndef SOKOL_ARGS_API_DECL
|
||||
#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_ARGS_IMPL)
|
||||
#define SOKOL_ARGS_API_DECL __declspec(dllexport)
|
||||
#elif defined(_WIN32) && defined(SOKOL_DLL)
|
||||
#define SOKOL_ARGS_API_DECL __declspec(dllimport)
|
||||
#else
|
||||
#define SOKOL_ARGS_API_DECL extern
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
sargs_allocator
|
||||
|
||||
Used in sargs_desc to provide custom memory-alloc and -free functions
|
||||
to sokol_args.h. If memory management should be overridden, both the
|
||||
alloc and free function must be provided (e.g. it's not valid to
|
||||
override one function but not the other).
|
||||
*/
|
||||
typedef struct sargs_allocator {
|
||||
void* (*alloc)(size_t size, void* user_data);
|
||||
void (*free)(void* ptr, void* user_data);
|
||||
void* user_data;
|
||||
} sargs_allocator;
|
||||
|
||||
typedef struct sargs_desc {
|
||||
int argc;
|
||||
char** argv;
|
||||
int max_args;
|
||||
int buf_size;
|
||||
sargs_allocator allocator;
|
||||
} sargs_desc;
|
||||
|
||||
/* setup sokol-args */
|
||||
SOKOL_ARGS_API_DECL void sargs_setup(const sargs_desc* desc);
|
||||
/* shutdown sokol-args */
|
||||
SOKOL_ARGS_API_DECL void sargs_shutdown(void);
|
||||
/* true between sargs_setup() and sargs_shutdown() */
|
||||
SOKOL_ARGS_API_DECL bool sargs_isvalid(void);
|
||||
/* test if an argument exists by key name */
|
||||
SOKOL_ARGS_API_DECL bool sargs_exists(const char* key);
|
||||
/* get value by key name, return empty string if key doesn't exist */
|
||||
SOKOL_ARGS_API_DECL const char* sargs_value(const char* key);
|
||||
/* get value by key name, return provided default if key doesn't exist */
|
||||
SOKOL_ARGS_API_DECL const char* sargs_value_def(const char* key, const char* def);
|
||||
/* return true if val arg matches the value associated with key */
|
||||
SOKOL_ARGS_API_DECL bool sargs_equals(const char* key, const char* val);
|
||||
/* return true if key's value is "true", "yes" or "on" */
|
||||
SOKOL_ARGS_API_DECL bool sargs_boolean(const char* key);
|
||||
/* get index of arg by key name, return -1 if not exists */
|
||||
SOKOL_ARGS_API_DECL int sargs_find(const char* key);
|
||||
/* get number of parsed arguments */
|
||||
SOKOL_ARGS_API_DECL int sargs_num_args(void);
|
||||
/* get key name of argument at index, or empty string */
|
||||
SOKOL_ARGS_API_DECL const char* sargs_key_at(int index);
|
||||
/* get value string of argument at index, or empty string */
|
||||
SOKOL_ARGS_API_DECL const char* sargs_value_at(int index);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
/* reference-based equivalents for c++ */
|
||||
inline void sargs_setup(const sargs_desc& desc) { return sargs_setup(&desc); }
|
||||
|
||||
#endif
|
||||
#endif // SOKOL_ARGS_INCLUDED
|
||||
|
||||
/*--- IMPLEMENTATION ---------------------------------------------------------*/
|
||||
#ifdef SOKOL_ARGS_IMPL
|
||||
#define SOKOL_ARGS_IMPL_INCLUDED (1)
|
||||
|
||||
#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE)
|
||||
#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sargs_desc.allocator to override memory allocation functions"
|
||||
#endif
|
||||
|
||||
#include <string.h> // memset, strcmp
|
||||
#include <stdlib.h> // malloc, free
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
#include <emscripten/emscripten.h>
|
||||
#endif
|
||||
|
||||
#ifndef SOKOL_API_IMPL
|
||||
#define SOKOL_API_IMPL
|
||||
#endif
|
||||
#ifndef SOKOL_DEBUG
|
||||
#ifndef NDEBUG
|
||||
#define SOKOL_DEBUG
|
||||
#endif
|
||||
#endif
|
||||
#ifndef SOKOL_ASSERT
|
||||
#include <assert.h>
|
||||
#define SOKOL_ASSERT(c) assert(c)
|
||||
#endif
|
||||
|
||||
#ifndef _SOKOL_PRIVATE
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define _SOKOL_PRIVATE __attribute__((unused)) static
|
||||
#else
|
||||
#define _SOKOL_PRIVATE static
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define _sargs_def(val, def) (((val) == 0) ? (def) : (val))
|
||||
|
||||
#define _SARGS_MAX_ARGS_DEF (16)
|
||||
#define _SARGS_BUF_SIZE_DEF (16*1024)
|
||||
|
||||
/* parser state */
|
||||
#define _SARGS_EXPECT_KEY (1<<0)
|
||||
#define _SARGS_EXPECT_SEP (1<<1)
|
||||
#define _SARGS_EXPECT_VAL (1<<2)
|
||||
#define _SARGS_PARSING_KEY (1<<3)
|
||||
#define _SARGS_PARSING_VAL (1<<4)
|
||||
#define _SARGS_ERROR (1<<5)
|
||||
|
||||
/* a key/value pair struct */
|
||||
typedef struct {
|
||||
int key; /* index to start of key string in buf */
|
||||
int val; /* index to start of value string in buf */
|
||||
} _sargs_kvp_t;
|
||||
|
||||
/* sokol-args state */
|
||||
typedef struct {
|
||||
int max_args; /* number of key/value pairs in args array */
|
||||
int num_args; /* number of valid items in args array */
|
||||
_sargs_kvp_t* args; /* key/value pair array */
|
||||
int buf_size; /* size of buffer in bytes */
|
||||
int buf_pos; /* current buffer position */
|
||||
char* buf; /* character buffer, first char is reserved and zero for 'empty string' */
|
||||
bool valid;
|
||||
uint32_t parse_state;
|
||||
char quote; /* current quote char, 0 if not in a quote */
|
||||
bool in_escape; /* currently in an escape sequence */
|
||||
sargs_allocator allocator;
|
||||
} _sargs_state_t;
|
||||
static _sargs_state_t _sargs;
|
||||
|
||||
/*== PRIVATE IMPLEMENTATION FUNCTIONS ========================================*/
|
||||
_SOKOL_PRIVATE void _sargs_clear(void* ptr, size_t size) {
|
||||
SOKOL_ASSERT(ptr && (size > 0));
|
||||
memset(ptr, 0, size);
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void* _sargs_malloc(size_t size) {
|
||||
SOKOL_ASSERT(size > 0);
|
||||
void* ptr;
|
||||
if (_sargs.allocator.alloc) {
|
||||
ptr = _sargs.allocator.alloc(size, _sargs.allocator.user_data);
|
||||
}
|
||||
else {
|
||||
ptr = malloc(size);
|
||||
}
|
||||
SOKOL_ASSERT(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void* _sargs_malloc_clear(size_t size) {
|
||||
void* ptr = _sargs_malloc(size);
|
||||
_sargs_clear(ptr, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sargs_free(void* ptr) {
|
||||
if (_sargs.allocator.free) {
|
||||
_sargs.allocator.free(ptr, _sargs.allocator.user_data);
|
||||
}
|
||||
else {
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sargs_putc(char c) {
|
||||
if ((_sargs.buf_pos+2) < _sargs.buf_size) {
|
||||
_sargs.buf[_sargs.buf_pos++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE const char* _sargs_str(int index) {
|
||||
SOKOL_ASSERT((index >= 0) && (index < _sargs.buf_size));
|
||||
return &_sargs.buf[index];
|
||||
}
|
||||
|
||||
/*-- argument parser functions ------------------*/
|
||||
_SOKOL_PRIVATE void _sargs_expect_key(void) {
|
||||
_sargs.parse_state = _SARGS_EXPECT_KEY;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE bool _sargs_key_expected(void) {
|
||||
return 0 != (_sargs.parse_state & _SARGS_EXPECT_KEY);
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sargs_expect_val(void) {
|
||||
_sargs.parse_state = _SARGS_EXPECT_VAL;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE bool _sargs_val_expected(void) {
|
||||
return 0 != (_sargs.parse_state & _SARGS_EXPECT_VAL);
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sargs_expect_sep(void) {
|
||||
_sargs.parse_state = _SARGS_EXPECT_SEP;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE bool _sargs_any_expected(void) {
|
||||
return 0 != (_sargs.parse_state & (_SARGS_EXPECT_KEY | _SARGS_EXPECT_VAL | _SARGS_EXPECT_SEP));
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE bool _sargs_is_separator(char c) {
|
||||
return c == '=';
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE bool _sargs_is_quote(char c) {
|
||||
if (0 == _sargs.quote) {
|
||||
return (c == '\'') || (c == '"');
|
||||
}
|
||||
else {
|
||||
return c == _sargs.quote;
|
||||
}
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sargs_begin_quote(char c) {
|
||||
_sargs.quote = c;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sargs_end_quote(void) {
|
||||
_sargs.quote = 0;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE bool _sargs_in_quotes(void) {
|
||||
return 0 != _sargs.quote;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE bool _sargs_is_whitespace(char c) {
|
||||
return !_sargs_in_quotes() && ((c == ' ') || (c == '\t'));
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sargs_start_key(void) {
|
||||
SOKOL_ASSERT(_sargs.num_args < _sargs.max_args);
|
||||
_sargs.parse_state = _SARGS_PARSING_KEY;
|
||||
_sargs.args[_sargs.num_args].key = _sargs.buf_pos;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sargs_end_key(void) {
|
||||
SOKOL_ASSERT(_sargs.num_args < _sargs.max_args);
|
||||
_sargs_putc(0);
|
||||
_sargs.parse_state = 0;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE bool _sargs_parsing_key(void) {
|
||||
return 0 != (_sargs.parse_state & _SARGS_PARSING_KEY);
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sargs_start_val(void) {
|
||||
SOKOL_ASSERT(_sargs.num_args < _sargs.max_args);
|
||||
_sargs.parse_state = _SARGS_PARSING_VAL;
|
||||
_sargs.args[_sargs.num_args].val = _sargs.buf_pos;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sargs_end_val(void) {
|
||||
SOKOL_ASSERT(_sargs.num_args < _sargs.max_args);
|
||||
_sargs_putc(0);
|
||||
_sargs.num_args++;
|
||||
_sargs.parse_state = 0;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE bool _sargs_is_escape(char c) {
|
||||
return '\\' == c;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sargs_start_escape(void) {
|
||||
_sargs.in_escape = true;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE bool _sargs_in_escape(void) {
|
||||
return _sargs.in_escape;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE char _sargs_escape(char c) {
|
||||
switch (c) {
|
||||
case 'n': return '\n';
|
||||
case 't': return '\t';
|
||||
case 'r': return '\r';
|
||||
case '\\': return '\\';
|
||||
default: return c;
|
||||
}
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sargs_end_escape(void) {
|
||||
_sargs.in_escape = false;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE bool _sargs_parsing_val(void) {
|
||||
return 0 != (_sargs.parse_state & _SARGS_PARSING_VAL);
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE bool _sargs_parse_carg(const char* src) {
|
||||
char c;
|
||||
while (0 != (c = *src++)) {
|
||||
if (_sargs_in_escape()) {
|
||||
c = _sargs_escape(c);
|
||||
_sargs_end_escape();
|
||||
}
|
||||
else if (_sargs_is_escape(c)) {
|
||||
_sargs_start_escape();
|
||||
continue;
|
||||
}
|
||||
if (_sargs_any_expected()) {
|
||||
if (!_sargs_is_whitespace(c)) {
|
||||
/* start of key, value or separator */
|
||||
if (_sargs_key_expected()) {
|
||||
/* start of new key */
|
||||
_sargs_start_key();
|
||||
}
|
||||
else if (_sargs_val_expected()) {
|
||||
/* start of value */
|
||||
if (_sargs_is_quote(c)) {
|
||||
_sargs_begin_quote(c);
|
||||
continue;
|
||||
}
|
||||
_sargs_start_val();
|
||||
}
|
||||
else {
|
||||
/* separator */
|
||||
if (_sargs_is_separator(c)) {
|
||||
_sargs_expect_val();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* skip white space */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (_sargs_parsing_key()) {
|
||||
if (_sargs_is_whitespace(c) || _sargs_is_separator(c)) {
|
||||
/* end of key string */
|
||||
_sargs_end_key();
|
||||
if (_sargs_is_separator(c)) {
|
||||
_sargs_expect_val();
|
||||
}
|
||||
else {
|
||||
_sargs_expect_sep();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (_sargs_parsing_val()) {
|
||||
if (_sargs_in_quotes()) {
|
||||
/* when in quotes, whitespace is a normal character
|
||||
and a matching quote ends the value string
|
||||
*/
|
||||
if (_sargs_is_quote(c)) {
|
||||
_sargs_end_quote();
|
||||
_sargs_end_val();
|
||||
_sargs_expect_key();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (_sargs_is_whitespace(c)) {
|
||||
/* end of value string (no quotes) */
|
||||
_sargs_end_val();
|
||||
_sargs_expect_key();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_sargs_putc(c);
|
||||
}
|
||||
if (_sargs_parsing_key()) {
|
||||
_sargs_end_key();
|
||||
_sargs_expect_sep();
|
||||
}
|
||||
else if (_sargs_parsing_val() && !_sargs_in_quotes()) {
|
||||
_sargs_end_val();
|
||||
_sargs_expect_key();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE bool _sargs_parse_cargs(int argc, const char** argv) {
|
||||
_sargs_expect_key();
|
||||
bool retval = true;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
retval &= _sargs_parse_carg(argv[i]);
|
||||
}
|
||||
_sargs.parse_state = 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*-- EMSCRIPTEN IMPLEMENTATION -----------------------------------------------*/
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(EM_JS_DEPS)
|
||||
EM_JS_DEPS(sokol_audio, "$withStackSave,$allocateUTF8OnStack");
|
||||
#endif
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void _sargs_add_kvp(const char* key, const char* val) {
|
||||
SOKOL_ASSERT(_sargs.valid && key && val);
|
||||
if (_sargs.num_args >= _sargs.max_args) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* copy key string */
|
||||
char c;
|
||||
_sargs.args[_sargs.num_args].key = _sargs.buf_pos;
|
||||
const char* ptr = key;
|
||||
while (0 != (c = *ptr++)) {
|
||||
_sargs_putc(c);
|
||||
}
|
||||
_sargs_putc(0);
|
||||
|
||||
/* copy value string */
|
||||
_sargs.args[_sargs.num_args].val = _sargs.buf_pos;
|
||||
ptr = val;
|
||||
while (0 != (c = *ptr++)) {
|
||||
_sargs_putc(c);
|
||||
}
|
||||
_sargs_putc(0);
|
||||
|
||||
_sargs.num_args++;
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
/* JS function to extract arguments from the page URL */
|
||||
EM_JS(void, sargs_js_parse_url, (void), {
|
||||
const params = new URLSearchParams(window.location.search).entries();
|
||||
for (let p = params.next(); !p.done; p = params.next()) {
|
||||
const key = p.value[0];
|
||||
const val = p.value[1];
|
||||
withStackSave(() => {
|
||||
const key_cstr = allocateUTF8OnStack(key);
|
||||
const val_cstr = allocateUTF8OnStack(val);
|
||||
__sargs_add_kvp(key_cstr, val_cstr)
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
#endif /* EMSCRIPTEN */
|
||||
|
||||
/*== PUBLIC IMPLEMENTATION FUNCTIONS =========================================*/
|
||||
SOKOL_API_IMPL void sargs_setup(const sargs_desc* desc) {
|
||||
SOKOL_ASSERT(desc);
|
||||
_sargs_clear(&_sargs, sizeof(_sargs));
|
||||
_sargs.max_args = _sargs_def(desc->max_args, _SARGS_MAX_ARGS_DEF);
|
||||
_sargs.buf_size = _sargs_def(desc->buf_size, _SARGS_BUF_SIZE_DEF);
|
||||
SOKOL_ASSERT(_sargs.buf_size > 8);
|
||||
_sargs.args = (_sargs_kvp_t*) _sargs_malloc_clear((size_t)_sargs.max_args * sizeof(_sargs_kvp_t));
|
||||
_sargs.buf = (char*) _sargs_malloc_clear((size_t)_sargs.buf_size * sizeof(char));
|
||||
/* the first character in buf is reserved and always zero, this is the 'empty string' */
|
||||
_sargs.buf_pos = 1;
|
||||
_sargs.allocator = desc->allocator;
|
||||
_sargs.valid = true;
|
||||
|
||||
/* parse argc/argv */
|
||||
_sargs_parse_cargs(desc->argc, (const char**) desc->argv);
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
/* on emscripten, also parse the page URL*/
|
||||
sargs_js_parse_url();
|
||||
#endif
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL void sargs_shutdown(void) {
|
||||
SOKOL_ASSERT(_sargs.valid);
|
||||
if (_sargs.args) {
|
||||
_sargs_free(_sargs.args);
|
||||
_sargs.args = 0;
|
||||
}
|
||||
if (_sargs.buf) {
|
||||
_sargs_free(_sargs.buf);
|
||||
_sargs.buf = 0;
|
||||
}
|
||||
_sargs.valid = false;
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL bool sargs_isvalid(void) {
|
||||
return _sargs.valid;
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL int sargs_find(const char* key) {
|
||||
SOKOL_ASSERT(_sargs.valid && key);
|
||||
for (int i = 0; i < _sargs.num_args; i++) {
|
||||
if (0 == strcmp(_sargs_str(_sargs.args[i].key), key)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL int sargs_num_args(void) {
|
||||
SOKOL_ASSERT(_sargs.valid);
|
||||
return _sargs.num_args;
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL const char* sargs_key_at(int index) {
|
||||
SOKOL_ASSERT(_sargs.valid);
|
||||
if ((index >= 0) && (index < _sargs.num_args)) {
|
||||
return _sargs_str(_sargs.args[index].key);
|
||||
}
|
||||
else {
|
||||
/* index 0 is always the empty string */
|
||||
return _sargs_str(0);
|
||||
}
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL const char* sargs_value_at(int index) {
|
||||
SOKOL_ASSERT(_sargs.valid);
|
||||
if ((index >= 0) && (index < _sargs.num_args)) {
|
||||
return _sargs_str(_sargs.args[index].val);
|
||||
}
|
||||
else {
|
||||
/* index 0 is always the empty string */
|
||||
return _sargs_str(0);
|
||||
}
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL bool sargs_exists(const char* key) {
|
||||
SOKOL_ASSERT(_sargs.valid && key);
|
||||
return -1 != sargs_find(key);
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL const char* sargs_value(const char* key) {
|
||||
SOKOL_ASSERT(_sargs.valid && key);
|
||||
return sargs_value_at(sargs_find(key));
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL const char* sargs_value_def(const char* key, const char* def) {
|
||||
SOKOL_ASSERT(_sargs.valid && key && def);
|
||||
int arg_index = sargs_find(key);
|
||||
if (-1 != arg_index) {
|
||||
return sargs_value_at(arg_index);
|
||||
}
|
||||
else {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL bool sargs_equals(const char* key, const char* val) {
|
||||
SOKOL_ASSERT(_sargs.valid && key && val);
|
||||
return 0 == strcmp(sargs_value(key), val);
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL bool sargs_boolean(const char* key) {
|
||||
const char* val = sargs_value(key);
|
||||
return (0 == strcmp("true", val)) ||
|
||||
(0 == strcmp("yes", val)) ||
|
||||
(0 == strcmp("on", val));
|
||||
}
|
||||
|
||||
#endif /* SOKOL_ARGS_IMPL */
|
@ -1 +1,2 @@
|
||||
ssh astris "cd flight; git pull; ./linux_server_install.sh"
|
||||
@echo off
|
||||
ssh astris "cd flight || exit 1 ; git pull || exit 1 ; ./linux_server_install.sh || exit 1 ; echo Successfully updated" || exit /b %errorlevel%
|
@ -0,0 +1,80 @@
|
||||
includes:
|
||||
-IC:\Users\Cameron\Documents\flight\
|
||||
thirdparty
|
||||
thirdparty\minilzo
|
||||
thirdparty\enet\include
|
||||
thirdparty\Chipmunk2D\include\chipmunk
|
||||
thirdparty\Chipmunk2D\include
|
||||
thirdparty\opus\include
|
||||
thirdparty\opus\src
|
||||
|
||||
objects:
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\
|
||||
chipmunk.o
|
||||
cpArbiter.o
|
||||
cpArray.o
|
||||
cpBBTree.o
|
||||
cpBody.o
|
||||
cpCollision.o
|
||||
cpConstraint.o
|
||||
cpDampedRotarySpring.o
|
||||
cpDampedSpring.o
|
||||
cpGearJoint.o
|
||||
cpGrooveJoint.o
|
||||
cpHashSet.o
|
||||
cpHastySpace.o
|
||||
cpMarch.o
|
||||
cpPinJoint.o
|
||||
cpPivotJoint.o
|
||||
cpPolyline.o
|
||||
cpPolyShape.o
|
||||
cpRatchetJoint.o
|
||||
cpRobust.o
|
||||
cpRotaryLimitJoint.o
|
||||
cpShape.o
|
||||
cpSimpleMotor.o
|
||||
cpSlideJoint.o
|
||||
cpSpace.o
|
||||
cpSpaceComponent.o
|
||||
cpSpaceDebug.o
|
||||
cpSpaceHash.o
|
||||
cpSpaceQuery.o
|
||||
cpSpaceStep.o
|
||||
cpSpatialIndex.o
|
||||
cpSweep1D.o
|
||||
|
||||
|
||||
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\chipmunk.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpArbiter.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpArray.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpBBTree.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpBody.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpCollision.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpConstraint.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpDampedRotarySpring.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpDampedSpring.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpGearJoint.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpGrooveJoint.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpHashSet.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpHastySpace.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpMarch.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpPinJoint.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpPivotJoint.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpPolyline.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpPolyShape.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpRatchetJoint.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpRobust.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpRotaryLimitJoint.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpShape.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpSimpleMotor.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpSlideJoint.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpSpace.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpSpaceComponent.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpSpaceDebug.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpSpaceHash.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpSpaceQuery.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpSpaceStep.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpSpatialIndex.o
|
||||
C:\Users\Cameron\Documents\flight\elf_objects\cpSweep1D.o
|
Loading…
Reference in New Issue