[gles] expose GLES surface and GLES API to orca apps.

- Allow orca app to request either Canvas or GLES surfaces
- Add bounds check specifications to the json bindings spec format and to the bindings generator scripts.
- Generate GLES API json bindings spec from gl.xml
- Remove APIs that can't be bound with current wasm memory model (ie buffer mapping)
- Manually link remaining APIs, except glGetString
- Add fluid simulation sample
- Add abort messages for wasm loading and runtime fatal errors
- Adapt orca build tool to generate GLES json spec from gl.xml
- Adapt glesTriangle and fluid samples build scripts to new orca build tool
This commit is contained in:
Martin Fouilleul 2023-08-03 11:37:32 +02:00
parent 3fae3252a1
commit e4d9955e83
42 changed files with 5158 additions and 753 deletions

4
.gitignore vendored
View File

@ -17,11 +17,15 @@ build
Debug/*
scripts/__pycache__
src/gles_api.json
src/bindgen_core_api.c
src/bindgen_gles_api.c
sdk/io_stubs.c
sdk/orca_surface.c
sdk/gl31.h
*bind_gen.c
gles_gen.log
.vscode/launch.json
.vscode/settings.json

View File

@ -1,62 +0,0 @@
@echo off
set target=%1%
if "%~1%" == "" set target=orca
if not exist bin mkdir bin
if not exist bin\obj mkdir bin\obj
if %target% == wasm3 (
echo building wasm3
set wasm3_includes=/I .\ext\wasm3\source
set wasm3_sources=/I .\ext\wasm3\source\*.c
for %%f in ( .\ext\wasm3\source\*.c ) do (
cl /nologo /Zi /Zc:preprocessor /O2 /c /Fo:bin\obj\%%~nf.obj %wasm3_includes% %%f
)
lib /nologo /out:bin\wasm3.lib bin\obj\*.obj
)
if %target% == milepost (
echo building milepost
cd milepost
build.bat
cd ..
)
if %target% == orca (
echo building orca
::copy libraries
copy milepost\bin\milepost.dll bin
copy milepost\bin\milepost.dll.lib bin
::generate wasm3 api bindings
python3 scripts\bindgen.py core src\core_api.json^
--wasm3-bindings src\core_api_bind_gen.c
python3 scripts\bindgen.py gles src\gles_api.json^
--wasm3-bindings src\gles_api_bind_gen.c
python3 scripts\bindgen.py canvas src\canvas_api.json^
--guest-stubs sdk\orca_surface.c^
--guest-include graphics.h^
--wasm3-bindings src\canvas_api_bind_gen.c
python3 scripts\bindgen.py clock src\clock_api.json^
--guest-stubs sdk\orca_clock.c^
--guest-include platform_clock.h^
--wasm3-bindings src\clock_api_bind_gen.c
python3 scripts\bindgen.py io^
src\io_api.json^
--guest-stubs sdk\io_stubs.c^
--wasm3-bindings src\io_api_bind_gen.c
::compile orca
set INCLUDES=/I src /I sdk /I ext\wasm3\source /I milepost\src /I milepost\ext
set LIBS=/LIBPATH:bin milepost.dll.lib wasm3.lib
cl /Zi /Zc:preprocessor /std:c11 /experimental:c11atomics %INCLUDES% src\main.c /link %LIBS% /out:bin\orca.exe
)

View File

@ -1,97 +0,0 @@
#!/bin/bash
set -exo pipefail
target="$1"
if [ -z $target ] ; then
target='orca'
fi
target=$(echo $target | tr '[:upper:]' '[:lower:]')
if [ ! \( -e bin \) ] ; then
mkdir ./bin
fi
if [ ! \( -e resources \) ] ; then
mkdir ./resources
fi
if [ $target = milepost ] ; then
echo "building milepost"
pushd milepost > /dev/null
./build.sh lib "$2"
popd > /dev/null
elif [ $target = wasm3 ] ; then
echo "building wasm3"
mkdir ./bin/obj
for file in ./ext/wasm3/source/*.c ; do
name=$(basename $file)
name=${name/.c/.o}
clang -c -g -O2 -foptimize-sibling-calls -Wno-extern-initializer -Dd_m3VerboseErrorMessages -o ./bin/obj/$name -I./ext/wasm3/source $file
done
ar -rcs ./bin/libwasm3.a ./bin/obj/*.o
rm -rf ./bin/obj
elif [ $target = orca ] ; then
echo "building orca"
if [ ! \( -e milepost/bin/libmilepost.dylib \) -o ! \( -e milepost/bin/mtl_renderer.metallib \) ] ; then
./build.sh milepost
fi
if [ ! \( -e ./bin/libwasm3.a \) ] ; then
./build.sh wasm3
fi
# copy libraries
cp milepost/bin/mtl_renderer.metallib bin/
cp milepost/bin/libmilepost.dylib bin/
cp milepost/bin/libGLESv2.dylib bin/
cp milepost/bin/libEGL.dylib bin/
INCLUDES="-Isrc -Isdk -Imilepost/src -Imilepost/src/util -Imilepost/src/platform -Iext/wasm3/source -Imilepost/ext/"
LIBS="-Lbin -lmilepost -lwasm3"
FLAGS="-g -DLOG_COMPILE_DEBUG -mmacos-version-min=10.15.4 -maes"
# generate wasm3 api bindings
python3 ./scripts/bindgen.py core \
src/core_api.json \
--wasm3-bindings ./src/core_api_bind_gen.c
python3 ./scripts/bindgen.py gles \
src/gles_api.json \
--wasm3-bindings ./src/gles_api_bind_gen.c
python3 ./scripts/bindgen.py canvas \
src/canvas_api.json \
--guest-stubs sdk/orca_surface.c \
--guest-include graphics.h \
--wasm3-bindings ./src/canvas_api_bind_gen.c
python3 ./scripts/bindgen.py clock \
src/clock_api.json \
--guest-stubs sdk/orca_clock.c \
--guest-include platform_clock.h \
--wasm3-bindings ./src/clock_api_bind_gen.c
python3 ./scripts/bindgen.py io \
src/io_api.json \
--guest-stubs sdk/io_stubs.c \
--wasm3-bindings ./src/io_api_bind_gen.c
# compile orca
clang $FLAGS $INCLUDES $LIBS -o bin/orca src/main.c
# fix libs imports
install_name_tool -change "./bin/libmilepost.dylib" "@rpath/libmilepost.dylib" bin/orca
install_name_tool -add_rpath "@executable_path/" bin/orca
else
echo "unknown build target $target"
fi

@ -1 +1 @@
Subproject commit c103c001f7c8e780602193f22360201810802438
Subproject commit d01dc832fbbc7b1e720476178a2c49a737717e0f

3
samples/fluid/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
Fluid
profile.dtrace
profile.spall

33
samples/fluid/build.bat Normal file
View File

@ -0,0 +1,33 @@
@echo off
:: compile wasm module
set wasmFlags=--target=wasm32^
--no-standard-libraries ^
-fno-builtin ^
-Wl,--no-entry ^
-Wl,--export-dynamic ^
-g ^
-O2 ^
-mbulk-memory ^
-D__ORCA__ ^
-isystem ..\..\cstdlib\include -I ..\..\sdk -I..\..\milepost\ext -I ..\..\milepost -I ..\..\milepost\src
set shaders=src/shaders/advect.glsl^
src/shaders/blit_div_fragment.glsl^
src/shaders/blit_div_vertex.glsl^
src/shaders/blit_fragment.glsl^
src/shaders/blit_residue_fragment.glsl^
src/shaders/blit_vertex.glsl^
src/shaders/common_vertex.glsl^
src/shaders/divergence.glsl^
src/shaders/jacobi_step.glsl^
src/shaders/multigrid_correct.glsl^
src/shaders/multigrid_restrict_residual.glsl^
src/shaders/splat.glsl^
src/shaders/subtract_pressure.glsl
call python3 ../../milepost/scripts/embed_text.py --prefix=glsl_ --output src/glsl_shaders.h %shaders%
clang %wasmFlags% -o .\module.wasm ..\..\sdk\orca.c ..\..\cstdlib\src\*.c src\main.c
python3 ..\..\scripts\mkapp.py --orca-dir ..\.. --icon icon.png --name Fluid module.wasm

35
samples/fluid/build.sh Executable file
View File

@ -0,0 +1,35 @@
#!/bin/bash
set -euo pipefail
if [[ -x /usr/local/opt/llvm/bin/clang ]]; then
CLANG=/usr/local/opt/llvm/bin/clang
elif [[ -x /opt/homebrew/opt/llvm/bin/clang ]]; then
CLANG=/opt/homebrew/opt/llvm/bin/clang
else
echo "Could not find Homebrew clang; this script will probably not work."
CLANG=clang
fi
STDLIB_DIR=../../cstdlib
ORCA_SDK_DIR=../../sdk
MILEPOST_DIR=../../milepost
python3 ../../milepost/scripts/embed_text.py --prefix=glsl_ --output src/glsl_shaders.h src/shaders/*.glsl
wasmFlags="--target=wasm32 \
--no-standard-libraries \
-fno-builtin \
-Wl,--no-entry \
-Wl,--export-dynamic \
-g \
-O2 \
-mbulk-memory \
-D__ORCA__ \
-I $STDLIB_DIR/include \
-I $ORCA_SDK_DIR \
-I $MILEPOST_DIR/ext -I $MILEPOST_DIR -I $MILEPOST_DIR/src"
$CLANG $wasmFlags -o ./module.wasm ../../sdk/orca.c ../../cstdlib/src/*.c src/main.c
orca bundle --orca-dir ../.. --icon icon.png --name Fluid module.wasm

BIN
samples/fluid/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

View File

@ -0,0 +1,551 @@
/*********************************************************************
*
* file: glsl_shaders.h
* note: string literals auto-generated by embed_text.py
* date: 08/082023
*
**********************************************************************/
#ifndef __GLSL_SHADERS_H__
#define __GLSL_SHADERS_H__
//NOTE: string imported from src/shaders/advect.glsl
const char* glsl_advect =
"#version 300 es\n"
"\n"
"precision highp float;\n"
"precision highp sampler2D;\n"
"\n"
"in vec2 texCoord;\n"
"out vec4 fragColor;\n"
"\n"
"uniform sampler2D src;\n"
"uniform sampler2D velocity;\n"
"uniform float delta;\n"
"uniform float dissipation;\n"
"\n"
"vec2 u(ivec2 coord)\n"
"{\n"
" return(texelFetch(velocity, coord, 0).xy);\n"
"}\n"
"\n"
"vec4 q(ivec2 coord)\n"
"{\n"
" if( coord.x < 0\n"
" || coord.x >= textureSize(src, 0).x\n"
" || coord.y < 0\n"
" || coord.y >= textureSize(src, 0).y)\n"
" {\n"
" return(vec4(0.));\n"
" }\n"
" return(texelFetch(src, coord, 0));\n"
"}\n"
"\n"
"vec4 bilerpSrc(vec2 pos)\n"
"{\n"
" vec2 offset = fract(pos);\n"
"\n"
" ivec2 bl = ivec2(floor(pos));\n"
"\n"
" ivec2 br = bl + ivec2(1, 0);\n"
" ivec2 tl = bl + ivec2(0, 1);\n"
" ivec2 tr = bl + ivec2(1, 1);\n"
"\n"
" vec4 lerpTop = (1.-offset.x)*q(tl) + offset.x*q(tr);\n"
" vec4 lerpBottom = (1.-offset.x)*q(bl) + offset.x*q(br);\n"
" vec4 result = (1.-offset.y)*lerpBottom + offset.y*lerpTop;\n"
"\n"
" return(result);\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" float texWidth = float(textureSize(velocity, 0).x);\n"
"\n"
" ivec2 pixelCoord = ivec2(floor(gl_FragCoord.xy));\n"
"\n"
" vec2 samplePos = vec2(pixelCoord) - texWidth * delta * u(pixelCoord);\n"
" fragColor = bilerpSrc(samplePos) / (1. + dissipation*delta);\n"
"}\n";
//NOTE: string imported from src/shaders/blit_div_fragment.glsl
const char* glsl_blit_div_fragment =
"#version 300 es\n"
"\n"
"precision highp float;\n"
"precision highp sampler2D;\n"
"\n"
"in vec2 texCoord;\n"
"out vec4 fragColor;\n"
"\n"
"uniform sampler2D tex;\n"
"\n"
"vec3 color_map(float v)\n"
"{\n"
" float logv = log(abs(v))/log(10.0);\n"
" float f = floor(logv + 7.0);\n"
" float i = floor(4.0*(logv + 7.0 - f));\n"
"\n"
" if(f < 0.0) return vec3(0.0);\n"
" if(f < 1.0) return mix(vec3(1.0, 0.0, 0.0), vec3(1.0), i/4.0);\n"
" if(f < 2.0) return mix(vec3(0.0, 1.0, 0.0), vec3(1.0), i/4.0);\n"
" if(f < 3.0) return mix(vec3(0.0, 0.0, 1.0), vec3(1.0), i/4.0);\n"
" if(f < 4.0) return mix(vec3(1.0, 1.0, 0.0), vec3(1.0), i/4.0);\n"
" if(f < 5.0) return mix(vec3(1.0, 0.0, 1.0), vec3(1.0), i/4.0);\n"
" if(f < 6.0) return mix(vec3(0.0, 1.0, 1.0), vec3(1.0), i/4.0);\n"
" if(f < 7.0) return mix(vec3(1.0, 0.5, 0.0), vec3(1.0), i/4.0);\n"
" if(f < 8.0) return mix(vec3(1.0, 1.0, 1.0), vec3(1.0), i/4.0);\n"
" return vec3(1.0);\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" ivec2 pixelCoord = ivec2(floor(texCoord.xy * vec2(textureSize(tex, 0).xy)));\n"
" float f = texelFetch(tex, pixelCoord, 0).x;\n"
" fragColor = vec4(color_map(f), 1.0);\n"
"}\n";
//NOTE: string imported from src/shaders/blit_div_vertex.glsl
const char* glsl_blit_div_vertex =
"#version 300 es\n"
"\n"
"precision highp float;\n"
"\n"
"in vec2 pos;\n"
"out vec2 texCoord;\n"
"\n"
"uniform mat4 mvp;\n"
"\n"
"void main()\n"
"{\n"
" texCoord = 0.5*(pos + vec2(1,1));\n"
" gl_Position = mvp * vec4(pos, 0, 1);\n"
"}\n";
//NOTE: string imported from src/shaders/blit_fragment.glsl
const char* glsl_blit_fragment =
"#version 300 es\n"
"\n"
"precision highp float;\n"
"precision highp sampler2D;\n"
"\n"
"in vec2 texCoord;\n"
"out vec4 fragColor;\n"
"\n"
"uniform sampler2D tex;\n"
"\n"
"void main()\n"
"{\n"
" fragColor = texture(tex, texCoord);\n"
" fragColor.a = 1.0;\n"
"}\n";
//NOTE: string imported from src/shaders/blit_residue_fragment.glsl
const char* glsl_blit_residue_fragment =
"#version 300 es\n"
"\n"
"precision highp float;\n"
"precision highp sampler2D;\n"
"\n"
"in vec2 texCoord;\n"
"out vec4 fragColor;\n"
"\n"
"uniform sampler2D xTex;\n"
"uniform sampler2D bTex;\n"
"\n"
"float x(ivec2 coord)\n"
"{\n"
" if( coord.x <= 0\n"
" || coord.x >= textureSize(xTex, 0).x\n"
" || coord.y <= 0\n"
" || coord.y >= textureSize(xTex, 0).y)\n"
" {\n"
" return(0.);\n"
" }\n"
" return(texelFetch(xTex, coord, 0).x);\n"
"}\n"
"\n"
"float b(ivec2 coord)\n"
"{\n"
" if( coord.x <= 0\n"
" || coord.x >= textureSize(bTex, 0).x\n"
" || coord.y <= 0\n"
" || coord.y >= textureSize(bTex, 0).y)\n"
" {\n"
" return(0.);\n"
" }\n"
" return(texelFetch(bTex, coord, 0).x);\n"
"}\n"
"\n"
"vec3 color_map(float v)\n"
"{\n"
" float logv = log(abs(v))/log(10.0);\n"
" float f = floor(logv + 7.0);\n"
" float i = floor(4.0*(logv + 7.0 - f));\n"
"\n"
" if(f < 0.0) return vec3(0.0);\n"
" if(f < 1.0) return mix(vec3(1.0, 0.0, 0.0), vec3(1.0), i/4.0);\n"
" if(f < 2.0) return mix(vec3(0.0, 1.0, 0.0), vec3(1.0), i/4.0);\n"
" if(f < 3.0) return mix(vec3(0.0, 0.0, 1.0), vec3(1.0), i/4.0);\n"
" if(f < 4.0) return mix(vec3(1.0, 1.0, 0.0), vec3(1.0), i/4.0);\n"
" if(f < 5.0) return mix(vec3(1.0, 0.0, 1.0), vec3(1.0), i/4.0);\n"
" if(f < 6.0) return mix(vec3(0.0, 1.0, 1.0), vec3(1.0), i/4.0);\n"
" if(f < 7.0) return mix(vec3(1.0, 0.5, 0.0), vec3(1.0), i/4.0);\n"
" if(f < 8.0) return mix(vec3(1.0, 1.0, 1.0), vec3(1.0), i/4.0);\n"
" return vec3(1.0);\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" ivec2 pixelCoord = ivec2(floor(texCoord.xy * vec2(textureSize(xTex, 0).xy)));\n"
"\n"
" float tl = x(pixelCoord + ivec2(-1, 1));\n"
" float tr = x(pixelCoord + ivec2(1, 1));\n"
" float bl = x(pixelCoord + ivec2(-1, -1));\n"
" float br = x(pixelCoord + ivec2(1, -1));\n"
"\n"
" float residue = b(pixelCoord) - (-tl - tr - bl - br + 4.*x(pixelCoord));\n"
" fragColor = vec4(color_map(residue), 1);\n"
"}\n";
//NOTE: string imported from src/shaders/blit_vertex.glsl
const char* glsl_blit_vertex =
"#version 300 es\n"
"\n"
"precision highp float;\n"
"\n"
"in vec2 pos;\n"
"out vec2 texCoord;\n"
"\n"
"uniform mat4 mvp;\n"
"uniform ivec2 gridSize;\n"
"\n"
"void main()\n"
"{\n"
" float margin = 32.;\n"
" float ratio = 1. - 2.*margin/float(gridSize.x);\n"
"\n"
" texCoord = margin/float(gridSize.x) + ratio*(0.5*(pos + vec2(1,1)));\n"
" gl_Position = mvp * vec4(pos, 0, 1);\n"
"}\n";
//NOTE: string imported from src/shaders/common_vertex.glsl
const char* glsl_common_vertex =
"#version 300 es\n"
"\n"
"precision highp float;\n"
"\n"
"in vec2 pos;\n"
"out vec2 texCoord;\n"
"\n"
"void main()\n"
"{\n"
" texCoord = 0.5*(pos + vec2(1,1));\n"
" gl_Position = vec4(pos, 0, 1);\n"
"}\n";
//NOTE: string imported from src/shaders/divergence.glsl
const char* glsl_divergence =
"#version 300 es\n"
"\n"
"precision highp float;\n"
"precision highp sampler2D;\n"
"\n"
"in vec2 texCoord;\n"
"out vec4 fragColor;\n"
"\n"
"uniform sampler2D src;\n"
"\n"
"vec2 u(ivec2 coord)\n"
"{\n"
" return(texelFetch(src, coord, 0).xy);\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" ivec2 pixelCoord = ivec2(floor(gl_FragCoord.xy));\n"
"\n"
" if( pixelCoord.x <= 0\n"
" || pixelCoord.x >= textureSize(src, 0).x\n"
" || pixelCoord.y <= 0\n"
" || pixelCoord.y >= textureSize(src, 0).y)\n"
" {\n"
" fragColor = vec4(0, 0, 0, 1);\n"
" }\n"
" else\n"
" {\n"
" vec2 tl = u(pixelCoord + ivec2(-1, 0));\n"
" vec2 tr = u(pixelCoord);\n"
" vec2 bl = u(pixelCoord + ivec2(-1, -1));\n"
" vec2 br = u(pixelCoord + ivec2(0, -1));\n"
"\n"
" float r = (tr.x + br.x)/2.;\n"
" float l = (tl.x + bl.x)/2.;\n"
" float t = (tl.y + tr.y)/2.;\n"
" float b = (bl.y + br.y)/2.;\n"
"\n"
" fragColor = vec4(-2.*(r - l + t - b), 0, 0, 1);\n"
" }\n"
"}\n";
//NOTE: string imported from src/shaders/jacobi_step.glsl
const char* glsl_jacobi_step =
"#version 300 es\n"
"\n"
"precision highp float;\n"
"precision highp sampler2D;\n"
"\n"
"in vec2 texCoord;\n"
"out vec4 fragColor;\n"
"\n"
"uniform sampler2D xTex;\n"
"uniform sampler2D bTex;\n"
"\n"
"float x(ivec2 coord)\n"
"{\n"
" if( coord.x <= 0\n"
" || coord.x >= textureSize(xTex, 0).x\n"
" || coord.y <= 0\n"
" || coord.y >= textureSize(xTex, 0).y)\n"
" {\n"
" return(0.);\n"
" }\n"
" return(texelFetch(xTex, coord, 0).x);\n"
"}\n"
"\n"
"float b(ivec2 coord)\n"
"{\n"
" if( coord.x <= 0\n"
" || coord.x >= textureSize(bTex, 0).x\n"
" || coord.y <= 0\n"
" || coord.y >= textureSize(bTex, 0).y)\n"
" {\n"
" return(0.);\n"
" }\n"
" return(texelFetch(bTex, coord, 0).x);\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" ivec2 pixelCoord = ivec2(floor(gl_FragCoord.xy));\n"
"\n"
" if( pixelCoord.x <= 0\n"
" || pixelCoord.y <= 0)\n"
" {\n"
" fragColor = vec4(0, 0, 0, 1);\n"
" }\n"
" else\n"
" {\n"
" float tl = x(pixelCoord + ivec2(-1, 1));\n"
" float tr = x(pixelCoord + ivec2(1, 1));\n"
" float bl = x(pixelCoord + ivec2(-1, -1));\n"
" float br = x(pixelCoord + ivec2(1, -1));\n"
"\n"
" float jacobi = (tl + tr + bl + br + b(pixelCoord))/4.;\n"
" fragColor = vec4(jacobi, 0, 0, 1);\n"
" }\n"
"}\n";
//NOTE: string imported from src/shaders/multigrid_correct.glsl
const char* glsl_multigrid_correct =
"#version 300 es\n"
"\n"
"precision highp float;\n"
"precision highp sampler2D;\n"
"\n"
"in vec2 texCoord;\n"
"out vec4 fragColor;\n"
"\n"
"uniform sampler2D src;\n"
"uniform sampler2D error;\n"
"uniform float invGridSize;\n"
"\n"
"float e(ivec2 coord)\n"
"{\n"
" if( coord.x <= 0\n"
" || coord.x >= textureSize(error, 0).x\n"
" || coord.y <= 0\n"
" || coord.y >= textureSize(error, 0).y)\n"
" {\n"
" return(0.);\n"
" }\n"
" return(texelFetch(error, coord, 0).x);\n"
"}\n"
"\n"
"float p(ivec2 coord)\n"
"{\n"
" if( coord.x <= 0\n"
" || coord.x >= textureSize(src, 0).x\n"
" || coord.y <= 0\n"
" || coord.y >= textureSize(src, 0).y)\n"
" {\n"
" return(0.);\n"
" }\n"
" return(texelFetch(src, coord, 0).x);\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" ivec2 pixelCoord = ivec2(floor(gl_FragCoord.xy));\n"
" vec2 coarseCoord = vec2(pixelCoord)/2.;\n"
" vec2 offset = fract(coarseCoord);\n"
"\n"
" ivec2 bl = ivec2(floor(coarseCoord));\n"
" ivec2 br = bl + ivec2(1, 0);\n"
" ivec2 tl = bl + ivec2(0, 1);\n"
" ivec2 tr = bl + ivec2(1, 1);\n"
"\n"
" float topLerp = (1.-offset.x)*e(tl)+ offset.x*e(tr);\n"
" float bottomLerp = (1.-offset.x)*e(bl) + offset.x*e(br);\n"
" float bilerpError = (1.-offset.y)*bottomLerp + offset.y*topLerp;\n"
"\n"
" fragColor = vec4(p(pixelCoord) + bilerpError, 0, 0, 1);\n"
"}\n";
//NOTE: string imported from src/shaders/multigrid_restrict_residual.glsl
const char* glsl_multigrid_restrict_residual =
"#version 300 es\n"
"\n"
"precision highp float;\n"
"precision highp sampler2D;\n"
"\n"
"in vec2 texCoord;\n"
"out vec4 fragColor;\n"
"\n"
"uniform sampler2D xTex;\n"
"uniform sampler2D bTex;\n"
"\n"
"float x(ivec2 coord)\n"
"{\n"
" if( coord.x <= 0\n"
" || coord.x >= textureSize(xTex, 0).x\n"
" || coord.y <= 0\n"
" || coord.y >= textureSize(xTex, 0).y)\n"
" {\n"
" return(0.);\n"
" }\n"
" return(texelFetch(xTex, coord, 0).x);\n"
"}\n"
"\n"
"float b(ivec2 coord)\n"
"{\n"
" if( coord.x <= 0\n"
" || coord.x >= textureSize(bTex, 0).x\n"
" || coord.y <= 0\n"
" || coord.y >= textureSize(bTex, 0).y)\n"
" {\n"
" return(0.);\n"
" }\n"
" return(texelFetch(bTex, coord, 0).x);\n"
"}\n"
"\n"
"float residual(ivec2 coord)\n"
"{\n"
" ivec2 vr = coord + ivec2(1, 0);\n"
" ivec2 vl = coord - ivec2(1, 0);\n"
" ivec2 vt = coord + ivec2(0, 1);\n"
" ivec2 vb = coord - ivec2(0, 1);\n"
"\n"
" return((x(vl) + x(vr) + x(vt) + x(vb) + b(coord) - 4.*x(coord))*4.);\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" ivec2 pixelCoord = ivec2(floor(gl_FragCoord.xy));\n"
"\n"
" float restricted = residual(2*pixelCoord + ivec2(-1, -1))\n"
" + residual(2*pixelCoord + ivec2(1, -1))\n"
" + residual(2*pixelCoord + ivec2(1, 1))\n"
" + residual(2*pixelCoord + ivec2(-1, 1))\n"
" + 2.*residual(2*pixelCoord + ivec2(-1, 0))\n"
" + 2.*residual(2*pixelCoord + ivec2(1, 0))\n"
" + 2.*residual(2*pixelCoord + ivec2(0, -1))\n"
" + 2.*residual(2*pixelCoord + ivec2(0, 1))\n"
" + 4.*residual(2*pixelCoord);\n"
" restricted /= 16.;\n"
" fragColor = vec4(restricted, 0, 0, 1);\n"
"}\n";
//NOTE: string imported from src/shaders/splat.glsl
const char* glsl_splat =
"#version 300 es\n"
"\n"
"precision highp float;\n"
"precision highp sampler2D;\n"
"\n"
"in vec2 texCoord;\n"
"out vec4 fragColor;\n"
"\n"
"uniform sampler2D src;\n"
"uniform vec2 splatPos;\n"
"uniform vec3 splatColor;\n"
"uniform float radius;\n"
"uniform float additive;\n"
"uniform float blending;\n"
"\n"
"uniform float randomize;\n"
"\n"
"void main()\n"
"{\n"
" float d2 = dot(texCoord - splatPos, texCoord - splatPos);\n"
" float intensity = exp(-10.*d2/radius);\n"
" vec2 force = splatColor.xy;\n"
"\n"
" vec3 u = texture(src, texCoord).xyz;\n"
" vec3 uAdd = u + intensity*splatColor.xyz;\n"
" vec3 uBlend = u*(1.-intensity) + intensity * splatColor;\n"
"\n"
" fragColor = vec4(uAdd*additive + uBlend*blending, 1);\n"
"}\n";
//NOTE: string imported from src/shaders/subtract_pressure.glsl
const char* glsl_subtract_pressure =
"#version 300 es\n"
"\n"
"precision highp float;\n"
"precision highp sampler2D;\n"
"\n"
"in vec2 texCoord;\n"
"out vec4 fragColor;\n"
"\n"
"uniform sampler2D src;\n"
"uniform sampler2D pressure;\n"
"uniform float invGridSize;\n"
"\n"
"vec2 u(ivec2 coord)\n"
"{\n"
" return(texelFetch(src, coord, 0).xy);\n"
"}\n"
"\n"
"float p(ivec2 coord)\n"
"{\n"
" if( coord.x <= 0\n"
" || coord.x >= textureSize(pressure, 0).x\n"
" || coord.y <= 0\n"
" || coord.y >= textureSize(pressure, 0).y)\n"
" {\n"
" return(0.);\n"
" }\n"
" return(texelFetch(pressure, coord, 0).x);\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" ivec2 pixelCoord = ivec2(floor(gl_FragCoord.xy));\n"
"\n"
" float tl = p(pixelCoord + ivec2(0, 1));\n"
" float tr = p(pixelCoord + ivec2(1, 1));\n"
" float bl = p(pixelCoord);\n"
" float br = p(pixelCoord + ivec2(1, 0));\n"
"\n"
" float r = (tr + br)/2.;\n"
" float l = (tl + bl)/2.;\n"
" float t = (tl + tr)/2.;\n"
" float b = (bl + br)/2.;\n"
"\n"
" vec2 gradP = vec2(r - l, t - b);\n"
"\n"
" fragColor = vec4(u(pixelCoord) - gradP, 0, 1);\n"
"}\n";
#endif // __GLSL_SHADERS_H__

928
samples/fluid/src/main.c Normal file
View File

@ -0,0 +1,928 @@
/************************************************************//**
*
* @file: main.cpp
* @author: Martin Fouilleul
* @date: 27/02/2022
* @revision:
*
*****************************************************************/
#include"orca.h"
#include"glsl_shaders.h"
//----------------------------------------------------------------
//NOTE(martin): GL vertex struct and identifiers
//----------------------------------------------------------------
typedef struct Vertex { float x, y; } Vertex;
typedef struct advect_program
{
GLuint prog;
GLint pos;
GLint src;
GLint velocity;
GLint delta;
GLint dissipation;
} advect_program;
typedef struct div_program
{
GLuint prog;
GLint pos;
GLint src;
} div_program;
typedef struct jacobi_program
{
GLuint prog;
GLint pos;
GLint xTex;
GLint bTex;
} jacobi_program;
typedef struct blit_residue_program
{
GLuint prog;
GLint pos;
GLint mvp;
GLint xTex;
GLint bTex;
} blit_residue_program;
typedef struct multigrid_restrict_residual_program
{
GLuint prog;
GLint pos;
GLint xTex;
GLint bTex;
} multigrid_restrict_residual_program;
typedef struct multigrid_correct_program
{
GLuint prog;
GLint pos;
GLint src;
GLint error;
GLint invGridSize;
} multigrid_correct_program;
typedef struct subtract_program
{
GLuint prog;
GLint pos;
GLint src;
GLint pressure;
GLint invGridSize;
} subtract_program;
typedef struct blit_program
{
GLuint prog;
GLint pos;
GLint mvp;
GLint gridSize;
GLint tex;
} blit_program;
typedef struct splat_program
{
GLuint prog;
GLint pos;
GLint src;
GLint splatPos;
GLint splatColor;
GLint radius;
GLint additive;
GLint blending;
GLint randomize;
} splat_program;
typedef struct frame_buffer
{
GLuint textures[2];
GLuint fbos[2];
} frame_buffer;
advect_program advectProgram;
div_program divProgram;
jacobi_program jacobiProgram;
multigrid_restrict_residual_program multigridRestrictResidualProgram;
multigrid_correct_program multigridCorrectProgram;
subtract_program subtractProgram;
splat_program splatProgram;
blit_program blitProgram;
blit_program blitDivProgram;
blit_residue_program blitResidueProgram;
frame_buffer colorBuffer;
frame_buffer velocityBuffer;
const int MULTIGRID_COUNT = 4;
frame_buffer pressureBuffer[4];
frame_buffer divBuffer[4];
GLuint vertexBuffer;
//----------------------------------------------------------------
//NOTE(martin): initialization
//----------------------------------------------------------------
GLuint compile_shader(const char* vs, const char* fs)
{
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vs, 0);
glCompileShader(vertexShader);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fs, 0);
glCompileShader(fragmentShader);
GLuint prog = glCreateProgram();
glAttachShader(prog, vertexShader);
glAttachShader(prog, fragmentShader);
glLinkProgram(prog);
//TODO errors
int status = 0;
glGetProgramiv(prog, GL_LINK_STATUS, &status);
if(status != GL_TRUE)
{
log_error("program failed to link: ");
int logSize = 0;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logSize);
mem_arena_scope scratch = mem_scratch_begin();
char* log = mem_arena_alloc(scratch.arena, logSize);
glGetProgramInfoLog(prog, logSize, 0, log);
log_error("%s\n", log);
mem_scratch_end(scratch);
}
int err = glGetError();
if(err)
{
log_error("gl error %i\n", err);
}
return(prog);
}
void init_advect(advect_program* program)
{
log_info("compiling advect...");
program->prog = compile_shader(glsl_common_vertex, glsl_advect);
program->pos = glGetAttribLocation(program->prog, "pos");
program->src = glGetUniformLocation(program->prog, "src");
program->velocity = glGetUniformLocation(program->prog, "velocity");
program->delta = glGetUniformLocation(program->prog, "delta");
program->dissipation = glGetUniformLocation(program->prog, "dissipation");
}
void init_div(div_program* program)
{
log_info("compiling div...");
program->prog = compile_shader(glsl_common_vertex, glsl_divergence);
program->pos = glGetAttribLocation(program->prog, "pos");
program->src = glGetUniformLocation(program->prog, "src");
}
void init_jacobi(jacobi_program* program)
{
log_info("compiling jacobi...");
program->prog = compile_shader(glsl_common_vertex, glsl_jacobi_step);
program->pos = glGetAttribLocation(program->prog, "pos");
program->xTex = glGetUniformLocation(program->prog, "xTex");
program->bTex = glGetUniformLocation(program->prog, "bTex");
}
void init_multigrid_restrict_residual(multigrid_restrict_residual_program* program)
{
log_info("compiling multigrid restrict residual...");
program->prog = compile_shader(glsl_common_vertex, glsl_multigrid_restrict_residual);
program->pos = glGetAttribLocation(program->prog, "pos");
program->xTex = glGetUniformLocation(program->prog, "xTex");
program->bTex = glGetUniformLocation(program->prog, "bTex");
}
void init_multigrid_correct(multigrid_correct_program* program)
{
log_info("compiling multigrid correct...");
program->prog = compile_shader(glsl_common_vertex, glsl_multigrid_correct);
program->pos = glGetAttribLocation(program->prog, "pos");
program->src = glGetUniformLocation(program->prog, "src");
program->error = glGetUniformLocation(program->prog, "error");
program->invGridSize = glGetUniformLocation(program->prog, "invGridSize");
}
void init_subtract(subtract_program* program)
{
log_info("compiling subtract...");
program->prog = compile_shader(glsl_common_vertex, glsl_subtract_pressure);
program->pos = glGetAttribLocation(program->prog, "pos");
program->src = glGetUniformLocation(program->prog, "src");
program->pressure = glGetUniformLocation(program->prog, "pressure");
program->invGridSize = glGetUniformLocation(program->prog, "invGridSize");
}
void init_splat(splat_program* program)
{
log_info("compiling splat...");
program->prog = compile_shader(glsl_common_vertex, glsl_splat);
program->pos = glGetAttribLocation(program->prog, "pos");
program->src = glGetUniformLocation(program->prog, "src");
program->splatPos = glGetUniformLocation(program->prog, "splatPos");
program->splatColor = glGetUniformLocation(program->prog, "splatColor");
program->radius = glGetUniformLocation(program->prog, "radius");
program->additive = glGetUniformLocation(program->prog, "additive");
program->blending = glGetUniformLocation(program->prog, "blending");
program->randomize = glGetUniformLocation(program->prog, "randomize");
}
void init_blit(blit_program* program)
{
log_info("compiling blit...");
program->prog = compile_shader(glsl_blit_vertex, glsl_blit_fragment);
program->pos = glGetAttribLocation(program->prog, "pos");
program->mvp = glGetUniformLocation(program->prog, "mvp");
program->tex = glGetUniformLocation(program->prog, "tex");
program->gridSize = glGetUniformLocation(program->prog, "gridSize");
}
void init_blit_div(blit_program* program)
{
log_info("compiling blit div...");
program->prog = compile_shader(glsl_blit_div_vertex, glsl_blit_div_fragment);
program->pos = glGetAttribLocation(program->prog, "pos");
program->mvp = glGetUniformLocation(program->prog, "mvp");
program->tex = glGetUniformLocation(program->prog, "tex");
}
void init_blit_residue(blit_residue_program* program)
{
log_info("compiling blit residue...");
program->prog = compile_shader(glsl_blit_div_vertex, glsl_blit_residue_fragment);
program->pos = glGetAttribLocation(program->prog, "pos");
program->mvp = glGetUniformLocation(program->prog, "mvp");
program->xTex = glGetUniformLocation(program->prog, "xTex");
program->bTex = glGetUniformLocation(program->prog, "bTex");
}
GLuint create_texture(int width, int height, GLenum internalFormat, GLenum format, GLenum type, char* initData)
{
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, initData);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
return(texture);
}
GLuint create_fbo(GLuint texture)
{
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glBindTexture(GL_TEXTURE_2D, texture);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
return(fbo);
}
void init_frame_buffer(frame_buffer* framebuffer,
int width,
int height,
GLenum internalFormat,
GLenum format,
GLenum type,
char* initData)
{
for(int i=0; i<2; i++)
{
framebuffer->textures[i] = create_texture(width, height, internalFormat, format, type, initData);
framebuffer->fbos[i] = create_fbo(framebuffer->textures[i]);
}
GLenum err = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(err != GL_FRAMEBUFFER_COMPLETE)
{
log_info("Frame buffer incomplete, %i", err);
}
}
void frame_buffer_swap(frame_buffer* buffer)
{
GLuint tmp = buffer->fbos[0];
buffer->fbos[0] = buffer->fbos[1];
buffer->fbos[1] = tmp;
tmp = buffer->textures[0];
buffer->textures[0] = buffer->textures[1];
buffer->textures[1] = tmp;
}
//----------------------------------------------------------------
//NOTE(martin): entry point
//----------------------------------------------------------------
#define texWidth (256)
#define texHeight (256)
float colorInitData[texWidth][texHeight][4] = {0};
float velocityInitData[texWidth][texHeight][4] = {0};
const float EPSILON = 1.,
INV_GRID_SIZE = 1./(float)texWidth,
DELTA = 1./120.;
const GLenum TEX_INTERNAL_FORMAT = GL_RGBA32F;
const GLenum TEX_FORMAT = GL_RGBA;
const GLenum TEX_TYPE = GL_FLOAT;
#define square(x) ((x)*(x))
/*
void reset_texture(GLuint texture, float width, float height, char* initData)
{
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, TEX_INTERNAL_FORMAT, width, height, 0, TEX_FORMAT, TEX_TYPE, initData);
}
static bool resetCmd = false;
void reset()
{
// resetCmd = true;
log_info("reset");
reset_texture(colorBuffer.textures[0], texWidth, texHeight, (char*)colorInitData);
reset_texture(colorBuffer.textures[1], texWidth, texHeight, (char*)colorInitData);
reset_texture(velocityBuffer.textures[0], texWidth, texHeight, (char*)velocityInitData);
reset_texture(velocityBuffer.textures[1], texWidth, texHeight, (char*)velocityInitData);
int gridFactor = 1;
for(int i=0; i<MULTIGRID_COUNT; i++)
{
reset_texture(pressureBuffer[i].textures[0], texWidth/gridFactor, texHeight/gridFactor, 0);
reset_texture(pressureBuffer[i].textures[1], texWidth/gridFactor, texHeight/gridFactor, 0);
gridFactor *= 2;
}
}
*/
typedef struct mouse_input
{
float x;
float y;
float deltaX;
float deltaY;
bool down;
} mouse_input;
mouse_input mouseInput = {0};
int frameWidth = 800;
int frameHeight = 600;
ORCA_EXPORT void OnMouseDown(int button)
{
mouseInput.down = true;
}
ORCA_EXPORT void OnMouseUp(int button)
{
mouseInput.down = false;
}
ORCA_EXPORT void OnMouseMove(float x, float y, float dx, float dy)
{
mouseInput.x = x * 2;
mouseInput.y = y * 2;
mouseInput.deltaX = dx * 2;
mouseInput.deltaY = dy * 2;
}
void init_color_checker()
{
for(int i=0; i<texHeight; i++)
{
for(int j=0; j<texWidth; j++)
{
float u = j/(float)texWidth;
float v = i/(float)texWidth;
float value = ((int)(u*10)%2) == ((int)(v*10)%2) ? 1. : 0.;
for(int k = 0; k<3; k++)
{
colorInitData[i][j][k] = value;
}
colorInitData[i][j][3] = 1;
}
}
}
void init_velocity_vortex()
{
for(int i=0; i<texHeight; i++)
{
for(int j=0; j<texWidth; j++)
{
float x = 2*j/(float)texWidth - 1;
float y = 2*i/(float)texWidth - 1;
velocityInitData[i][j][0] = sinf(2*M_PI*y);
velocityInitData[i][j][1] = sinf(2*M_PI*x);
}
}
}
void apply_splat(float splatPosX, float splatPosY, float radius, float splatVelX, float splatVelY, float r, float g, float b, bool randomize)
{
glUseProgram(splatProgram.prog);
if(randomize)
{
glUniform1f(splatProgram.randomize, 1.);
}
else
{
glUniform1f(splatProgram.randomize, 0.);
}
// force
glBindFramebuffer(GL_FRAMEBUFFER, velocityBuffer.fbos[1]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, velocityBuffer.textures[0]);
glUniform1i(splatProgram.src, 0);
glUniform2f(splatProgram.splatPos, splatPosX, splatPosY);
glUniform3f(splatProgram.splatColor, splatVelX, splatVelY, 0);
glUniform1f(splatProgram.additive, 1);
glUniform1f(splatProgram.blending, 0);
glUniform1f(splatProgram.radius, radius);
glDrawArrays(GL_TRIANGLES, 0, 6);
frame_buffer_swap(&velocityBuffer);
// dye
glBindFramebuffer(GL_FRAMEBUFFER, colorBuffer.fbos[1]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, colorBuffer.textures[0]);
glUniform1i(splatProgram.src, 0);
glUniform2f(splatProgram.splatPos, splatPosX, splatPosY);
glUniform3f(splatProgram.splatColor, r, g, b);
glUniform1f(splatProgram.additive, 0);
glUniform1f(splatProgram.blending, 1);
glUniform1f(splatProgram.radius, radius);
glDrawArrays(GL_TRIANGLES, 0, 6);
frame_buffer_swap(&colorBuffer);
}
void jacobi_solve(frame_buffer* x, frame_buffer* b, float invGridSize, int iterationCount)
{
glUseProgram(jacobiProgram.prog);
for(int i=0; i<iterationCount; i++)
{
glBindFramebuffer(GL_FRAMEBUFFER, x->fbos[1]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, x->textures[0]);
glUniform1i(jacobiProgram.xTex, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, b->textures[0]);
glUniform1i(jacobiProgram.bTex, 1);
glDrawArrays(GL_TRIANGLES, 0, 6);
frame_buffer_swap(x);
}
}
void multigrid_coarsen_residual(frame_buffer* output, frame_buffer* x, frame_buffer* b, float invFineGridSize)
{
//NOTE: compute residual and downsample to coarser grid, put result in coarser buffer
glUseProgram(multigridRestrictResidualProgram.prog);
glBindFramebuffer(GL_FRAMEBUFFER, output->fbos[1]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, x->textures[0]);
glUniform1i(multigridRestrictResidualProgram.xTex, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, b->textures[0]);
glUniform1i(multigridRestrictResidualProgram.bTex, 1);
glDrawArrays(GL_TRIANGLES, 0, 6);
frame_buffer_swap(output);
}
void multigrid_prolongate_and_correct(frame_buffer* x, frame_buffer* error, float invFineGridSize)
{
//NOTE: correct finer pressure
glUseProgram(multigridCorrectProgram.prog);
glBindFramebuffer(GL_FRAMEBUFFER, x->fbos[1]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, x->textures[0]);
glUniform1i(multigridCorrectProgram.src, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, error->textures[0]);
glUniform1i(multigridCorrectProgram.error, 1);
glUniform1f(multigridCorrectProgram.invGridSize, invFineGridSize);
glDrawArrays(GL_TRIANGLES, 0, 6);
frame_buffer_swap(x);
}
void multigrid_clear(frame_buffer* error)
{
glBindFramebuffer(GL_FRAMEBUFFER, error->fbos[0]);
glClear(GL_COLOR_BUFFER_BIT);
}
void input_splat(float t)
{
//NOTE: apply force and dye
if(mouseInput.down && (mouseInput.deltaX || mouseInput.deltaY))
{
// account for margin
float margin = 32;
float offset = margin/texWidth;
float ratio = 1 - 2*margin/texWidth;
float splatPosX = (mouseInput.x/frameWidth)*ratio + offset;
float splatPosY = (1 - mouseInput.y/frameHeight)*ratio + offset;
float splatVelX = (10000.*DELTA*mouseInput.deltaX/frameWidth)*ratio;
float splatVelY = (-10000.*DELTA*mouseInput.deltaY/frameWidth)*ratio;
float intensity = 100*sqrtf(square(ratio*mouseInput.deltaX/frameWidth) + square(ratio*mouseInput.deltaY/frameHeight));
float r = intensity * (sinf(2*M_PI*0.1*t) + 1);
float g = 0.5*intensity * (cosf(2*M_PI*0.1/M_E*t + 654) + 1);
float b = intensity * (sinf(2*M_PI*0.1/M_SQRT2*t + 937) + 1);
float radius = 0.005;
apply_splat(splatPosX, splatPosY, radius, splatVelX, splatVelY, r, g, b, false);
mouseInput.deltaX = 0;
mouseInput.deltaY = 0;
}
}
float testDiv[texWidth/2][texWidth/2][4];
mg_surface surface;
ORCA_EXPORT void OnInit()
{
log_info("Hello, world (from C)");
surface = mg_surface_gles();
mg_surface_prepare(surface);
// init_color_checker();
// init_velocity_vortex();
// init programs
init_advect(&advectProgram);
init_div(&divProgram);
init_jacobi(&jacobiProgram);
init_multigrid_restrict_residual(&multigridRestrictResidualProgram);
init_multigrid_correct(&multigridCorrectProgram);
init_blit_residue(&blitResidueProgram);
init_subtract(&subtractProgram);
init_splat(&splatProgram);
init_blit(&blitProgram);
init_blit_div(&blitDivProgram);
// init frame buffers
log_info("create color buffer");
init_frame_buffer(&colorBuffer, texWidth, texHeight, TEX_INTERNAL_FORMAT, TEX_FORMAT, TEX_TYPE, (char*)colorInitData);
log_info("create velocity buffer");
init_frame_buffer(&velocityBuffer, texWidth, texHeight, TEX_INTERNAL_FORMAT, TEX_FORMAT, TEX_TYPE, (char*)velocityInitData);
int gridFactor = 1;
for(int i=0; i<MULTIGRID_COUNT; i++)
{
log_info("create div buffer %i", i);
init_frame_buffer(&divBuffer[i], texWidth/gridFactor, texHeight/gridFactor, TEX_INTERNAL_FORMAT, TEX_FORMAT, TEX_TYPE, 0);
log_info("create pressure buffer %i", i);
init_frame_buffer(&pressureBuffer[i], texWidth/gridFactor, texHeight/gridFactor, TEX_INTERNAL_FORMAT, TEX_FORMAT, TEX_TYPE, 0);
gridFactor *= 2;
}
// init vertex buffer
static Vertex vertices[6] =
{
{-1, -1},
{ 1, -1},
{ 1, 1},
{-1, -1},
{ 1, 1},
{ -1, 1}
};
//WARN: we assume blitProgram.pos == advectProgram.pos, is there a situation where it wouldn't be true??
GLuint vertexBuffer = 0;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, 6*sizeof(Vertex), vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(blitProgram.pos, 2, GL_FLOAT, GL_FALSE, 0, 0);
for(int i=0; i<texWidth/2; i++)
{
for(int j=0; j<texHeight/2; j++)
{
testDiv[i][j][0] = 0.5 + 0.5*cosf(j/100.*3.14159 + i/100.*1.2139);
}
}
}
ORCA_EXPORT void OnFrameResize(u32 width, u32 height)
{
frameWidth = width*2;
frameHeight = height*2;
}
ORCA_EXPORT void OnFrameRefresh()
{
float aspectRatio = texWidth/texHeight; //TODO replace with actual aspect ratio?
static float t = 0;
t += 1./60.;
mg_surface_prepare(surface);
glViewport(0, 0, texWidth, texHeight);
//NOTE: advect velocity thru itself
glUseProgram(advectProgram.prog);
glBindFramebuffer(GL_FRAMEBUFFER, velocityBuffer.fbos[1]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, velocityBuffer.textures[0]);
glUniform1i(advectProgram.src, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, velocityBuffer.textures[0]);
glUniform1i(advectProgram.velocity, 1);
glUniform1f(advectProgram.delta, DELTA);
glUniform1f(advectProgram.dissipation, 0.01);
glDrawArrays(GL_TRIANGLES, 0, 6);
frame_buffer_swap(&velocityBuffer);
/*
//DEBUG
static bool splatTrig = false;
static bool splat = false;
static float splatStart = 0;
static int splatDir = 0;
static int frameCount = 0;
if(resetCmd)
{
frameCount = 0;
splat = true;
splatStart = frameT;
}
if(splat)
{
if(frameT - splatStart >= 0.5)
{
splat = false;
splatDir++;
splatDir = splatDir % 3;
}
float dirX = 0;
float dirY = 0;
if(splatDir == 0)
{
dirX = 0;
dirY = 0.3;
}
if(splatDir == 1)
{
dirX = 0.3;
dirY = 0;
}
if(splatDir == 2)
{
dirX = 0.2121;
dirY = 0.2121;
}
apply_splat(0.5, 0.5, dirX, dirY, 1.5, 1., 0.1, false);
}
resetCmd = false;
if(frameCount>20)
{
return;
}
frameCount++;
*/
input_splat(t);
//NOTE: compute divergence of advected velocity
glUseProgram(divProgram.prog);
glBindFramebuffer(GL_FRAMEBUFFER, divBuffer[0].fbos[1]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, velocityBuffer.textures[0]);
glUniform1i(divProgram.src, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
frame_buffer_swap(&divBuffer[0]);
//NOTE: compute pressure
glBindFramebuffer(GL_FRAMEBUFFER, pressureBuffer[0].fbos[1]);
glClear(GL_COLOR_BUFFER_BIT);
#if 0
multigrid_clear(&pressureBuffer[0]);
jacobi_solve(&pressureBuffer[0], &divBuffer[0], INV_GRID_SIZE, texWidth*texHeight);
#else
multigrid_clear(&pressureBuffer[0]);
for(int i=0; i<1; i++)
{
jacobi_solve(&pressureBuffer[0], &divBuffer[0], INV_GRID_SIZE, 2);
multigrid_coarsen_residual(&divBuffer[1], &pressureBuffer[0], &divBuffer[0], INV_GRID_SIZE);
multigrid_clear(&pressureBuffer[1]);
jacobi_solve(&pressureBuffer[1], &divBuffer[1], 2*INV_GRID_SIZE, 2);
multigrid_coarsen_residual(&divBuffer[2], &pressureBuffer[1], &divBuffer[1], 2*INV_GRID_SIZE);
multigrid_clear(&pressureBuffer[2]);
jacobi_solve(&pressureBuffer[2], &divBuffer[2], 4*INV_GRID_SIZE, 30);
multigrid_prolongate_and_correct(&pressureBuffer[1], &pressureBuffer[2], 2*INV_GRID_SIZE);
jacobi_solve(&pressureBuffer[1], &divBuffer[1], 2*INV_GRID_SIZE, 8);
multigrid_prolongate_and_correct(&pressureBuffer[0], &pressureBuffer[1], INV_GRID_SIZE);
jacobi_solve(&pressureBuffer[0], &divBuffer[0], INV_GRID_SIZE, 4);
}
#endif
//NOTE: subtract pressure gradient to advected velocity
glUseProgram(subtractProgram.prog);
glBindFramebuffer(GL_FRAMEBUFFER, velocityBuffer.fbos[1]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, velocityBuffer.textures[0]);
glUniform1i(subtractProgram.src, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, pressureBuffer[0].textures[0]);
glUniform1i(subtractProgram.pressure, 1);
glUniform1f(subtractProgram.invGridSize, INV_GRID_SIZE);
glDrawArrays(GL_TRIANGLES, 0, 6);
frame_buffer_swap(&velocityBuffer);
//NOTE: Advect color through corrected velocity field
glUseProgram(advectProgram.prog);
glBindFramebuffer(GL_FRAMEBUFFER, colorBuffer.fbos[1]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, colorBuffer.textures[0]);
glUniform1i(advectProgram.src, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, velocityBuffer.textures[0]);
glUniform1i(advectProgram.velocity, 1);
glUniform1f(advectProgram.delta, DELTA);
glUniform1f(advectProgram.dissipation, 0.001);
glDrawArrays(GL_TRIANGLES, 0, 6);
frame_buffer_swap(&colorBuffer);
//NOTE: Blit color texture to screen
//NOTE: blit residue to screen
glViewport(0, 0, frameWidth, frameHeight);
float displayMatrix[16] = {
1/aspectRatio, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1 };
/*
glUseProgram(blitResidueProgram.prog);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, pressureBuffer[0].textures[0]);
glUniform1i(blitResidueProgram.xTex, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, divBuffer[0].textures[0]);
glUniform1i(blitResidueProgram.bTex, 1);
glUniformMatrix4fv(blitResidueProgram.mvp, 1, GL_FALSE, displayMatrix);
glDrawArrays(GL_TRIANGLES, 0, 6);
//*/
//*
glUseProgram(blitProgram.prog);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, colorBuffer.textures[0]);
glUniform1i(blitProgram.tex, 0);
glUniform2i(blitProgram.gridSize, texWidth, texHeight);
glUniformMatrix4fv(blitProgram.mvp, 1, GL_FALSE, displayMatrix);
glDrawArrays(GL_TRIANGLES, 0, 6);
/*/
//NOTE: recompute divergence of (corrected) velocity
glUseProgram(divProgram.prog);
glBindFramebuffer(GL_FRAMEBUFFER, divBuffer[0].fbos[1]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, velocityBuffer.textures[0]);
glUniform1i(divProgram.src, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
frame_buffer_swap(&divBuffer[0]);
//NOTE: Blit divergence to screen
glViewport(0, 0, canvas_width(), canvas_height());
glUseProgram(blitDivProgram.prog);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, divBuffer[0].textures[0]);
glUniform1i(blitDivProgram.tex, 0);
glUniformMatrix4fv(blitDivProgram.mvp, 1, GL_FALSE, displayMatrix);
glDrawArrays(GL_TRIANGLES, 0, 6);
//*/
mg_surface_present(surface);
}

View File

@ -0,0 +1,56 @@
#version 300 es
precision highp float;
precision highp sampler2D;
in vec2 texCoord;
out vec4 fragColor;
uniform sampler2D src;
uniform sampler2D velocity;
uniform float delta;
uniform float dissipation;
vec2 u(ivec2 coord)
{
return(texelFetch(velocity, coord, 0).xy);
}
vec4 q(ivec2 coord)
{
if( coord.x < 0
|| coord.x >= textureSize(src, 0).x
|| coord.y < 0
|| coord.y >= textureSize(src, 0).y)
{
return(vec4(0.));
}
return(texelFetch(src, coord, 0));
}
vec4 bilerpSrc(vec2 pos)
{
vec2 offset = fract(pos);
ivec2 bl = ivec2(floor(pos));
ivec2 br = bl + ivec2(1, 0);
ivec2 tl = bl + ivec2(0, 1);
ivec2 tr = bl + ivec2(1, 1);
vec4 lerpTop = (1.-offset.x)*q(tl) + offset.x*q(tr);
vec4 lerpBottom = (1.-offset.x)*q(bl) + offset.x*q(br);
vec4 result = (1.-offset.y)*lerpBottom + offset.y*lerpTop;
return(result);
}
void main()
{
float texWidth = float(textureSize(velocity, 0).x);
ivec2 pixelCoord = ivec2(floor(gl_FragCoord.xy));
vec2 samplePos = vec2(pixelCoord) - texWidth * delta * u(pixelCoord);
fragColor = bilerpSrc(samplePos) / (1. + dissipation*delta);
}

View File

@ -0,0 +1,34 @@
#version 300 es
precision highp float;
precision highp sampler2D;
in vec2 texCoord;
out vec4 fragColor;
uniform sampler2D tex;
vec3 color_map(float v)
{
float logv = log(abs(v))/log(10.0);
float f = floor(logv + 7.0);
float i = floor(4.0*(logv + 7.0 - f));
if(f < 0.0) return vec3(0.0);
if(f < 1.0) return mix(vec3(1.0, 0.0, 0.0), vec3(1.0), i/4.0);
if(f < 2.0) return mix(vec3(0.0, 1.0, 0.0), vec3(1.0), i/4.0);
if(f < 3.0) return mix(vec3(0.0, 0.0, 1.0), vec3(1.0), i/4.0);
if(f < 4.0) return mix(vec3(1.0, 1.0, 0.0), vec3(1.0), i/4.0);
if(f < 5.0) return mix(vec3(1.0, 0.0, 1.0), vec3(1.0), i/4.0);
if(f < 6.0) return mix(vec3(0.0, 1.0, 1.0), vec3(1.0), i/4.0);
if(f < 7.0) return mix(vec3(1.0, 0.5, 0.0), vec3(1.0), i/4.0);
if(f < 8.0) return mix(vec3(1.0, 1.0, 1.0), vec3(1.0), i/4.0);
return vec3(1.0);
}
void main()
{
ivec2 pixelCoord = ivec2(floor(texCoord.xy * vec2(textureSize(tex, 0).xy)));
float f = texelFetch(tex, pixelCoord, 0).x;
fragColor = vec4(color_map(f), 1.0);
}

View File

@ -0,0 +1,14 @@
#version 300 es
precision highp float;
in vec2 pos;
out vec2 texCoord;
uniform mat4 mvp;
void main()
{
texCoord = 0.5*(pos + vec2(1,1));
gl_Position = mvp * vec4(pos, 0, 1);
}

View File

@ -0,0 +1,15 @@
#version 300 es
precision highp float;
precision highp sampler2D;
in vec2 texCoord;
out vec4 fragColor;
uniform sampler2D tex;
void main()
{
fragColor = texture(tex, texCoord);
fragColor.a = 1.0;
}

View File

@ -0,0 +1,65 @@
#version 300 es
precision highp float;
precision highp sampler2D;
in vec2 texCoord;
out vec4 fragColor;
uniform sampler2D xTex;
uniform sampler2D bTex;
float x(ivec2 coord)
{
if( coord.x <= 0
|| coord.x >= textureSize(xTex, 0).x
|| coord.y <= 0
|| coord.y >= textureSize(xTex, 0).y)
{
return(0.);
}
return(texelFetch(xTex, coord, 0).x);
}
float b(ivec2 coord)
{
if( coord.x <= 0
|| coord.x >= textureSize(bTex, 0).x
|| coord.y <= 0
|| coord.y >= textureSize(bTex, 0).y)
{
return(0.);
}
return(texelFetch(bTex, coord, 0).x);
}
vec3 color_map(float v)
{
float logv = log(abs(v))/log(10.0);
float f = floor(logv + 7.0);
float i = floor(4.0*(logv + 7.0 - f));
if(f < 0.0) return vec3(0.0);
if(f < 1.0) return mix(vec3(1.0, 0.0, 0.0), vec3(1.0), i/4.0);
if(f < 2.0) return mix(vec3(0.0, 1.0, 0.0), vec3(1.0), i/4.0);
if(f < 3.0) return mix(vec3(0.0, 0.0, 1.0), vec3(1.0), i/4.0);
if(f < 4.0) return mix(vec3(1.0, 1.0, 0.0), vec3(1.0), i/4.0);
if(f < 5.0) return mix(vec3(1.0, 0.0, 1.0), vec3(1.0), i/4.0);
if(f < 6.0) return mix(vec3(0.0, 1.0, 1.0), vec3(1.0), i/4.0);
if(f < 7.0) return mix(vec3(1.0, 0.5, 0.0), vec3(1.0), i/4.0);
if(f < 8.0) return mix(vec3(1.0, 1.0, 1.0), vec3(1.0), i/4.0);
return vec3(1.0);
}
void main()
{
ivec2 pixelCoord = ivec2(floor(texCoord.xy * vec2(textureSize(xTex, 0).xy)));
float tl = x(pixelCoord + ivec2(-1, 1));
float tr = x(pixelCoord + ivec2(1, 1));
float bl = x(pixelCoord + ivec2(-1, -1));
float br = x(pixelCoord + ivec2(1, -1));
float residue = b(pixelCoord) - (-tl - tr - bl - br + 4.*x(pixelCoord));
fragColor = vec4(color_map(residue), 1);
}

View File

@ -0,0 +1,18 @@
#version 300 es
precision highp float;
in vec2 pos;
out vec2 texCoord;
uniform mat4 mvp;
uniform ivec2 gridSize;
void main()
{
float margin = 32.;
float ratio = 1. - 2.*margin/float(gridSize.x);
texCoord = margin/float(gridSize.x) + ratio*(0.5*(pos + vec2(1,1)));
gl_Position = mvp * vec4(pos, 0, 1);
}

View File

@ -0,0 +1,12 @@
#version 300 es
precision highp float;
in vec2 pos;
out vec2 texCoord;
void main()
{
texCoord = 0.5*(pos + vec2(1,1));
gl_Position = vec4(pos, 0, 1);
}

View File

@ -0,0 +1,41 @@
#version 300 es
precision highp float;
precision highp sampler2D;
in vec2 texCoord;
out vec4 fragColor;
uniform sampler2D src;
vec2 u(ivec2 coord)
{
return(texelFetch(src, coord, 0).xy);
}
void main()
{
ivec2 pixelCoord = ivec2(floor(gl_FragCoord.xy));
if( pixelCoord.x <= 0
|| pixelCoord.x >= textureSize(src, 0).x
|| pixelCoord.y <= 0
|| pixelCoord.y >= textureSize(src, 0).y)
{
fragColor = vec4(0, 0, 0, 1);
}
else
{
vec2 tl = u(pixelCoord + ivec2(-1, 0));
vec2 tr = u(pixelCoord);
vec2 bl = u(pixelCoord + ivec2(-1, -1));
vec2 br = u(pixelCoord + ivec2(0, -1));
float r = (tr.x + br.x)/2.;
float l = (tl.x + bl.x)/2.;
float t = (tl.y + tr.y)/2.;
float b = (bl.y + br.y)/2.;
fragColor = vec4(-2.*(r - l + t - b), 0, 0, 1);
}
}

View File

@ -0,0 +1,55 @@
#version 300 es
precision highp float;
precision highp sampler2D;
in vec2 texCoord;
out vec4 fragColor;
uniform sampler2D xTex;
uniform sampler2D bTex;
float x(ivec2 coord)
{
if( coord.x <= 0
|| coord.x >= textureSize(xTex, 0).x
|| coord.y <= 0
|| coord.y >= textureSize(xTex, 0).y)
{
return(0.);
}
return(texelFetch(xTex, coord, 0).x);
}
float b(ivec2 coord)
{
if( coord.x <= 0
|| coord.x >= textureSize(bTex, 0).x
|| coord.y <= 0
|| coord.y >= textureSize(bTex, 0).y)
{
return(0.);
}
return(texelFetch(bTex, coord, 0).x);
}
void main()
{
ivec2 pixelCoord = ivec2(floor(gl_FragCoord.xy));
if( pixelCoord.x <= 0
|| pixelCoord.y <= 0)
{
fragColor = vec4(0, 0, 0, 1);
}
else
{
float tl = x(pixelCoord + ivec2(-1, 1));
float tr = x(pixelCoord + ivec2(1, 1));
float bl = x(pixelCoord + ivec2(-1, -1));
float br = x(pixelCoord + ivec2(1, -1));
float jacobi = (tl + tr + bl + br + b(pixelCoord))/4.;
fragColor = vec4(jacobi, 0, 0, 1);
}
}

View File

@ -0,0 +1,53 @@
#version 300 es
precision highp float;
precision highp sampler2D;
in vec2 texCoord;
out vec4 fragColor;
uniform sampler2D src;
uniform sampler2D error;
uniform float invGridSize;
float e(ivec2 coord)
{
if( coord.x <= 0
|| coord.x >= textureSize(error, 0).x
|| coord.y <= 0
|| coord.y >= textureSize(error, 0).y)
{
return(0.);
}
return(texelFetch(error, coord, 0).x);
}
float p(ivec2 coord)
{
if( coord.x <= 0
|| coord.x >= textureSize(src, 0).x
|| coord.y <= 0
|| coord.y >= textureSize(src, 0).y)
{
return(0.);
}
return(texelFetch(src, coord, 0).x);
}
void main()
{
ivec2 pixelCoord = ivec2(floor(gl_FragCoord.xy));
vec2 coarseCoord = vec2(pixelCoord)/2.;
vec2 offset = fract(coarseCoord);
ivec2 bl = ivec2(floor(coarseCoord));
ivec2 br = bl + ivec2(1, 0);
ivec2 tl = bl + ivec2(0, 1);
ivec2 tr = bl + ivec2(1, 1);
float topLerp = (1.-offset.x)*e(tl)+ offset.x*e(tr);
float bottomLerp = (1.-offset.x)*e(bl) + offset.x*e(br);
float bilerpError = (1.-offset.y)*bottomLerp + offset.y*topLerp;
fragColor = vec4(p(pixelCoord) + bilerpError, 0, 0, 1);
}

View File

@ -0,0 +1,61 @@
#version 300 es
precision highp float;
precision highp sampler2D;
in vec2 texCoord;
out vec4 fragColor;
uniform sampler2D xTex;
uniform sampler2D bTex;
float x(ivec2 coord)
{
if( coord.x <= 0
|| coord.x >= textureSize(xTex, 0).x
|| coord.y <= 0
|| coord.y >= textureSize(xTex, 0).y)
{
return(0.);
}
return(texelFetch(xTex, coord, 0).x);
}
float b(ivec2 coord)
{
if( coord.x <= 0
|| coord.x >= textureSize(bTex, 0).x
|| coord.y <= 0
|| coord.y >= textureSize(bTex, 0).y)
{
return(0.);
}
return(texelFetch(bTex, coord, 0).x);
}
float residual(ivec2 coord)
{
ivec2 vr = coord + ivec2(1, 0);
ivec2 vl = coord - ivec2(1, 0);
ivec2 vt = coord + ivec2(0, 1);
ivec2 vb = coord - ivec2(0, 1);
return((x(vl) + x(vr) + x(vt) + x(vb) + b(coord) - 4.*x(coord))*4.);
}
void main()
{
ivec2 pixelCoord = ivec2(floor(gl_FragCoord.xy));
float restricted = residual(2*pixelCoord + ivec2(-1, -1))
+ residual(2*pixelCoord + ivec2(1, -1))
+ residual(2*pixelCoord + ivec2(1, 1))
+ residual(2*pixelCoord + ivec2(-1, 1))
+ 2.*residual(2*pixelCoord + ivec2(-1, 0))
+ 2.*residual(2*pixelCoord + ivec2(1, 0))
+ 2.*residual(2*pixelCoord + ivec2(0, -1))
+ 2.*residual(2*pixelCoord + ivec2(0, 1))
+ 4.*residual(2*pixelCoord);
restricted /= 16.;
fragColor = vec4(restricted, 0, 0, 1);
}

View File

@ -0,0 +1,29 @@
#version 300 es
precision highp float;
precision highp sampler2D;
in vec2 texCoord;
out vec4 fragColor;
uniform sampler2D src;
uniform vec2 splatPos;
uniform vec3 splatColor;
uniform float radius;
uniform float additive;
uniform float blending;
uniform float randomize;
void main()
{
float d2 = dot(texCoord - splatPos, texCoord - splatPos);
float intensity = exp(-10.*d2/radius);
vec2 force = splatColor.xy;
vec3 u = texture(src, texCoord).xyz;
vec3 uAdd = u + intensity*splatColor.xyz;
vec3 uBlend = u*(1.-intensity) + intensity * splatColor;
fragColor = vec4(uAdd*additive + uBlend*blending, 1);
}

View File

@ -0,0 +1,47 @@
#version 300 es
precision highp float;
precision highp sampler2D;
in vec2 texCoord;
out vec4 fragColor;
uniform sampler2D src;
uniform sampler2D pressure;
uniform float invGridSize;
vec2 u(ivec2 coord)
{
return(texelFetch(src, coord, 0).xy);
}
float p(ivec2 coord)
{
if( coord.x <= 0
|| coord.x >= textureSize(pressure, 0).x
|| coord.y <= 0
|| coord.y >= textureSize(pressure, 0).y)
{
return(0.);
}
return(texelFetch(pressure, coord, 0).x);
}
void main()
{
ivec2 pixelCoord = ivec2(floor(gl_FragCoord.xy));
float tl = p(pixelCoord + ivec2(0, 1));
float tr = p(pixelCoord + ivec2(1, 1));
float bl = p(pixelCoord);
float br = p(pixelCoord + ivec2(1, 0));
float r = (tr + br)/2.;
float l = (tl + bl)/2.;
float t = (tl + tr)/2.;
float b = (bl + br)/2.;
vec2 gradP = vec2(r - l, t - b);
fragColor = vec4(u(pixelCoord) - gradP, 0, 1);
}

3
samples/glesTriangle/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
Triangle
profile.dtrace
profile.spall

View File

@ -0,0 +1,17 @@
@echo off
:: compile wasm module
set wasmFlags=--target=wasm32^
--no-standard-libraries ^
-fno-builtin ^
-Wl,--no-entry ^
-Wl,--export-dynamic ^
-g ^
-O2 ^
-mbulk-memory ^
-D__ORCA__ ^
-isystem ..\..\cstdlib\include -I ..\..\sdk -I..\..\milepost\ext -I ..\..\milepost -I ..\..\milepost\src
clang %wasmFlags% -o .\module.wasm ..\..\sdk\orca.c ..\..\cstdlib\src\*.c src\main.c
python3 ..\..\scripts\mkapp.py --orca-dir ..\.. --name Triangle module.wasm

33
samples/glesTriangle/build.sh Executable file
View File

@ -0,0 +1,33 @@
#!/bin/bash
set -euo pipefail
if [[ -x /usr/local/opt/llvm/bin/clang ]]; then
CLANG=/usr/local/opt/llvm/bin/clang
elif [[ -x /opt/homebrew/opt/llvm/bin/clang ]]; then
CLANG=/opt/homebrew/opt/llvm/bin/clang
else
echo "Could not find Homebrew clang; this script will probably not work."
CLANG=clang
fi
STDLIB_DIR=../../cstdlib
ORCA_SDK_DIR=../../sdk
MILEPOST_DIR=../../milepost
wasmFlags="--target=wasm32 \
--no-standard-libraries \
-fno-builtin \
-Wl,--no-entry \
-Wl,--export-dynamic \
-g \
-O2 \
-mbulk-memory \
-D__ORCA__ \
-I $STDLIB_DIR/include \
-I $ORCA_SDK_DIR \
-I $MILEPOST_DIR/ext -I $MILEPOST_DIR -I $MILEPOST_DIR/src"
$CLANG $wasmFlags -o ./module.wasm ../../sdk/orca.c ../../cstdlib/src/*.c src/main.c
orca bundle --orca-dir ../.. --name Triangle module.wasm

View File

@ -0,0 +1,114 @@
#include <keys.h>
#include <graphics.h>
#include <math.h>
#include <orca.h>
vec2 frameSize = {100, 100};
mg_surface surface;
unsigned int program;
const char* vshaderSource =
"attribute vec4 vPosition;\n"
"uniform mat4 transform;\n"
"void main()\n"
"{\n"
" gl_Position = transform*vPosition;\n"
"}\n";
const char* fshaderSource =
"precision mediump float;\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";
void compile_shader(GLuint shader, const char* source)
{
glShaderSource(shader, 1, &source, 0);
glCompileShader(shader);
int err = glGetError();
if(err)
{
log_info("gl error");
}
}
char* ORCA_IMPORT(orca_mem_grow)(u64 size);
ORCA_EXPORT void OnInit(void)
{
surface = mg_surface_gles();
mg_surface_prepare(surface);
const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
log_info("GLES extensions: %s\n", extensions);
int extensionCount = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &extensionCount);
for(int i=0; i<extensionCount; i++)
{
const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
log_info("GLES extension %i: %s\n", i, extension);
}
unsigned int vshader = glCreateShader(GL_VERTEX_SHADER);
unsigned int fshader = glCreateShader(GL_FRAGMENT_SHADER);
program = glCreateProgram();
compile_shader(vshader, vshaderSource);
compile_shader(fshader, fshaderSource);
glAttachShader(program, vshader);
glAttachShader(program, fshader);
glLinkProgram(program);
glUseProgram(program);
GLfloat vertices[] = {
-0.866/2, -0.5/2, 0, 0.866/2, -0.5/2, 0, 0, 0.5, 0};
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, 9*sizeof(GLfloat), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
}
ORCA_EXPORT void OnFrameResize(u32 width, u32 height)
{
log_info("frame resize %u, %u", width, height);
frameSize.x = width;
frameSize.y = height;
}
ORCA_EXPORT void OnFrameRefresh(void)
{
f32 aspect = frameSize.x/frameSize.y;
mg_surface_prepare(surface);
glClearColor(0, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
static float alpha = 0;
glViewport(0, 0, frameSize.x * 2, frameSize.y * 2);
GLfloat matrix[] = {cosf(alpha)/aspect, sinf(alpha), 0, 0,
-sinf(alpha)/aspect, cosf(alpha), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1};
alpha += 2*M_PI/120;
glUniformMatrix4fv(0, 1, false, matrix);
glDrawArrays(GL_TRIANGLES, 0, 3);
mg_surface_present(surface);
}

View File

@ -45,9 +45,6 @@ mg_image ballImage;
mg_image paddleImage;
mg_font pongFont;
// TODO(ben): Why is this here? Why isn't it forward-declared by some header?
mg_surface mg_surface_main(void);
f32 lerp(f32 a, f32 b, f32 t);
mp_rect blockRect(int i);
int checkCollision(mp_rect block);
@ -69,7 +66,7 @@ str8 loadFile(mem_arena* arena, str8 filename) {
ORCA_EXPORT void OnInit(void)
{
surface = mg_surface_main();
surface = mg_surface_canvas();
canvas = mg_canvas_create();
waterImage = mg_image_create_from_data(surface, loadFile(mem_scratch(), STR8("/underwater.jpg")), false);

View File

@ -12,12 +12,10 @@ mg_font font;
ui_context ui;
mem_arena textArena = {0};
mg_surface mg_surface_main(void);
ORCA_EXPORT void OnInit(void)
{
//TODO create surface for main window
surface = mg_surface_main();
surface = mg_surface_canvas();
canvas = mg_canvas_create();
ui_init(&ui);

View File

@ -108,48 +108,104 @@ def bindgen(apiName, spec, **kwargs):
if gen_stub == False:
s += ';\n\n'
else:
s += '\n{\n\t'
s += '\n{\n'
# NOTE: check and cast arguments
retTag = decl['ret']['tag']
if retTag == 'i':
s += '*((i32*)&_sp[0]) = '
elif retTag == 'I':
s += '*((i64*)&_sp[0]) = '
elif retTag == 'f':
s += '*((f32*)&_sp[0]) = '
elif retTag == 'F':
s += '*((f64*)&_sp[0]) = '
elif retTag == 'S':
retTypeName = decl['ret']['name']
retTypeCName = decl['ret'].get('cname', retTypeName)
s += '*(' + retTypeCName + '*)((char*)_mem + *(i32*)&_sp[0]) = '
s += cname + '('
firstArgIndex = 0
if retTag != 'v':
firstArgIndex = 1
for i, arg in enumerate(decl['args']):
for argIndex, arg in enumerate(decl['args']):
argName = arg['name']
typeName = arg['type']['name']
typeCName = arg['type'].get('cname', typeName)
argTag = arg['type']['tag']
s += '\t'
if argTag == 'i':
s += '*(i32*)&_sp[' + str(firstArgIndex + i) + ']'
s += typeCName + ' ' + argName + ' = ('+typeCName+')*(i32*)&_sp[' + str(firstArgIndex + argIndex) + '];\n'
elif argTag == 'I':
s += '*(i64*)&_sp[' + str(firstArgIndex + i) + ']'
s += typeCName + ' ' + argName + ' = ('+typeCName+')*(i64*)&_sp[' + str(firstArgIndex + argIndex) + '];\n'
elif argTag == 'f':
s += '*(f32*)&_sp[' + str(firstArgIndex + i) + ']'
s += typeCName + ' ' + argName + ' = ('+typeCName+')*(f32*)&_sp[' + str(firstArgIndex + argIndex) + '];\n'
elif argTag == 'F':
s += '*(f64*)&_sp[' + str(firstArgIndex + i) + ']'
s += typeCName + ' ' + argName + ' = ('+typeCName+')*(f64*)&_sp[' + str(firstArgIndex + argIndex) + '];\n'
elif argTag == 'p':
s += '(void*)((char*)_mem + *(i32*)&_sp[' + str(firstArgIndex + i) + '])'
s += typeCName + ' ' + argName + ' = ('+ typeCName +')((char*)_mem + *(u32*)&_sp[' + str(firstArgIndex + argIndex) + ']);\n'
elif argTag == 'S':
s += '*(' + typeCName + '*)((char*)_mem + *(i32*)&_sp[' + str(firstArgIndex + i) + '])'
s += typeCName + ' ' + argName + ' = *('+ typeCName +'*)((char*)_mem + *(u32*)&_sp[' + str(firstArgIndex + argIndex) + ']);\n'
else:
print('unrecognized type ' + c + ' in procedure signature\n')
break
# check pointer arg length
for arg in decl['args']:
argName = arg['name']
typeName = arg['type']['name']
typeCName = arg['type'].get('cname', typeName)
argTag = arg['type']['tag']
argLen = arg.get('len')
if argTag == 'p' and argLen != None:
s += '\t{\n'
s += '\t\tORCA_ASSERT(((char*)'+ argName + ' >= (char*)_mem) && (((char*)'+ argName +' - (char*)_mem) < m3_GetMemorySize(runtime)), "parameter \''+argName+'\' is out of bounds");\n'
s += '\t\tORCA_ASSERT((char*)' + argName + ' + '
proc = argLen.get('proc')
if proc != None:
s += proc + '(runtime, '
lenProcArgs = argLen['args']
for i, lenProcArg in enumerate(lenProcArgs):
s += lenProcArg
if i < len(lenProcArgs)-1:
s += ', '
s += ')'
else:
components = argLen.get('components')
countArg = argLen.get('count')
if components != None:
s += str(components)
if countArg != None:
s += '*'
if countArg != None:
s += countArg
if typeCName.endswith('**') or (typeCName.startswith('void') == False and typeCName.startswith('const void') == False):
s += '*sizeof('+typeCName[:-1]+')'
s += ' <= ((char*)_mem + m3_GetMemorySize(runtime)), "parameter \''+argName+'\' overflows wasm memory");\n'
s += '\t}\n'
s += '\t'
if retTag == 'i':
s += '*((i32*)&_sp[0]) = (i32)'
elif retTag == 'I':
s += '*((i64*)&_sp[0]) = (i64)'
elif retTag == 'f':
s += '*((f32*)&_sp[0]) = (f32)'
elif retTag == 'F':
s += '*((f64*)&_sp[0]) = (f64)'
elif retTag == 'S':
retTypeName = decl['ret']['name']
retTypeCName = decl['ret'].get('cname', retTypeName)
s += '*(' + retTypeCName + '*)((char*)_mem + *(i32*)&_sp[0]) = '
elif retTag == 'p':
print("Warning: " + name + ": pointer return type not supported yet")
s += cname + '('
for i, arg in enumerate(decl['args']):
s += arg['name']
if i+1 < len(decl['args']):
s += ', '
@ -158,8 +214,9 @@ def bindgen(apiName, spec, **kwargs):
print(s, file=host_bindings)
# link function
s = 'int bindgen_link_' + apiName + '_api(IM3Module module)\n{\n\t'
s += 'M3Result res;\n'
s = 'int bindgen_link_' + apiName + '_api(IM3Module module)\n{\n'
s += ' M3Result res;\n'
s += ' int ret = 0;\n'
for decl in data:
name = decl['name']
@ -185,11 +242,14 @@ def bindgen(apiName, spec, **kwargs):
m3Sig += ')'
s += '\tres = m3_LinkRawFunction(module, "*", "' + name + '", "' + m3Sig + '", ' + cname + '_stub);\n'
s += '\tif(res != m3Err_none && res != m3Err_functionLookupFailed) { log_error("error: %s\\n", res); return(-1); }\n\n'
s += ' res = m3_LinkRawFunction(module, "*", "' + name + '", "' + m3Sig + '", ' + cname + '_stub);\n'
s += ' if(res != m3Err_none && res != m3Err_functionLookupFailed)\n'
s += ' {\n'
s += ' log_error("Couldn\'t link function ' + name + ' (%s)\\n", res);\n'
s += ' ret = -1;\n'
s += ' }\n\n'
s += '\treturn(0);\n}\n'
s += '\treturn(ret);\n}\n'
print(s, file=host_bindings)
@ -213,7 +273,7 @@ if __name__ == "__main__":
wasm3_bindings_path = args.wasm3_bindings
if wasm3_bindings_path == None:
wasm3_bindings_path = 'bindgen_' + apiName + '_wasm3_bindings.c'
bindgen(apiName, spec,
guest_stubs=guest_stubs_path,
guest_include=args.guest_include,

View File

@ -171,6 +171,8 @@ def macos_make_app(args):
<string>icon.icns</string>
<key>NSHighResolutionCapable</key>
<string>True</string>
<key>MetalCaptureEnabled</key>
<true/>
</dict>
</plist>
"""

View File

@ -10,6 +10,7 @@ from zipfile import ZipFile
from . import checksum
from .bindgen import bindgen
from .gles_gen import gles_gen
from .log import *
from .utils import pushd, removeall
@ -374,6 +375,12 @@ def gen_all_bindings():
bindgen("core", "src/core_api.json",
wasm3_bindings="src/core_api_bind_gen.c",
)
gles_gen("milepost/ext/gl.xml",
"src/gles_api.json",
"sdk/gl31.h"
)
bindgen("gles", "src/gles_api.json",
wasm3_bindings="src/gles_api_bind_gen.c",
)

315
scripts/gles_gen.py Normal file
View File

@ -0,0 +1,315 @@
from .reg_modified import *
import xml.etree.ElementTree as et
from argparse import ArgumentParser
# remove APIs that can't be sandboxed
removeProc = [
"glMapBuffer",
"glMapBufferRange",
"glUnmapBuffer",
"glFlushMappedBufferRange",
"glGetBufferPointerv"
]
def gen_gles_header(spec, filename):
# Generates the GLES header, wrapping gl functions
# prototypes in ORCA_IMPORT() macro
gles2through31Pat = '2\.[0-9]|3\.[01]'
allVersions = '.*'
genOpts = CGeneratorOptions(
filename=filename,
apiname='gles2',
profile='common',
versions=gles2through31Pat,
emitversions=allVersions,
protectProto=False,
procMacro='ORCA_IMPORT',
removeProc = removeProc)
reg = Registry()
tree = et.parse(spec)
reg.loadElementTree(tree)
logFile = open('./gles_gen.log', 'w')
gen = COutputGenerator(diagFile=logFile)
reg.setGenerator(gen)
reg.apiGen(genOpts)
logFile.close()
def get_bindgen_tag_for_type(typeName):
typeToTags = {
"void": "v",
"GLenum": "i",
"GLbitfield": "i",
"GLboolean": "i",
"GLbyte": "i",
"GLubyte": "i",
"GLchar": "i",
"GLshort": "i",
"GLushort": "i",
"GLhalf": "i",
"GLhalfARB": "i",
"GLuint": "i",
"GLint": "i",
"GLclampx": "i",
"GLsizei": "i",
"GLfixed": "i",
"GLintptr": "i",
"GLsizeiptr": "i",
"GLuint64": "I",
"GLint64": "I",
"GLfloat": "f",
"GLclampf": "f",
"GLdouble": "F",
"GLclampd": "F",
#NOTE: we treat sync objects as opaque 64bit values
#TODO we should _also_ make sure that Wasm code treat them as 64bit values
"GLsync": "I"
}
if typeName[len(typeName)-1] == '*':
return "p"
else:
tag = typeToTags.get(typeName)
return tag
def gen_compsize_len_entry(name, argName, compsizeArgs):
entry = '\t\t\t"len": {\n'
entry += '\t\t\t\t"proc": "orca_'+ name +'_'+argName+'_length",\n'
entry += '\t\t\t\t"args": ['
for i, compsizeArg in enumerate(compsizeArgs):
entry += '"' + compsizeArg + '"'
if i < len(compsizeArgs)-1:
entry += ', '
entry += ']\n'
entry += '\t\t\t}'
return entry
def gen_argcount_len_entry(name, argName, tokens):
entry = '\t\t\t"len": {'
if len(tokens) == 2:
if tokens[1].isnumeric() == False:
print("Warning: function " + name + ": couldn't parse parameter '" + argName + "' lenght attribute")
entry += '"count": "' + tokens[0] + '", "components": '+ tokens[1]
elif len(tokens) == 1:
if tokens[0].isnumeric():
entry += '"components":'+ tokens[0]
else:
entry += '"count": "'+ tokens[0] + '"'
else:
print("Warning: function " + name + ": couldn't parse parameter '" + argName + "' lenght attribute")
entry += '}'
return entry
def gen_gles_bindgen_json(spec, filename):
# Gather gles 3.1 required functions
tree = et.parse(spec)
api = []
for feature in tree.iterfind('feature[@api="gles2"]'):
if float(feature.get('number')) > 3.1:
break
for require in feature.iter('require'):
if require.get('profile') == 'compatibility':
continue
for command in require.iter('command'):
if command.get('name') not in removeProc:
api.append(command.get('name'))
for remove in feature.iter('remove'):
for command in remove.iter('command'):
api.remove(command.get('name'))
# put all GL commands in a dict
commands = dict()
commandsSpec = tree.find('./commands')
for command in commandsSpec.iter('command'):
name = command.find('proto/name')
commands[name.text] = command
# TODO: Generate json descriptions for commands in api
manualBind = [
"glShaderSource",
"glGetVertexAttribPointerv",
"glVertexAttribPointer",
"glVertexAttribIPointer",
"glGetString",
"glGetStringi",
"glGetUniformIndices"
]
json = '[\n'
for name in api:
if name in manualBind:
continue
command = commands.get(name)
if command == None:
print("Couldn't find definition for required command '" + name + "'")
exit(-1)
proto = command.find("proto")
ptype = proto.find("ptype")
retType = ''
if proto.text != None:
retType += proto.text
if ptype != None:
if ptype.text != None:
retType += ptype.text
if ptype.tail != None:
retType += ptype.tail
retType = retType.strip()
retTag = get_bindgen_tag_for_type(retType)
if retTag == None:
print("Couldn't find tag for GL type '" + retType + "'")
exit(-1)
entry = '{\n\t"name": "' + name + '",\n'
entry += '\t"cname": "' + name + '",\n'
entry += '\t"ret": { "name": "' + retType + '", "tag": "' + retTag + '"},\n'
entry += '\t"args": [ '
# iterate through params
for param in command.iter('param'):
argNode = param.find('name')
argName = argNode.text
typeNode = param.find('ptype')
typeName = ''
if param.text != None:
typeName += param.text
if typeNode != None:
if typeNode.text != None:
typeName += typeNode.text
if typeNode.tail != None:
typeName += typeNode.tail
typeName = typeName.strip()
if typeName.endswith('**'):
print("Warning: function " + name + ": parameter " + argName + " has 2 (or more) levels of indirection")
typeTag = get_bindgen_tag_for_type(typeName)
if typeTag == None:
print("Couldn't find tag for GL type '" + typeName + "' in function '"+ name +"'")
exit(-1)
entry += '\n'
entry += '\t\t{\n\t\t\t"name": "'+ argName +'",\n'
entry += '\t\t\t"type": {"name": "'+ typeName +'", "tag": "'+ typeTag +'"}'
lenString = param.get('len')
nullStringProcWithNoLen = [
"glBindAttribLocation",
"glGetAttribLocation",
"glGetUniformLocation"
]
drawIndirectProc = [
"glDrawArraysIndirect",
"glDrawElementsIndirect"
]
if typeTag == "p":
if lenString == None:
if name in drawIndirectProc:
entry += ',\n'
entry += gen_compsize_len_entry(name, argName, ['indirect'])
elif name in nullStringProcWithNoLen:
entry += ',\n'
entry += gen_compsize_len_entry(name, argName, ['name'])
else:
print("Warning: function " + name + ": parameter " + argName + " has no len attribute")
elif lenString != None:
entry += ',\n'
tokens = lenString.split('*')
if lenString.startswith("COMPSIZE"):
tmp = lenString
if tmp.startswith("COMPSIZE("):
tmp = tmp[len("COMPSIZE("):]
if tmp.endswith(")"):
tmp = tmp[:-1]
compsizeArgs = list(filter(None, tmp.split(",")))
if len(compsizeArgs) == 0:
# special case glGetUniformBlockIndex which isn't specified correctly in gl.xml
if name == 'glGetUniformBlockIndex':
compsizeArgs = ['uniformBlockName']
entry += gen_compsize_len_entry(name, argName, compsizeArgs)
else:
entry += gen_argcount_len_entry(name, argName, tokens)
entry += '\n\t\t},'
entry = entry[:-1]
entry += '\n\t]\n}'
json += entry
json += ',\n'
json = json[:-2]
json += '\n]'
# write json to jsonFile
f = open(filename, 'w')
f.write(json)
f.close()
def gles_gen(spec, json, header):
gen_gles_header(spec, header)
gen_gles_bindgen_json(spec, json)
#----------------------------------------
# driver
#----------------------------------------
if __name__ == "__main__":
parser = ArgumentParser()
parser.add_argument("-s", "--spec")
parser.add_argument("--header")
parser.add_argument("-j", "--json")
args = parser.parse_args()
glesHeader = args.header
jsonFile = args.json
gles_gen(args.spec, jsonFile, glesHeader)

1175
scripts/reg_modified.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -19,10 +19,22 @@
#include"platform/platform_clock.h"
#include"platform/platform_io.h"
#include"math.h"
#include"graphics.h"
#include"gl31.h"
#if COMPILER_CLANG
#define ORCA_EXPORT __attribute__((visibility("default")))
#else
#error "Orca apps can only be compiled with clang for now"
#endif
mg_surface mg_surface_canvas();
mg_surface mg_surface_gles();
#endif //__ORCA_H_

View File

@ -36,12 +36,6 @@
{"name": "pixels",
"type": {"name": "u8*", "tag": "p"}}]
},
{
"name": "mg_surface_main",
"cname": "orca_surface_main",
"ret": {"name": "mg_surface", "tag": "S"},
"args": []
},
{
"name": "mg_surface_prepare",
"cname": "mg_surface_prepare",
@ -75,4 +69,17 @@
"type": {"name": "u32", "tag": "i"}},
{"name": "elements",
"type": {"name": "mg_path_elt*", "tag": "p"}}]
}]
},
{
"name": "mg_surface_canvas",
"cname": "orca_surface_canvas",
"ret": {"name": "mg_surface", "tag": "S"},
"args": []
},
{
"name": "mg_surface_gles",
"cname": "orca_surface_gles",
"ret": {"name": "mg_surface", "tag": "S"},
"args": []
}
]

View File

@ -1,60 +1,4 @@
[
{
"name": "cosf",
"cname": "cosf",
"ret": {"name": "float", "tag": "f"},
"args": [ {"name": "x",
"type": {"name": "float", "tag": "f"}}]
},
{
"name": "sinf",
"cname": "sinf",
"ret": {"name": "float", "tag": "f"},
"args": [ {"name": "x",
"type": {"name": "float", "tag": "f"}}]
},
{
"name": "floorf",
"cname": "floorf",
"ret": {"name": "float", "tag": "f"},
"args": [ {"name": "x",
"type": {"name": "float", "tag": "f"}}]
},
{
"name": "sqrtf",
"cname": "sqrtf",
"ret": {"name": "float", "tag": "f"},
"args": [ {"name": "x",
"type": {"name": "float", "tag": "f"}}]
},
{
"name": "cos",
"cname": "cos",
"ret": {"name": "double", "tag": "F"},
"args": [ {"name": "x",
"type": {"name": "double", "tag": "F"}}]
},
{
"name": "sin",
"cname": "sin",
"ret": {"name": "double", "tag": "F"},
"args": [ {"name": "x",
"type": {"name": "double", "tag": "F"}}]
},
{
"name": "sqrt",
"cname": "sqrt",
"ret": {"name": "double", "tag": "F"},
"args": [ {"name": "x",
"type": {"name": "double", "tag": "F"}}]
},
{
"name": "fabs",
"cname": "fabs",
"ret": {"name": "double", "tag": "F"},
"args": [ {"name": "x",
"type": {"name": "double", "tag": "F"}}]
},
{
"name": "orca_log",
"cname": "orca_log",

View File

@ -1,383 +0,0 @@
[
{
"name": "glCreateProgram",
"cname": "glCreateProgram",
"ret": {"name": "int", "tag": "i"},
"args": []
},
{
"name": "glCreateShader",
"cname": "glCreateShader",
"ret": {"name": "int", "tag": "i"},
"args": [ {"name": "shaderType",
"type": {"name": "GLenum", "tag": "i"}}]
},
{
"name": "glCompileShader",
"cname": "glCompileShader",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "shader",
"type": {"name": "GLuint", "tag": "i"}}]
},
{
"name": "glAttachShader",
"cname": "glAttachShader",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "program",
"type": {"name": "GLuint", "tag": "i"}},
{"name": "shader",
"type": {"name": "GLuint", "tag": "i"}}
]
},
{
"name": "glLinkProgram",
"cname": "glLinkProgram",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "program",
"type": {"name": "GLuint", "tag": "i"}}]
},
{
"name": "glUseProgram",
"cname": "glUseProgram",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "program",
"type": {"name": "GLuint", "tag": "i"}}]
},
{
"name": "glGetError",
"cname": "glGetError",
"ret": {"name": "GLenum", "tag": "i"},
"args": []
},
{
"name": "glClearColor",
"cname": "glClearColor",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "red",
"type": {"name": "GLfloat", "tag": "f"}},
{"name": "green",
"type": {"name": "GLfloat", "tag": "f"}},
{"name": "blue",
"type": {"name": "GLfloat", "tag": "f"}},
{"name": "alpha",
"type": {"name": "GLfloat", "tag": "f"}}
]
},
{
"name": "glClear",
"cname": "glClear",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "mask",
"type": {"name": "GLbitfield", "tag": "i"}}]
},
{
"name": "glViewport",
"cname": "glViewport",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "x",
"type": {"name": "GLint", "tag": "i"}},
{"name": "y",
"type": {"name": "GLint", "tag": "i"}},
{"name": "width",
"type": {"name": "GLsizei", "tag": "i"}},
{"name": "height",
"type": {"name": "GLsizei", "tag": "i"}}
]
},
{
"name": "glGetShaderiv",
"cname": "glGetShaderiv",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "shader",
"type": {"name": "GLuint", "tag": "i"}},
{"name": "pname",
"type": {"name": "GLenum", "tag": "i"}},
{"name": "params",
"type": {"name": "GLint*", "tag": "p"}}
]
},
{
"name": "glGetShaderInfoLog",
"cname": "glGetShaderInfoLog",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "shader",
"type": {"name": "GLuint", "tag": "i"}},
{"name": "maxLength",
"type": {"name": "GLsizei", "tag": "i"}},
{"name": "length",
"type": {"name": "GLsizei", "tag": "p"}},
{"name": "infoLog",
"type": {"name": "GLchar", "tag": "p"}}
]
},
{
"name": "glBindFramebuffer",
"cname": "glBindFramebuffer",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "target",
"type": {"name": "GLenum", "tag": "i"}},
{"name": "framebuffer",
"type": {"name": "GLuint", "tag": "i"}}
]
},
{
"name": "glBindTexture",
"cname": "glBindTexture",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "target",
"type": {"name": "GLenum", "tag": "i"}},
{"name": "texture",
"type": {"name": "GLuint", "tag": "i"}}
]
},
{
"name": "glActiveTexture",
"cname": "glActiveTexture",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "texture",
"type": {"name": "GLuint", "tag": "i"}}]
},
{
"name": "glGenBuffers",
"cname": "glGenBuffers",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "n",
"type": {"name": "GLenum", "tag": "i"}},
{"name": "buffers",
"type": {"name": "GLuint*", "tag": "p"}}
]
},
{
"name": "glGenTextures",
"cname": "glGenTextures",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "n",
"type": {"name": "GLenum", "tag": "i"}},
{"name": "textures",
"type": {"name": "GLuint*", "tag": "p"}}
]
},
{
"name": "glGenFramebuffers",
"cname": "glGenFramebuffers",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "n",
"type": {"name": "GLenum", "tag": "i"}},
{"name": "framebuffers",
"type": {"name": "GLuint*", "tag": "p"}}
]
},
{
"name": "glFramebufferTexture2D",
"cname": "glFramebufferTexture2D",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "target",
"type": {"name": "GLenum", "tag": "i"}},
{"name": "attachment",
"type": {"name": "GLenum", "tag": "i"}},
{"name": "textarget",
"type": {"name": "GLenum", "tag": "i"}},
{"name": "texture",
"type": {"name": "GLuint", "tag": "i"}},
{"name": "level",
"type": {"name": "GLint", "tag": "i"}}
]
},
{
"name": "glCheckFramebufferStatus",
"cname": "glCheckFramebufferStatus",
"ret": {"name": "GLenum", "tag": "i"},
"args": [ {"name": "target",
"type": {"name": "GLenum", "tag": "i"}}]
},
{
"name": "glTexImage2D",
"cname": "glTexImage2D",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "target",
"type": {"name": "GLenum", "tag": "i"}},
{"name": "level",
"type": {"name": "GLint", "tag": "i"}},
{"name": "internalformat",
"type": {"name": "GLint", "tag": "i"}},
{"name": "width",
"type": {"name": "GLsizei", "tag": "i"}},
{"name": "height",
"type": {"name": "GLsizei", "tag": "i"}},
{"name": "border",
"type": {"name": "GLint", "tag": "i"}},
{"name": "format",
"type": {"name": "GLenum", "tag": "i"}},
{"name": "type",
"type": {"name": "GLenum", "tag": "i"}},
{"name": "data",
"type": {"name": "void*", "tag": "p"}}
]
},
{
"name": "glTexParameteri",
"cname": "glTexParameteri",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "target",
"type": {"name": "GLenum", "tag": "i"}},
{"name": "pname",
"type": {"name": "GLenum", "tag": "i"}},
{"name": "param",
"type": {"name": "GLint", "tag": "i"}}
]
},
{
"name": "glBindBuffer",
"cname": "glBindBuffer",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "target",
"type": {"name": "GLenum", "tag": "i"}},
{"name": "buffer",
"type": {"name": "GLuint", "tag": "i"}}
]
},
{
"name": "glBufferData",
"cname": "glBufferData",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "target",
"type": {"name": "GLenum", "tag": "i"}},
{"name": "size",
"type": {"name": "GLsizeiptr", "tag": "i"}},
{"name": "data",
"type": {"name": "void*", "tag": "p"}},
{"name": "usage",
"type": {"name": "GLenum", "tag": "i"}}
]
},
{
"name": "glUniform1i",
"cname": "glUniform1i",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "location",
"type": {"name": "GLint", "tag": "i"}},
{"name": "v0",
"type": {"name": "GLint", "tag": "i"}}
]
},
{
"name": "glUniform2i",
"cname": "glUniform2i",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "location",
"type": {"name": "GLint", "tag": "i"}},
{"name": "v0",
"type": {"name": "GLint", "tag": "i"}},
{"name": "v1",
"type": {"name": "GLint", "tag": "i"}}
]
},
{
"name": "glUniform1f",
"cname": "glUniform1f",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "location",
"type": {"name": "GLint", "tag": "i"}},
{"name": "v0",
"type": {"name": "GLfloat", "tag": "f"}}
]
},
{
"name": "glUniform2f",
"cname": "glUniform2f",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "location",
"type": {"name": "GLint", "tag": "i"}},
{"name": "v0",
"type": {"name": "GLfloat", "tag": "f"}},
{"name": "v1",
"type": {"name": "GLfloat", "tag": "f"}}
]
},
{
"name": "glUniform3f",
"cname": "glUniform3f",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "location",
"type": {"name": "GLint", "tag": "i"}},
{"name": "v0",
"type": {"name": "GLfloat", "tag": "f"}},
{"name": "v1",
"type": {"name": "GLfloat", "tag": "f"}},
{"name": "v2",
"type": {"name": "GLfloat", "tag": "f"}}
]
},
{
"name": "glUniformMatrix4fv",
"cname": "glUniformMatrix4fv",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "location",
"type": {"name": "GLint", "tag": "i"}},
{"name": "count",
"type": {"name": "GLsizei", "tag": "i"}},
{"name": "transpose",
"type": {"name": "GLboolean", "tag": "i"}},
{"name": "value",
"type": {"name": "GLfloat*", "tag": "p"}}
]
},
{
"name": "glGetAttribLocation",
"cname": "glGetAttribLocation",
"ret": {"name": "GLint", "tag": "i"},
"args": [ {"name": "program",
"type": {"name": "GLuint", "tag": "i"}},
{"name": "name",
"type": {"name": "GLchar*", "tag": "p"}}
]
},
{
"name": "glGetUniformLocation",
"cname": "glGetUniformLocation",
"ret": {"name": "GLint", "tag": "i"},
"args": [ {"name": "program",
"type": {"name": "GLuint", "tag": "i"}},
{"name": "name",
"type": {"name": "GLchar*", "tag": "p"}}
]
},
{
"name": "glVertexAttribPointer",
"cname": "glVertexAttribPointer",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "index",
"type": {"name": "GLuint", "tag": "i"}},
{"name": "size",
"type": {"name": "GLint", "tag": "i"}},
{"name": "type",
"type": {"name": "GLenum", "tag": "i"}},
{"name": "normalized",
"type": {"name": "GLboolean", "tag": "i"}},
{"name": "stride",
"type": {"name": "GLsizei", "tag": "i"}},
{"name": "pointer",
"type": {"name": "void*", "tag": "p"}}
]
},
{
"name": "glEnableVertexAttribArray",
"cname": "glEnableVertexAttribArray",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "index",
"type": {"name": "GLuint", "tag": "i"}}]
},
{
"name": "glDrawArrays",
"cname": "glDrawArrays",
"ret": {"name": "void", "tag": "v"},
"args": [ {"name": "mode",
"type": {"name": "GLenum", "tag": "i"}},
{"name": "first",
"type": {"name": "GLint", "tag": "i"}},
{"name": "count",
"type": {"name": "GLsizei", "tag": "i"}}
]
}
]

1132
src/gles_api_bind_manual.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -18,9 +18,6 @@
#include"memory_impl.c"
#include"io_impl.c"
#define LOG_SUBSYSTEM "Orca"
int orca_assert(const char* file, const char* function, int line, const char* src, const char* note)
{
mem_arena* scratch = mem_scratch();
@ -38,7 +35,47 @@ int orca_assert(const char* file, const char* function, int line, const char* sr
const char* options[] = {"OK"};
mp_alert_popup("Assertion Failed", msgCStr, 1, options);
//TODO: should terminate more gracefully...
//TODO: could terminate more gracefully?
exit(-1);
return(-1);
}
int orca_assert_fmt(const char* file, const char* function, int line, const char* src, const char* fmt, ...)
{
mem_arena* scratch = mem_scratch();
va_list ap;
va_start(ap, fmt);
str8 msg = str8_pushfv(scratch, fmt, ap);
va_end(ap);
return(orca_assert(file, function, line, src, msg.ptr));
}
void orca_abort_fmt(const char* file, const char* function, int line, const char* fmt, ...)
{
mem_arena* scratch = mem_scratch();
va_list ap;
va_start(ap, fmt);
str8 note = str8_pushfv(scratch, fmt, ap);
va_end(ap);
str8 msg = str8_pushf(scratch,
"Fatal error in function %s() in file \"%s\", line %i:\n%.*s\n",
function,
file,
line,
(int)note.len,
note.ptr);
const char* msgCStr = str8_to_cstring(scratch, msg);
log_error(msgCStr);
const char* options[] = {"OK"};
mp_alert_popup("Fatal Error", msgCStr, 1, options);
//TODO: could terminate more gracefully?
exit(-1);
}
@ -170,9 +207,50 @@ void orca_log(log_level level,
msg);
}
mg_surface orca_surface_main(void)
typedef struct orca_surface_create_data
{
return(__orcaApp.surface);
mp_window window;
mg_surface_api api;
mg_surface surface;
} orca_surface_create_data;
i32 orca_surface_callback(void* user)
{
orca_surface_create_data* data = (orca_surface_create_data*)user;
data->surface = mg_surface_create_for_window(data->window, data->api);
//NOTE: this will be called on main thread, so we need to deselect the surface here,
// and reselect it on the orca thread
mg_surface_deselect();
return(0);
}
mg_surface orca_surface_canvas(void)
{
orca_surface_create_data data = {
.surface = mg_surface_nil(),
.window = __orcaApp.window,
.api = MG_CANVAS
};
mp_dispatch_on_main_thread_sync(__orcaApp.window, orca_surface_callback, (void*)&data);
mg_surface_prepare(data.surface);
return(data.surface);
}
mg_surface orca_surface_gles(void)
{
orca_surface_create_data data = {
.surface = mg_surface_nil(),
.window = __orcaApp.window,
.api = MG_GLES
};
mp_dispatch_on_main_thread_sync(__orcaApp.window, orca_surface_callback, (void*)&data);
mg_surface_prepare(data.surface);
return(data.surface);
}
void orca_surface_render_commands(mg_surface surface,
@ -302,8 +380,25 @@ void orca_runtime_init(orca_runtime* runtime)
#include"clock_api_bind_gen.c"
#include"io_api_bind_gen.c"
#include"gles_api_bind_manual.c"
#include"gles_api_bind_gen.c"
#include"manual_gles_api.c"
void orca_wasm3_abort(IM3Runtime runtime, M3Result res, const char* file, const char* function, int line, const char* msg)
{
M3ErrorInfo errInfo = {0};
m3_GetErrorInfo(runtime, &errInfo);
if(errInfo.message && res == errInfo.result)
{
orca_abort_fmt(file, function, line, "%s: %s (%s)", msg, res, errInfo.message);
}
else
{
orca_abort_fmt(file, function, line, "%s: %s", msg, res);
}
}
#define ORCA_WASM3_ABORT(runtime, err, msg) orca_wasm3_abort(runtime, err, __FILE__, __FUNCTION__, __LINE__, msg)
i32 orca_runloop(void* user)
{
@ -318,16 +413,7 @@ i32 orca_runloop(void* user)
FILE* file = fopen(modulePath.ptr, "rb");
if(!file)
{
log_error("Couldn't load wasm module at %s\n", modulePath.ptr);
const char* options[] = {"OK"};
mp_alert_popup("Error",
"The application couldn't load: web assembly module not found",
1,
options);
mp_request_quit();
return(-1);
ORCA_ABORT("The application couldn't load: web assembly module not found");
}
fseek(file, 0, SEEK_END);
@ -343,41 +429,44 @@ i32 orca_runloop(void* user)
app->runtime.m3Env = m3_NewEnvironment();
app->runtime.m3Runtime = m3_NewRuntime(app->runtime.m3Env, stackSize, NULL);
m3_RuntimeSetMemoryCallbacks(app->runtime.m3Runtime, wasm_memory_resize_callback, wasm_memory_free_callback, &app->runtime.wasmMemory);
//NOTE: host memory will be freed when runtime is freed.
m3_RuntimeSetMemoryCallbacks(app->runtime.m3Runtime, wasm_memory_resize_callback, wasm_memory_free_callback, &app->runtime.wasmMemory);
//TODO check errors
m3_ParseModule(app->runtime.m3Env, &app->runtime.m3Module, (u8*)app->runtime.wasmBytecode.ptr, app->runtime.wasmBytecode.len);
m3_LoadModule(app->runtime.m3Runtime, app->runtime.m3Module);
M3Result res = m3_ParseModule(app->runtime.m3Env, &app->runtime.m3Module, (u8*)app->runtime.wasmBytecode.ptr, app->runtime.wasmBytecode.len);
if(res)
{
ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "The application couldn't parse its web assembly module");
}
res = m3_LoadModule(app->runtime.m3Runtime, app->runtime.m3Module);
if(res)
{
ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "The application couldn't load its web assembly module into the runtime");
}
m3_SetModuleName(app->runtime.m3Module, bundleNameCString);
mem_arena_clear(mem_scratch());
//NOTE: bind orca APIs
bindgen_link_core_api(app->runtime.m3Module);
bindgen_link_canvas_api(app->runtime.m3Module);
bindgen_link_clock_api(app->runtime.m3Module);
bindgen_link_io_api(app->runtime.m3Module);
bindgen_link_gles_api(app->runtime.m3Module);
manual_link_gles_api(app->runtime.m3Module);
{
int err = 0;
err |= bindgen_link_core_api(app->runtime.m3Module);
err |= bindgen_link_canvas_api(app->runtime.m3Module);
err |= bindgen_link_clock_api(app->runtime.m3Module);
err |= bindgen_link_io_api(app->runtime.m3Module);
err |= bindgen_link_gles_api(app->runtime.m3Module);
err |= manual_link_gles_api(app->runtime.m3Module);
if(err)
{
ORCA_ABORT("The application couldn't link one or more functions to its web assembly module (see console log for more information)");
}
}
//NOTE: compile
M3Result res = m3_CompileModule(app->runtime.m3Module);
res = m3_CompileModule(app->runtime.m3Module);
if(res)
{
M3ErrorInfo errInfo = {0};
m3_GetErrorInfo(app->runtime.m3Runtime, &errInfo);
log_error("wasm error: %s\n", errInfo.message);
const char* options[] = {"OK"};
mp_alert_popup("Error",
"The application couldn't load: can't compile web assembly module",
1,
options);
mp_request_quit();
return(-1);
ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "The application couldn't compile its web assembly module");
}
//NOTE: Find and type check event handlers.
@ -451,28 +540,15 @@ i32 orca_runloop(void* user)
app->rootDir = cmp.handle;
}
//NOTE: prepare GL surface
mg_surface_prepare(app->surface);
IM3Function* exports = app->runtime.exports;
//NOTE: call init handler
if(exports[G_EXPORT_ON_INIT])
{
M3Result err = m3_Call(exports[G_EXPORT_ON_INIT], 0, 0);
if(err != NULL)
M3Result res = m3_Call(exports[G_EXPORT_ON_INIT], 0, 0);
if(res)
{
log_error("runtime error: %s\n", err);
str8 msg = str8_pushf(mem_scratch(), "Runtime error: %s\n", err);
const char* options[] = {"OK"};
mp_alert_popup("Error",
msg.ptr,
1,
options);
mp_request_quit();
return(-1);
ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
}
}
@ -482,7 +558,11 @@ i32 orca_runloop(void* user)
u32 width = (u32)content.w;
u32 height = (u32)content.h;
const void* args[2] = {&width, &height};
m3_Call(exports[G_EXPORT_FRAME_RESIZE], 2, args);
M3Result res = m3_Call(exports[G_EXPORT_FRAME_RESIZE], 2, args);
if(res)
{
ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
}
}
ui_set_context(&app->debugOverlay.ui);
@ -505,7 +585,11 @@ i32 orca_runloop(void* user)
memcpy(eventPtr, event, sizeof(*event));
const void* args[1] = {&app->runtime.rawEventOffset};
m3_Call(exports[G_EXPORT_RAW_EVENT], 1, args);
M3Result res = m3_Call(exports[G_EXPORT_RAW_EVENT], 1, args);
if(res)
{
ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
}
#else
log_error("OnRawEvent() is not supported on big endian platforms");
#endif
@ -527,7 +611,11 @@ i32 orca_runloop(void* user)
u32 width = (u32)event->move.content.w;
u32 height = (u32)event->move.content.h;
const void* args[2] = {&width, &height};
m3_Call(exports[G_EXPORT_FRAME_RESIZE], 2, args);
M3Result res = m3_Call(exports[G_EXPORT_FRAME_RESIZE], 2, args);
if(res)
{
ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
}
}
} break;
@ -539,7 +627,11 @@ i32 orca_runloop(void* user)
{
int key = event->key.code;
const void* args[1] = {&key};
m3_Call(exports[G_EXPORT_MOUSE_DOWN], 1, args);
M3Result res = m3_Call(exports[G_EXPORT_MOUSE_DOWN], 1, args);
if(res)
{
ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
}
}
}
else
@ -548,7 +640,11 @@ i32 orca_runloop(void* user)
{
int key = event->key.code;
const void* args[1] = {&key};
m3_Call(exports[G_EXPORT_MOUSE_UP], 1, args);
M3Result res = m3_Call(exports[G_EXPORT_MOUSE_UP], 1, args);
if(res)
{
ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
}
}
}
} break;
@ -558,7 +654,11 @@ i32 orca_runloop(void* user)
if(exports[G_EXPORT_MOUSE_MOVE])
{
const void* args[4] = {&event->mouse.x, &event->mouse.y, &event->mouse.deltaX, &event->mouse.deltaY};
m3_Call(exports[G_EXPORT_MOUSE_MOVE], 4, args);
M3Result res = m3_Call(exports[G_EXPORT_MOUSE_MOVE], 4, args);
if(res)
{
ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
}
}
} break;
@ -576,7 +676,11 @@ i32 orca_runloop(void* user)
if(exports[G_EXPORT_KEY_DOWN])
{
const void* args[1] = {&event->key.code};
m3_Call(exports[G_EXPORT_KEY_DOWN], 1, args);
M3Result res = m3_Call(exports[G_EXPORT_KEY_DOWN], 1, args);
if(res)
{
ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
}
}
}
else if(event->key.action == MP_KEY_RELEASE)
@ -584,7 +688,11 @@ i32 orca_runloop(void* user)
if(exports[G_EXPORT_KEY_UP])
{
const void* args[1] = {&event->key.code};
m3_Call(exports[G_EXPORT_KEY_UP], 1, args);
M3Result res = m3_Call(exports[G_EXPORT_KEY_UP], 1, args);
if(res)
{
ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
}
}
}
} break;
@ -732,8 +840,11 @@ i32 orca_runloop(void* user)
if(exports[G_EXPORT_FRAME_REFRESH])
{
mg_surface_prepare(app->surface);
m3_Call(exports[G_EXPORT_FRAME_REFRESH], 0, 0);
M3Result res = m3_Call(exports[G_EXPORT_FRAME_REFRESH], 0, 0);
if(res)
{
ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
}
}
if(app->debugOverlay.show)
@ -761,10 +872,6 @@ int main(int argc, char** argv)
mp_rect windowRect = {.x = 100, .y = 100, .w = 810, .h = 610};
app->window = mp_window_create(windowRect, "orca", 0);
app->surface = mg_surface_create_for_window(app->window, MG_CANVAS);
app->canvas = mg_canvas_create();
mg_surface_swap_interval(app->surface, 1);
app->debugOverlay.show = false;
app->debugOverlay.surface = mg_surface_create_for_window(app->window, MG_CANVAS);
app->debugOverlay.canvas = mg_canvas_create();
@ -784,11 +891,6 @@ int main(int argc, char** argv)
for(int i=0; i<3; i++)
{
mg_surface_prepare(app->surface);
mg_canvas_set_current(app->canvas);
mg_render(app->surface, app->canvas);
mg_surface_present(app->surface);
mg_surface_prepare(app->debugOverlay.surface);
mg_canvas_set_current(app->debugOverlay.canvas);
mg_render(app->debugOverlay.surface, app->debugOverlay.canvas);
@ -812,9 +914,6 @@ int main(int argc, char** argv)
mp_thread_join(runloopThread, NULL);
mg_canvas_destroy(app->canvas);
mg_surface_destroy(app->surface);
mg_canvas_destroy(app->debugOverlay.canvas);
mg_surface_destroy(app->debugOverlay.surface);

View File

@ -1,29 +0,0 @@
const void* glShaderSource_stub(IM3Runtime runtime, IM3ImportContext _ctx, uint64_t * _sp, void * _mem)
{
i32 shader = *(i32*)&_sp[0];
i32 count = *(i32*)&_sp[1];
i32 stringArrayOffset = *(i32*)&_sp[2];
i32 lengthArrayOffset = *(i32*)&_sp[3];
int* stringOffsetArray = (int*)((char*)_mem + stringArrayOffset);
const char** stringArray = (const char**)mem_arena_alloc_array(mem_scratch(), char*, count);
for(int i=0; i<count; i++)
{
stringArray[i] = (char*)_mem + stringOffsetArray[i];
}
int* lengthArray = lengthArrayOffset ? (int*)((char*)_mem + lengthArrayOffset) : 0;
glShaderSource(shader, count, stringArray, lengthArray);
return(0);
}
int manual_link_gles_api(IM3Module module)
{
M3Result res;
res = m3_LinkRawFunction(module, "*", "glShaderSource", "v(iiii)", glShaderSource_stub);
if(res) { log_error("error: %s\n", res); return(-1); }
return(0);
}

View File

@ -112,8 +112,6 @@ typedef struct orca_debug_overlay
typedef struct orca_app
{
mp_window window;
mg_surface surface;
mg_canvas canvas;
file_table fileTable;
file_handle rootDir;
@ -128,4 +126,13 @@ orca_app* orca_app_get();
orca_runtime* orca_runtime_get();
int orca_assert(const char* file, const char* function, int line, const char* src, const char* note);
int orca_assert_fmt(const char* file, const char* function, int line, const char* src, const char* fmt, ...);
void orca_abort_fmt(const char* file, const char* function, int line, const char* fmt, ...);
#define _ORCA_ASSERT_(test, fmt, ...) ((test) || orca_assert_fmt(__FILE__, __FUNCTION__, __LINE__, #test, fmt, ##__VA_ARGS__))
#define ORCA_ASSERT(test, ...) _ORCA_ASSERT_(test, ORCA_VA_NOPT("", ##__VA_ARGS__) ORCA_ARG1(__VA_ARGS__) ORCA_VA_COMMA_TAIL(__VA_ARGS__))
#define ORCA_ABORT(fmt, ...) orca_abort_fmt(__FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
#endif //__ORCA_RUNTIME_H_