initial commit
This commit is contained in:
parent
d3970e3f18
commit
496943a5bd
|
@ -0,0 +1,13 @@
|
|||
# Build files
|
||||
/build-fx
|
||||
/build-cg
|
||||
/*.g1a
|
||||
/*.g3a
|
||||
|
||||
# Python bytecode
|
||||
__pycache__/
|
||||
|
||||
# Common IDE files
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
.vscode
|
|
@ -0,0 +1,50 @@
|
|||
# Configure with [fxsdk build-fx] or [fxsdk build-cg], which provide the
|
||||
# toolchain file and module path of the fxSDK
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(MyAddin)
|
||||
|
||||
include(GenerateG1A)
|
||||
include(GenerateG3A)
|
||||
include(Fxconv)
|
||||
find_package(Gint 2.9 REQUIRED)
|
||||
find_package(LibProf 2.4 REQUIRED)
|
||||
|
||||
|
||||
set(SOURCES
|
||||
src/main.c
|
||||
# src/menus.c
|
||||
# src/fluid64x64.c
|
||||
# src/fluid128x64.c
|
||||
)
|
||||
# Shared assets, fx-9860G-only assets and fx-CG-50-only assets
|
||||
set(ASSETS
|
||||
# ...
|
||||
)
|
||||
set(ASSETS_fx
|
||||
assets-fx/example.png
|
||||
assets-fx/myfont.png
|
||||
# ...
|
||||
)
|
||||
set(ASSETS_cg
|
||||
assets-cg/example.png
|
||||
# ...
|
||||
)
|
||||
|
||||
fxconv_declare_assets(${ASSETS} ${ASSETS_fx} ${ASSETS_cg} WITH_METADATA)
|
||||
|
||||
add_executable(myaddin ${SOURCES} ${ASSETS} ${ASSETS_${FXSDK_PLATFORM}})
|
||||
target_compile_options(myaddin PRIVATE -Wall -Wextra -O3)
|
||||
target_link_options(myaddin PRIVATE
|
||||
-Wl,-Map=map -Wl,--print-memory-usage)
|
||||
target_link_libraries(myaddin LibProf::LibProf)
|
||||
target_link_libraries(myaddin Gint::Gint)
|
||||
|
||||
|
||||
if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G)
|
||||
generate_g1a(TARGET myaddin OUTPUT "MyAddin.g1a"
|
||||
NAME "MyAddin" ICON assets-fx/icon.png)
|
||||
elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50)
|
||||
generate_g3a(TARGET myaddin OUTPUT "MyAddin.g3a"
|
||||
NAME "MyAddin" ICONS assets-cg/icon-uns.png assets-cg/icon-sel.png)
|
||||
endif()
|
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
|
@ -0,0 +1,3 @@
|
|||
example.png:
|
||||
type: bopti-image
|
||||
name: img_example
|
Binary file not shown.
After Width: | Height: | Size: 8.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
|
@ -0,0 +1,11 @@
|
|||
example.png:
|
||||
type: bopti-image
|
||||
name: img_example
|
||||
|
||||
myfont.png:
|
||||
type: font
|
||||
name: myfont
|
||||
charset: print
|
||||
grid.size: 5x7
|
||||
grid.padding: 1
|
||||
proportional: true
|
Binary file not shown.
After Width: | Height: | Size: 7.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
|
@ -0,0 +1,85 @@
|
|||
#ifndef DEFINES_H
|
||||
#define DEFINES_H
|
||||
|
||||
// Fixed Point
|
||||
|
||||
typedef int fix;
|
||||
|
||||
#define DB 16
|
||||
#define FIX(x) ((x)<<DB) // int to fixed
|
||||
#define FFIX(x) ((x)*(1<<DB)) // float to fixed
|
||||
#define UNFIX(x) ((x)>>DB) // fixed to int
|
||||
|
||||
fix fmul(fix x, fix y) {
|
||||
int64_t p = (int64_t)x * (int64_t)y;
|
||||
return (int32_t)(p >> DB);
|
||||
}
|
||||
|
||||
fix ffrac(fix f) {
|
||||
return f & ((1 << DB) - 1);
|
||||
}
|
||||
|
||||
float fixtof(fix f) {
|
||||
return ((float)f)/(1<<DB);
|
||||
}
|
||||
|
||||
|
||||
// 64x64 simulation
|
||||
|
||||
#define W 64//29
|
||||
#define H 64//19
|
||||
#define ID(x, y) ((x) + (y) * W)
|
||||
|
||||
#define fH (float)H
|
||||
#define MAX_X FIX(W - 1)
|
||||
#define MAX_Y FIX(H - 1)
|
||||
#define rdx FIX(H/2)
|
||||
#define dx FFIX(1./(fH/2.))
|
||||
#define dtRdx fmul(dt, rdx)
|
||||
#define halfRdx rdx/2
|
||||
#define alpha fmul(-ONE, fmul(dx, dx))
|
||||
#define alphaHalfRdx fmul(alpha, halfRdx)
|
||||
|
||||
|
||||
// 128x64 simulation
|
||||
|
||||
#define W2 128
|
||||
#define ID2(x, y) ((x) + (y) * W2)
|
||||
|
||||
#define MAX_X2 FIX(W2 - 1)
|
||||
|
||||
|
||||
// Global Defines
|
||||
|
||||
#define ONE FIX(1)
|
||||
#define ONE_HALF ONE/2
|
||||
#define dt FFIX(1./14.)
|
||||
|
||||
#define PREC_STEP FFIX(0.001)
|
||||
|
||||
#define swap(a, b) { fix *tmp=a; a=b; b=tmp; }
|
||||
|
||||
#define div tx
|
||||
#define p ty
|
||||
|
||||
#define K_RESET KEY_DEL
|
||||
#define K_PARAMS KEY_SHIFT
|
||||
#define K_COLORS KEY_ALPHA
|
||||
#define K_FPS KEY_MUL
|
||||
#define K_HELP KEY_OPTN
|
||||
|
||||
fix radius = FIX(4);
|
||||
fix dyeDiffusion = FFIX(0.999);
|
||||
fix velDiffusion = FFIX(1);
|
||||
fix dyeIntensity = FFIX(0.5);
|
||||
fix velIntensity = FFIX(0.5);
|
||||
const fix maxDyeIntensity = FIX(4);
|
||||
fix emptyTreshold = FFIX(0.4);
|
||||
fix saturateTreshold = FFIX(0.8);
|
||||
int pressureIterations = 10;
|
||||
|
||||
fix *vx, *vy, *dye, *tx, *ty, *tz;
|
||||
int addX, addY;
|
||||
int currentView = 0; // 0 : simulation only, 1 : simulation + parameters, 2 : simulation + color settings
|
||||
|
||||
#endif // DEFINES_H
|
|
@ -0,0 +1,196 @@
|
|||
void advect128x64(fix* dye, fix* vx, fix* vy, fix* outx, fix* outy, fix* outz) {
|
||||
for (int j = 1; j < H-1; j++) {
|
||||
for (int i = 1; i < W2-1; i++) {
|
||||
int id = ID2(i, j);
|
||||
|
||||
fix x = FIX(i) - fmul(dtRdx, vx[id]);
|
||||
fix y = FIX(j) - fmul(dtRdx, vy[id]);
|
||||
|
||||
if (x < 0) x = 0;
|
||||
else if (x > MAX_X2) x = MAX_X2;
|
||||
if (y < 0) y = 0;
|
||||
else if (y > MAX_Y) y = MAX_Y;
|
||||
|
||||
int x1 = UNFIX(x);
|
||||
int y1 = UNFIX(y);
|
||||
int x2 = x1 + 1;
|
||||
int y2 = y1 + 1;
|
||||
|
||||
int tl = ID2(x1, y1);
|
||||
int tr = ID2(x2, y1);
|
||||
int bl = ID2(x1, y2);
|
||||
int br = ID2(x2, y2);
|
||||
|
||||
fix s1 = ffrac(x);
|
||||
fix s0 = ONE - s1;
|
||||
fix t1 = ffrac(y);
|
||||
fix t0 = ONE - t1;
|
||||
|
||||
outx[id] = fmul(s0, fmul(t0, vx[tl]) + fmul(t1, vx[bl])) +
|
||||
fmul(s1, fmul(t0, vx[tr]) + fmul(t1, vx[br]));
|
||||
|
||||
outy[id] = fmul(s0, fmul(t0, vy[tl]) + fmul(t1, vy[bl])) +
|
||||
fmul(s1, fmul(t0, vy[tr]) + fmul(t1, vy[br]));
|
||||
|
||||
outz[id] = fmul(s0, fmul(t0, dye[tl]) + fmul(t1, dye[bl])) +
|
||||
fmul(s1, fmul(t0, dye[tr]) + fmul(t1, dye[br]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fluid_step128x64() {
|
||||
// Advect the velocity field and the dye (27.7ms)
|
||||
advect128x64(dye, vx, vy, tx, ty, tz);
|
||||
// Swap the pointers
|
||||
swap(vx, tx);
|
||||
swap(vy, ty);
|
||||
swap(dye, tz);
|
||||
|
||||
// Velocity boundary conditions (0.1ms)
|
||||
for (int i = 0; i < W2; i++) {
|
||||
vy[ID2(i, 0)] = -vy[ID2(i, 1)];
|
||||
vy[ID2(i, H-1)] = -vy[ID2(i, H-2)];
|
||||
vx[ID2(i, 0)] = vx[ID2(i, 1)];
|
||||
vx[ID2(i, H-1)] = vx[ID2(i, H-2)];
|
||||
}
|
||||
for (int j = 0; j < H; j++) {
|
||||
vx[ID2(0, j)] = -vx[ID2(1, j)];
|
||||
vx[ID2(W2-1, j)] = -vx[ID2(W2-2, j)];
|
||||
vy[ID2(0, j)] = vy[ID2(1, j)];
|
||||
vy[ID2(W2-1, j)] = vy[ID2(W2-2, j)];
|
||||
}
|
||||
|
||||
// Calculate divergence & first pressure iteration (3.6ms)
|
||||
for (int j = 1; j < H-1; j++) {
|
||||
for (int i = 1; i < W2-1; i++) {
|
||||
div[ID2(i, j)] = fmul(alphaHalfRdx, vx[ID2(i+1,j)] - vx[ID2(i-1, j)] + vy[ID2(i, j+1)] - vy[ID2(i, j-1)]);
|
||||
p[ID2(i, j)] = div[ID2(i, j)] >> 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Initial Pressure boundary conditions (0ms)
|
||||
for (int i = 0; i < W2; i++) {
|
||||
p[ID2(i, 0)] = p[ID2(i, 1)];
|
||||
p[ID2(i, H-1)] = p[ID2(i, H-2)];
|
||||
}
|
||||
for (int j = 0; j < H; j++) {
|
||||
p[ID2(0, j)] = p[ID2(1, j)];
|
||||
p[ID2(W2-1, j)] = p[ID2(W2-2, j)];
|
||||
}
|
||||
|
||||
// Poisson pressure solver (20.8ms)
|
||||
for (int k = 0; k < pressureIterations-1; k++) {
|
||||
// Jacobi iteration (20.4ms)
|
||||
for (int j = 1; j < H-1; j++) {
|
||||
for (int i = 1; i < W2-1; i++) {
|
||||
int id = ID2(i, j);
|
||||
p[id] = (div[id] + p[ID2(i-1, j)] + p[ID2(i+1, j)] + p[ID2(i, j-1)] + p[ID2(i, j+1)]) >> 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Pressure boundary conditions (0.4ms)
|
||||
for (int i = 0; i < W2; i++) {
|
||||
p[ID2(i, 0)] = p[ID2(i, 1)];
|
||||
p[ID2(i, H-1)] = p[ID2(i, H-2)];
|
||||
}
|
||||
for (int j = 0; j < H; j++) {
|
||||
p[ID2(0, j)] = p[ID2(1, j)];
|
||||
p[ID2(W2-1, j)] = p[ID2(W2-2, j)];
|
||||
}
|
||||
}
|
||||
|
||||
// Apply Forces
|
||||
if (currentView == 0) {
|
||||
int lastX = addX;
|
||||
int lastY = addY;
|
||||
|
||||
if (keydown(KEY_LEFT)) { addX -= 1; if (addX < 1) addX = W2-2; }
|
||||
else if (keydown(KEY_RIGHT)) { addX += 1; if (addX > W2-2) addX = 1; }
|
||||
if (keydown(KEY_UP)) { addY -= 1; if (addY < 1) addY = H-2; }
|
||||
else if (keydown(KEY_DOWN)) { addY += 1; if (addY > H-2) addY = 1; }
|
||||
|
||||
fix adx = FIX(addX - lastX);
|
||||
fix ady = FIX(addY - lastY);
|
||||
|
||||
if (adx || ady) {
|
||||
fix ddx = abs(adx);
|
||||
fix ddy = abs(ady);
|
||||
fix vdx = adx / 10;
|
||||
fix vdy = ady / 10;
|
||||
fix ddxy = ddx + ddy;
|
||||
|
||||
for (int j = addY-3; j < addY+3; j++) {
|
||||
for (int i = addX-3; i < addX+3; i++) {
|
||||
if (i<=0||j<=0||i>=W2-1||j>=H-1) continue;
|
||||
int id = ID2(i, j);
|
||||
|
||||
fix dist = radius - FIX((addX-i)*(addX-i)+(addY-j)*(addY-j));
|
||||
if (dist < 0) continue;
|
||||
fix dyeD = fmul(dist, dyeIntensity);
|
||||
fix velD = fmul(dist, velIntensity);
|
||||
|
||||
dye[id] = dye[id] + fmul(ddxy, dyeD);
|
||||
if (dye[id] > maxDyeIntensity) dye[id] = maxDyeIntensity;
|
||||
vx[id] = vx[id] + fmul(vdx, velD);
|
||||
vy[id] = vy[id] + fmul(vdy, velD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Subtract pressure from velocity & Diffuse dye and velocity (3.4ms)
|
||||
for (int j = 1; j < H-1; j++) {
|
||||
for (int i = 1; i < W2-1; i++) {
|
||||
int id = ID2(i, j);
|
||||
vx[id] = fmul(vx[id] - fmul(halfRdx, p[ID2(i+1, j)] - p[ID2(i-1, j)]), velDiffusion);
|
||||
vy[id] = fmul(vy[id] - fmul(halfRdx, p[ID2(i, j+1)] - p[ID2(i, j-1)]), velDiffusion);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw dye to vram (3.1ms)
|
||||
uint32_t *vram = gint_vram+4;
|
||||
for (int j = 1; j < H-1; j++) {
|
||||
uint32_t data = 0;
|
||||
|
||||
data = (data << 1);
|
||||
for(int k = 1; k < 32; k++) {
|
||||
int x = 32*0+k;
|
||||
int id = ID2(x, j);
|
||||
dye[id] = fmul(dye[id], dyeDiffusion);
|
||||
data = (data << 1) | (dye[id] > saturateTreshold || (dye[id] > emptyTreshold && (x+j)%2));
|
||||
}
|
||||
vram[0] = data;
|
||||
data = 0;
|
||||
|
||||
data = (data << 1);
|
||||
for(int k = 0; k < 32; k++) {
|
||||
int x = 32*1+k;
|
||||
int id = ID2(x, j);
|
||||
dye[id] = fmul(dye[id], dyeDiffusion);
|
||||
data = (data << 1) | (dye[id] > saturateTreshold || (dye[id] > emptyTreshold && (x+j)%2));
|
||||
}
|
||||
vram[1] = data;
|
||||
data = 0;
|
||||
|
||||
data = (data << 1);
|
||||
for(int k = 0; k < 32; k++) {
|
||||
int x = 32*2+k;
|
||||
int id = ID2(x, j);
|
||||
dye[id] = fmul(dye[id], dyeDiffusion);
|
||||
data = (data << 1) | (dye[id] > saturateTreshold || (dye[id] > emptyTreshold && (x+j)%2));
|
||||
}
|
||||
vram[2] = data;
|
||||
data = 0;
|
||||
|
||||
for(int k = 0; k < 31; k++) {
|
||||
int x = 32*3+k;
|
||||
int id = ID2(x, j);
|
||||
dye[id] = fmul(dye[id], dyeDiffusion);
|
||||
data = (data << 1) | (dye[id] > saturateTreshold || (dye[id] > emptyTreshold && (x+j)%2));
|
||||
}
|
||||
data = (data << 1);
|
||||
vram[3] = data;
|
||||
|
||||
vram+=4;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
void advect64x64(fix* dye, fix* vx, fix* vy, fix* outx, fix* outy, fix* outz) {
|
||||
for (int j = 1; j < H-1; j++) {
|
||||
for (int i = 1; i < W-1; i++) {
|
||||
int id = ID(i, j);
|
||||
|
||||
fix x = FIX(i) - fmul(dtRdx, vx[id]);
|
||||
fix y = FIX(j) - fmul(dtRdx, vy[id]);
|
||||
|
||||
if (x < 0) x = 0;
|
||||
else if (x > MAX_X) x = MAX_X;
|
||||
if (y < 0) y = 0;
|
||||
else if (y > MAX_Y) y = MAX_Y;
|
||||
|
||||
int x1 = UNFIX(x);
|
||||
int y1 = UNFIX(y);
|
||||
int x2 = x1 + 1;
|
||||
int y2 = y1 + 1;
|
||||
|
||||
int tl = ID(x1, y1);
|
||||
int tr = ID(x2, y1);
|
||||
int bl = ID(x1, y2);
|
||||
int br = ID(x2, y2);
|
||||
|
||||
fix s1 = ffrac(x);
|
||||
fix s0 = ONE - s1;
|
||||
fix t1 = ffrac(y);
|
||||
fix t0 = ONE - t1;
|
||||
|
||||
outx[id] = fmul(s0, fmul(t0, vx[tl]) + fmul(t1, vx[bl])) +
|
||||
fmul(s1, fmul(t0, vx[tr]) + fmul(t1, vx[br]));
|
||||
|
||||
outy[id] = fmul(s0, fmul(t0, vy[tl]) + fmul(t1, vy[bl])) +
|
||||
fmul(s1, fmul(t0, vy[tr]) + fmul(t1, vy[br]));
|
||||
|
||||
outz[id] = fmul(s0, fmul(t0, dye[tl]) + fmul(t1, dye[bl])) +
|
||||
fmul(s1, fmul(t0, dye[tr]) + fmul(t1, dye[br]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fluid_step64x64() {
|
||||
// Advect the velocity field and the dye (27.7ms)
|
||||
advect64x64(dye, vx, vy, tx, ty, tz);
|
||||
// Swap the pointers
|
||||
swap(vx, tx);
|
||||
swap(vy, ty);
|
||||
swap(dye, tz);
|
||||
|
||||
// Velocity boundary conditions (0.1ms)
|
||||
for (int i = 0; i < W; i++) {
|
||||
vy[ID(i, 0)] = -vy[ID(i, 1)];
|
||||
vy[ID(i, H-1)] = -vy[ID(i, H-2)];
|
||||
vx[ID(i, 0)] = vx[ID(i, 1)];
|
||||
vx[ID(i, H-1)] = vx[ID(i, H-2)];
|
||||
}
|
||||
for (int j = 0; j < H; j++) {
|
||||
vx[ID(0, j)] = -vx[ID(1, j)];
|
||||
vx[ID(W-1, j)] = -vx[ID(W-2, j)];
|
||||
vy[ID(0, j)] = vy[ID(1, j)];
|
||||
vy[ID(W-1, j)] = vy[ID(W-2, j)];
|
||||
}
|
||||
|
||||
// Calculate divergence & first pressure iteration (3.6ms)
|
||||
for (int j = 1; j < H-1; j++) {
|
||||
for (int i = 1; i < W-1; i++) {
|
||||
div[ID(i, j)] = fmul(alphaHalfRdx, vx[ID(i+1,j)] - vx[ID(i-1, j)] + vy[ID(i, j+1)] - vy[ID(i, j-1)]);
|
||||
p[ID(i, j)] = div[ID(i, j)] >> 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Initial Pressure boundary conditions (0ms)
|
||||
for (int i = 0; i < W; i++) {
|
||||
p[ID(i, 0)] = p[ID(i, 1)];
|
||||
p[ID(i, H-1)] = p[ID(i, H-2)];
|
||||
}
|
||||
for (int j = 0; j < H; j++) {
|
||||
p[ID(0, j)] = p[ID(1, j)];
|
||||
p[ID(W-1, j)] = p[ID(W-2, j)];
|
||||
}
|
||||
|
||||
// Poisson pressure solver (20.8ms)
|
||||
for (int k = 0; k < pressureIterations-1; k++) {
|
||||
// Jacobi iteration (20.4ms)
|
||||
for (int j = 1; j < H-1; j++) {
|
||||
for (int i = 1; i < W-1; i++) {
|
||||
int id = ID(i, j);
|
||||
p[id] = (div[id] + p[ID(i-1, j)] + p[ID(i+1, j)] + p[ID(i, j-1)] + p[ID(i, j+1)]) >> 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Pressure boundary conditions (0.4ms)
|
||||
for (int i = 0; i < W; i++) {
|
||||
p[ID(i, 0)] = p[ID(i, 1)];
|
||||
p[ID(i, H-1)] = p[ID(i, H-2)];
|
||||
}
|
||||
for (int j = 0; j < H; j++) {
|
||||
p[ID(0, j)] = p[ID(1, j)];
|
||||
p[ID(W-1, j)] = p[ID(W-2, j)];
|
||||
}
|
||||
}
|
||||
|
||||
// Apply Forces
|
||||
if (currentView == 0) {
|
||||
int lastX = addX;
|
||||
int lastY = addY;
|
||||
|
||||
if (keydown(KEY_LEFT)) { addX -= 1; if (addX < 1) addX = W-2; }
|
||||
else if (keydown(KEY_RIGHT)) { addX += 1; if (addX > W-2) addX = 1; }
|
||||
if (keydown(KEY_UP)) { addY -= 1; if (addY < 1) addY = H-2; }
|
||||
else if (keydown(KEY_DOWN)) { addY += 1; if (addY > H-2) addY = 1; }
|
||||
|
||||
fix adx = FIX(addX - lastX);
|
||||
fix ady = FIX(addY - lastY);
|
||||
|
||||
if (adx || ady) {
|
||||
fix ddx = abs(adx);
|
||||
fix ddy = abs(ady);
|
||||
fix vdx = adx / 10;
|
||||
fix vdy = ady / 10;
|
||||
fix ddxy = ddx + ddy;
|
||||
|
||||
for (int j = addY-3; j < addY+3; j++) {
|
||||
for (int i = addX-3; i < addX+3; i++) {
|
||||
if (i<=0||j<=0||i>=W-1||j>=H-1) continue;
|
||||
int id = ID(i, j);
|
||||
|
||||
fix dist = radius - FIX((addX-i)*(addX-i)+(addY-j)*(addY-j));
|
||||
if (dist < 0) continue;
|
||||
fix dyeD = fmul(dist, dyeIntensity);
|
||||
fix velD = fmul(dist, velIntensity);
|
||||
|
||||
dye[id] = dye[id] + fmul(ddxy, dyeD);
|
||||
if (dye[id] > maxDyeIntensity) dye[id] = maxDyeIntensity;
|
||||
vx[id] = vx[id] + fmul(vdx, velD);
|
||||
vy[id] = vy[id] + fmul(vdy, velD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Subtract pressure from velocity & Diffuse dye and velocity (3.4ms)
|
||||
for (int j = 1; j < H-1; j++) {
|
||||
for (int i = 1; i < W-1; i++) {
|
||||
int id = ID(i, j);
|
||||
vx[id] = fmul(vx[id] - fmul(halfRdx, p[ID(i+1, j)] - p[ID(i-1, j)]), velDiffusion);
|
||||
vy[id] = fmul(vy[id] - fmul(halfRdx, p[ID(i, j+1)] - p[ID(i, j-1)]), velDiffusion);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw dye to vram (3.1ms)
|
||||
uint32_t *vram = gint_vram+4;
|
||||
for (int j = 1; j < H-1; j++) {
|
||||
uint32_t data = 0;
|
||||
|
||||
data = (data << 1);
|
||||
for(int k = 1; k < 32; k++) {
|
||||
int x = 32*0+k;
|
||||
int id = ID(x, j);
|
||||
dye[id] = fmul(dye[id], dyeDiffusion);
|
||||
data = (data << 1) | (dye[id] > saturateTreshold || (dye[id] > emptyTreshold && (x+j)%2));
|
||||
}
|
||||
vram[0] = data;
|
||||
data = 0;
|
||||
|
||||
for(int k = 0; k < 31; k++) {
|
||||
int x = 32*1+k;
|
||||
int id = ID(x, j);
|
||||
dye[id] = fmul(dye[id], dyeDiffusion);
|
||||
data = (data << 1) | (dye[id] > saturateTreshold || (dye[id] > emptyTreshold && (x+j)%2));
|
||||
}
|
||||
data = (data << 1);
|
||||
vram[1] = data;
|
||||
|
||||
vram+=4;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <gint/display.h>
|
||||
#include <gint/hardware.h>
|
||||
#include <gint/keyboard.h>
|
||||
#include <gint/clock.h>
|
||||
#include <fxlibc/printf.h>
|
||||
#include <libprof.h>
|
||||
|
||||
#include "defines.h"
|
||||
#include "menus.c"
|
||||
#include "fluid64x64.c"
|
||||
#include "fluid128x64.c"
|
||||
|
||||
int main(void) {
|
||||
if(gint[HWCALC] == HWCALC_G35PE2) {
|
||||
dtext_opt(64, 10, C_BLACK, C_WHITE, DTEXT_CENTER, DTEXT_TOP, "Cette calculatrice", -1);
|
||||
dtext_opt(64, 25, C_BLACK, C_WHITE, DTEXT_CENTER, DTEXT_TOP, "est incompatible.", -1);
|
||||
dtext_opt(64, 45, C_BLACK, C_WHITE, DTEXT_CENTER, DTEXT_TOP, "[EXE] Quitter", -1);
|
||||
dupdate();
|
||||
getkey();
|
||||
return 1;
|
||||
}
|
||||
|
||||
fix (*buffers)[W*H] = (void *)0x88040000; // magic pointer to extra memory
|
||||
fix (*buffersFS)[W2*H] = (void *)0x88040000;
|
||||
dye = buffers[0]; // dye concentration
|
||||
vx = buffers[1]; // fluid x velocity
|
||||
vy = buffers[2]; // fluid y velocity
|
||||
tx = buffers[3]; // temp buffer (used to advect vx & to compute div)
|
||||
ty = buffers[4]; // temp buffer (used to advect vy & to compute p)
|
||||
tz = buffers[5]; // temp buffer (used to advect dye)
|
||||
|
||||
// Empty all buffers
|
||||
memset(buffers, 0, W*H*sizeof(fix)*6);
|
||||
|
||||
// Init timer
|
||||
prof_init();
|
||||
prof_t prof = prof_make();
|
||||
uint32_t lastTime = 0, time = 0;
|
||||
|
||||
// Init font
|
||||
extern font_t myfont;
|
||||
dfont(&myfont);
|
||||
__printf_enable_fp();
|
||||
|
||||
main_menu();
|
||||
// settings_menu(true);
|
||||
|
||||
/// Main Loop ///
|
||||
bool fullscreen = false;
|
||||
bool showFPS = true;
|
||||
addX = W/2;
|
||||
addY = H/2;
|
||||
while (1) {
|
||||
prof_enter(prof); // resume timer
|
||||
|
||||
clearevents(); // Read all events
|
||||
|
||||
if (fullscreen) { // fullscreen 128x64 simulation
|
||||
fluid_step128x64();
|
||||
drect_border(0, 0, 127, H-1, C_NONE, 1, C_BLACK);
|
||||
|
||||
// Handle fullscreen exit
|
||||
if (keydown(KEY_MINUS) || keydown(K_PARAMS) || keydown(K_COLORS)) {
|
||||
fullscreen = false;
|
||||
memset(buffers, 0, W*H*sizeof(fix)*6);
|
||||
|
||||
dye = buffers[0];
|
||||
vx = buffers[1];
|
||||
vy = buffers[2];
|
||||
tx = buffers[3];
|
||||
ty = buffers[4];
|
||||
tz = buffers[5];
|
||||
|
||||
dclear(C_WHITE);
|
||||
if (keydown(K_PARAMS)) settings_menu(true);
|
||||
}
|
||||
} else { // halfscreen 64x64 simulation
|
||||
fluid_step64x64();
|
||||
settings_menu(false);
|
||||
|
||||
// Handle fullscreen enter
|
||||
if (keydown(KEY_PLUS)) {
|
||||
fullscreen = true;
|
||||
currentView = 0;
|
||||
memset(buffers, 0, W2*H*sizeof(fix)*6);
|
||||
|
||||
dye = buffersFS[0];
|
||||
vx = buffersFS[1];
|
||||
vy = buffersFS[2];
|
||||
tx = buffersFS[3];
|
||||
ty = buffersFS[4];
|
||||
tz = buffersFS[5];
|
||||
|
||||
dclear(C_WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
// Simulation reset
|
||||
if (keydown(K_RESET)) {
|
||||
memset(buffers, 0, (fullscreen ? W2 : W)*H*sizeof(fix)*6);
|
||||
} // Toggle FPS
|
||||
else if (keydown(K_FPS)) {
|
||||
showFPS = !showFPS;
|
||||
} // Toggle help screen
|
||||
else if (keydown(K_HELP) || keydown(KEY_EXIT)) {
|
||||
int res = help_menu();
|
||||
currentView = 0;
|
||||
if (res == -1) return 1;
|
||||
}
|
||||
|
||||
color_menu();
|
||||
|
||||
// Show FPS
|
||||
if (showFPS) {
|
||||
int ms = (time - lastTime)/1000;
|
||||
sprintf(strFPS, "%dms / %dfps", (time - lastTime)/100, 1000/ms);
|
||||
dtext_opt(66, 1, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, strFPS, -1);
|
||||
dline(64, 8, 127, 8, C_BLACK);
|
||||
}
|
||||
|
||||
// Update vram
|
||||
dupdate();
|
||||
|
||||
// pause timer
|
||||
prof_leave(prof);
|
||||
lastTime = time;
|
||||
time = prof_time(prof);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,321 @@
|
|||
char strFPS[20];
|
||||
char strDyeDiff[20];
|
||||
char strVelDiff[20];
|
||||
char strDyeForce[20];
|
||||
char strVelForce[20];
|
||||
char strRadius[20];
|
||||
char strPressureIter[20];
|
||||
char strEmptyTreshold[20];
|
||||
char strSaturateTreshold[20];
|
||||
|
||||
// Main Screen
|
||||
void main_menu() {
|
||||
const int gap = 8;
|
||||
const int startY = 11;
|
||||
dhline(5, C_BLACK);
|
||||
dtext_opt(64, 2, C_BLACK, C_WHITE, DTEXT_CENTER, DTEXT_TOP, " CASIO FLUID SIMULATION ", -1);
|
||||
dtext_opt(3, startY, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, "Implementation of Jos Stam's", -1);
|
||||
dtext_opt(3, startY + gap, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, "\"Real Time Fluid Dynamics for", -1);
|
||||
dtext_opt(3, startY + gap*2, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, "games\" paper on monochrome", -1);
|
||||
dtext_opt(3, startY + gap*3, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, "Casio calculators", -1);
|
||||
dtext_opt(3, startY + gap*4+2, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, "[Optn] key displays the help", -1);
|
||||
dtext_opt(124, 62, C_BLACK, C_WHITE, DTEXT_RIGHT, DTEXT_BOTTOM, "[EXE] Start", -1);
|
||||
dupdate();
|
||||
dclear(C_WHITE);
|
||||
|
||||
sleep_ms(500);
|
||||
|
||||
while(1) {
|
||||
clearevents();
|
||||
uint key = getkey().key;
|
||||
if (key == KEY_EXE || key == K_HELP) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Controls/Help Menu
|
||||
int help_menu() {
|
||||
const int margin = 2;
|
||||
|
||||
drect_border(margin, margin, 128 - margin-1, 64 - margin-1, C_WHITE, 1, C_BLACK);
|
||||
dtext_opt(margin+2, margin+3+8*0, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, "[Arrows]: Interact", -1);
|
||||
dtext_opt(margin+2, margin+3+8*1, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, "[Shift]: Toggle edit mode", -1);
|
||||
dtext_opt(margin+2, margin+3+8*2, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, "[Alpha]: Toggle color mode", -1);
|
||||
dtext_opt(margin+2, margin+3+8*3, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, "[Del]: Reset the simulation", -1);
|
||||
dtext_opt(margin+2, margin+3+8*4, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, "[+]/[-]: Toggle fullscreen", -1);
|
||||
dtext_opt(margin+2, margin+3+8*5, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, "[x]: Hide/Show FPS", -1);
|
||||
dtext_opt(margin+2, margin+3+8*6, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, "[Exit]: Quit [EXE]: Continue", -1);
|
||||
dupdate();
|
||||
dclear(C_WHITE);
|
||||
|
||||
while(1) {
|
||||
uint key = getkey().key;
|
||||
if (key == KEY_EXIT) return -1;
|
||||
if (key == KEY_EXE || key == K_HELP) return 0;
|
||||
}
|
||||
// if (getkey().key == KEY_EXIT) return -1;
|
||||
// return 0;
|
||||
}
|
||||
|
||||
// Fluid Simulation Settings Menu
|
||||
void settings_menu(bool redraw) {
|
||||
static int selected = 0;
|
||||
const int menuX = 66;
|
||||
const int menuY = 2;
|
||||
const int gap = 8;
|
||||
const int rx = 64;
|
||||
const bool activated = redraw;
|
||||
bool updateRect = false, updateDyeD = activated, updateVelD = activated, updateDyeF = activated, updateVelF = activated, updateRadius = activated, updatePressureIter = activated;
|
||||
static bool releaseParams = true;
|
||||
|
||||
if (currentView == 1 && releaseParams && keydown(K_PARAMS)) {
|
||||
releaseParams = false;
|
||||
currentView = 0;
|
||||
int ry = menuY+gap*(selected+1)+2;
|
||||
drect(rx, ry, rx, ry+2, C_WHITE);
|
||||
drect_border(63, 0, 127, H-1, C_NONE, 1, C_WHITE);
|
||||
}
|
||||
else if (currentView != 1 && releaseParams && keydown(K_PARAMS)) {
|
||||
releaseParams = false;
|
||||
currentView = 1;
|
||||
updateRect = true;
|
||||
updateDyeD = true, updateVelD = true, updateDyeF = true, updateVelF = true, updateRadius = true, updatePressureIter = true;
|
||||
drect(64, 0, 128, 64, C_WHITE);
|
||||
drect_border(0, 0, W-1, H-1, C_NONE, 1, C_WHITE);
|
||||
} else if (!keydown(K_PARAMS)) {
|
||||
releaseParams = true;
|
||||
}
|
||||
|
||||
if (currentView == 0) {
|
||||
drect_border(0, 0, W-1, H-1, C_NONE, 1, C_BLACK);
|
||||
if (!redraw) return;
|
||||
} else if (currentView == 2) return;
|
||||
{
|
||||
drect_border(0, 0, W-1, H-1, C_NONE, 1, C_WHITE);
|
||||
drect_border(63, 0, 127, H-1, C_NONE, 1, C_BLACK);
|
||||
}
|
||||
|
||||
if (keydown(KEY_LEFT)) {
|
||||
if (selected == 0 && dyeDiffusion > 0) {
|
||||
dyeDiffusion -= PREC_STEP;
|
||||
updateDyeD = true;
|
||||
}
|
||||
else if (selected == 1 && velDiffusion > 0) {
|
||||
velDiffusion -= PREC_STEP;
|
||||
updateVelD = true;
|
||||
}
|
||||
else if (selected == 2 && dyeIntensity > 0) {
|
||||
dyeIntensity -= PREC_STEP;
|
||||
updateDyeF = true;
|
||||
}
|
||||
else if (selected == 3 && velIntensity > 0) {
|
||||
velIntensity -= PREC_STEP;
|
||||
updateVelF = true;
|
||||
}
|
||||
else if (selected == 4 && radius > ONE) {
|
||||
radius -= FIX(1);
|
||||
updateRadius = true;
|
||||
}
|
||||
else if (selected == 5 && pressureIterations > 0) {
|
||||
pressureIterations--;
|
||||
updatePressureIter = true;
|
||||
}
|
||||
}
|
||||
else if (keydown(KEY_RIGHT)) {
|
||||
if (selected == 0 && dyeDiffusion < ONE) {
|
||||
dyeDiffusion += PREC_STEP;
|
||||
updateDyeD = true;
|
||||
}
|
||||
else if (selected == 1 && velDiffusion < ONE) {
|
||||
velDiffusion += PREC_STEP;
|
||||
updateVelD = true;
|
||||
}
|
||||
else if (selected == 2 && dyeIntensity < ONE*2) {
|
||||
dyeIntensity += PREC_STEP;
|
||||
updateDyeF = true;
|
||||
}
|
||||
else if (selected == 3 && velIntensity < ONE*2) {
|
||||
velIntensity += PREC_STEP;
|
||||
updateVelF = true;
|
||||
}
|
||||
else if (selected == 4 && radius < ONE*10) {
|
||||
radius += FIX(1);
|
||||
updateRadius = true;
|
||||
}
|
||||
else if (selected == 5) {
|
||||
pressureIterations++;
|
||||
updatePressureIter = true;
|
||||
}
|
||||
}
|
||||
else if (keydown(KEY_UP)) {
|
||||
int ry = menuY+gap*(selected+1)+2;
|
||||
drect(rx, ry, rx, ry+2, C_WHITE);
|
||||
if (--selected < 0) selected = 5;
|
||||
updateRect = true;
|
||||
}
|
||||
else if (keydown(KEY_DOWN)) {
|
||||
int ry = menuY+gap*(selected+1)+2;
|
||||
drect(rx, ry, rx, ry+2, C_WHITE);
|
||||
if (++selected > 5) selected = 0;
|
||||
updateRect = true;
|
||||
}
|
||||
|
||||
if (updateDyeD) {
|
||||
sprintf(strDyeDiff, "dye diff:%.3f ", fixtof(dyeDiffusion));
|
||||
dtext_opt(menuX, menuY + gap, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, strDyeDiff, -1);
|
||||
}
|
||||
if (updateVelD) {
|
||||
sprintf(strVelDiff, "vel diff:%.3f ", fixtof(velDiffusion));
|
||||
dtext_opt(menuX, menuY + gap*2, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, strVelDiff, -1);
|
||||
}
|
||||
if (updateDyeF) {
|
||||
sprintf(strDyeForce, "dye force:%.1f ", fixtof(dyeIntensity));
|
||||
dtext_opt(menuX, menuY + gap*3, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, strDyeForce, -1);
|
||||
}
|
||||
if (updateVelF) {
|
||||
sprintf(strVelForce, "vel force:%.1f ", fixtof(velIntensity));
|
||||
dtext_opt(menuX, menuY + gap*4, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, strVelForce, -1);
|
||||
}
|
||||
if (updateRadius) {
|
||||
sprintf(strRadius, "radius: %d ", UNFIX(radius));
|
||||
dtext_opt(menuX, menuY + gap*5, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, strRadius, -1);
|
||||
}
|
||||
if (updatePressureIter) {
|
||||
sprintf(strPressureIter, "iterations: %d ", pressureIterations);
|
||||
dtext_opt(menuX, menuY + gap*6, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, strPressureIter, -1);
|
||||
}
|
||||
if (updateRect) {
|
||||
int ry = menuY+gap*(selected+1)+2;
|
||||
drect(rx, ry, rx, ry+2, C_BLACK);
|
||||
}
|
||||
}
|
||||
|
||||
// Fluid color settings Menu
|
||||
void color_menu() {
|
||||
const int xmargin = 3;
|
||||
const float fw = 64. - (float)xmargin * 2.;
|
||||
const int y = 22;
|
||||
const int h = 5;
|
||||
const int bar_overflow = 3;
|
||||
const int STEP_MULT = 20;
|
||||
|
||||
const float tresh1 = fixtof(emptyTreshold);
|
||||
const float tresh2 = fixtof(saturateTreshold);
|
||||
const int x1 = 64 + xmargin + (int)(tresh1 * fw);
|
||||
const int x2 = 64 + xmargin + (int)(tresh2 * fw);
|
||||
|
||||
static bool x1Selected = true;
|
||||
static bool releaseKey = true;
|
||||
bool updated = false;
|
||||
|
||||
// Manage keys
|
||||
if (keydown(K_COLORS) && releaseKey) {
|
||||
releaseKey = false;
|
||||
if (currentView == 2) {
|
||||
currentView = 0;
|
||||
drect_border(63, 0, 127, H-1, C_NONE, 1, C_WHITE);
|
||||
}
|
||||
else {
|
||||
currentView = 2;
|
||||
updated = true;
|
||||
}
|
||||
} else if (!keydown(K_COLORS) && !releaseKey) {
|
||||
releaseKey = true;
|
||||
}
|
||||
|
||||
if (currentView != 2) return;
|
||||
|
||||
if (keydown(KEY_F1)) {
|
||||
emptyTreshold -= PREC_STEP * STEP_MULT;
|
||||
if (emptyTreshold < 0) emptyTreshold = 0;
|
||||
|
||||
x1Selected = true;
|
||||
updated = true;
|
||||
}
|
||||
else if (keydown(KEY_F2)) {
|
||||
emptyTreshold += PREC_STEP * STEP_MULT;
|
||||
if (emptyTreshold > ONE) emptyTreshold = ONE;
|
||||
if (emptyTreshold > saturateTreshold) saturateTreshold = emptyTreshold;
|
||||
|
||||
x1Selected = true;
|
||||
updated = true;
|
||||
}
|
||||
else if (keydown(KEY_F3)) {
|
||||
saturateTreshold -= PREC_STEP * STEP_MULT;
|
||||
if (saturateTreshold < 0) saturateTreshold = 0;
|
||||
if (saturateTreshold < emptyTreshold) emptyTreshold = saturateTreshold;
|
||||
|
||||
x1Selected = false;
|
||||
updated = true;
|
||||
}
|
||||
else if (keydown(KEY_F4)) {
|
||||
saturateTreshold += PREC_STEP * STEP_MULT;
|
||||
if (saturateTreshold > ONE) saturateTreshold = ONE;
|
||||
|
||||
x1Selected = false;
|
||||
updated = true;
|
||||
}
|
||||
else if (keydown(KEY_F5)) {
|
||||
fix diff = saturateTreshold - emptyTreshold;
|
||||
|
||||
emptyTreshold -= PREC_STEP * STEP_MULT;
|
||||
if (emptyTreshold < 0) emptyTreshold = 0;
|
||||
saturateTreshold = emptyTreshold + diff;
|
||||
|
||||
x1Selected = true;
|
||||
updated = true;
|
||||
}
|
||||
else if (keydown(KEY_F6)) {
|
||||
fix diff = saturateTreshold - emptyTreshold;
|
||||
|
||||
saturateTreshold += PREC_STEP * STEP_MULT;
|
||||
if (saturateTreshold > ONE) saturateTreshold = ONE;
|
||||
emptyTreshold = saturateTreshold - diff;
|
||||
|
||||
x1Selected = false;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
// Clear
|
||||
drect(64, 0, 128, 64, C_WHITE);
|
||||
drect_border(0, 0, W-1, H-1, C_NONE, 1, C_WHITE);
|
||||
|
||||
// Draw selectors
|
||||
if (x1Selected) {
|
||||
drect(x1-1, y - bar_overflow-1, x1+1, y+h+bar_overflow+1, C_BLACK);
|
||||
dline(x2, y - bar_overflow, x2, y+h+bar_overflow, C_BLACK);
|
||||
} else {
|
||||
dline(x1, y - bar_overflow, x1, y+h+bar_overflow, C_BLACK);
|
||||
drect(x2-1, y - bar_overflow-1, x2+1, y+h+bar_overflow+1, C_BLACK);
|
||||
}
|
||||
|
||||
// Draw white band
|
||||
drect(64 + xmargin, y, x1, y + h, C_WHITE);
|
||||
|
||||
// Draw checker band
|
||||
for (int j = y; j <= y+h; j++) {
|
||||
dline(x1, j, x2, j, j%2 ? C_BLACK : C_WHITE);
|
||||
}
|
||||
for (int i = x1; i < x2; i+=2) {
|
||||
dline(i, y, i, y+h, C_BLACK);
|
||||
}
|
||||
|
||||
// Draw black band
|
||||
drect(x2, y, 128 - xmargin, y + h, C_BLACK);
|
||||
|
||||
// Draw border
|
||||
drect_border(64 + xmargin-1, y-1, 128 - xmargin+1, y+h+1, C_NONE, 1, C_BLACK);
|
||||
|
||||
// Draw float values
|
||||
sprintf(strEmptyTreshold, "%.2f", tresh1);
|
||||
sprintf(strSaturateTreshold, "%.2f", tresh2);
|
||||
dtext_opt(x1, y - bar_overflow - 1, C_BLACK, C_WHITE, DTEXT_CENTER, DTEXT_BOTTOM, strEmptyTreshold, -1);
|
||||
dtext_opt(x2, y + h + bar_overflow + 1, C_BLACK, C_WHITE, DTEXT_CENTER, DTEXT_TOP, strSaturateTreshold, -1);
|
||||
|
||||
dtext_opt(65, 40, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, "[F1/F2] Lower", -1);
|
||||
dtext_opt(65, 48, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, "[F3/F4] Upper", -1);
|
||||
dtext_opt(65, 56, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, "[F5/F6] Both", -1);
|
||||
}
|
||||
|
||||
drect_border(63, 0, 127, H-1, C_NONE, 1, C_BLACK);
|
||||
}
|
Loading…
Reference in New Issue