Prob lighting

This commit is contained in:
Renan LE CARO 2025-04-20 09:33:12 +02:00
parent 6adab3d07f
commit a386c5f3d2
14 changed files with 160 additions and 44 deletions

View file

@ -27,8 +27,9 @@ Other translation are very welcome, contact me if you'd like to submit one.
## Done ## Done
- option: reuse past frame's light in new frame lighting computation when there are 150+ coins on screen, to limit the performance impact of rendering lots of lights
## 29084571 ## 29084606
- simpler and more readable encoding for save files - simpler and more readable encoding for save files
- removed check of payload signature on save file, seemed to fail because of the poor encoding of the name of the "côte d'ivoire" level - removed check of payload signature on save file, seemed to fail because of the poor encoding of the name of the "côte d'ivoire" level

66
dist/index.html vendored

File diff suppressed because one or more lines are too long

View file

@ -67,7 +67,7 @@ export async function openCreativeModePerksPicker() {
value: u, value: u,
className: creativeModePerks[u.id] className: creativeModePerks[u.id]
? "sandbox highlight" ? "sandbox highlight"
: "sandbox grey-out-unless-hovered", : "sandbox ",
tooltip: u.help(creativeModePerks[u.id] || 1), tooltip: u.help(creativeModePerks[u.id] || 1),
})), })),
t("lab.select_level"), t("lab.select_level"),

View file

@ -692,6 +692,7 @@ async function openSettingsMenu() {
"contrast", "contrast",
"smooth_lighting", "smooth_lighting",
"precise_lighting", "precise_lighting",
"probabilistic_lighting",
].includes(key)) || ].includes(key)) ||
false, false,
value: () => { value: () => {

View file

@ -194,6 +194,8 @@
"settings.pointer_lock_help": "يقوم بقفل وإخفاء مؤشر الماوس.", "settings.pointer_lock_help": "يقوم بقفل وإخفاء مؤشر الماوس.",
"settings.precise_lighting": "", "settings.precise_lighting": "",
"settings.precise_lighting_help": "", "settings.precise_lighting_help": "",
"settings.probabilistic_lighting": "",
"settings.probabilistic_lighting_help": "",
"settings.record": "تسجيل مقاطع فيديو للعبة", "settings.record": "تسجيل مقاطع فيديو للعبة",
"settings.record_download": "تنزيل الفيديو ({{size}} ميجابايت)", "settings.record_download": "تنزيل الفيديو ({{size}} ميجابايت)",
"settings.record_help": "احصل على فيديو لكل مستوى.", "settings.record_help": "احصل على فيديو لكل مستوى.",

View file

@ -6927,6 +6927,76 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>probabilistic_lighting</name>
<description/>
<comment/>
<translations>
<translation>
<language>ar-LB</language>
<approved>false</approved>
</translation>
<translation>
<language>de-DE</language>
<approved>false</approved>
</translation>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-CL</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-FR</language>
<approved>false</approved>
</translation>
<translation>
<language>ru-RU</language>
<approved>false</approved>
</translation>
<translation>
<language>tr-TR</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>probabilistic_lighting_help</name>
<description/>
<comment/>
<translations>
<translation>
<language>ar-LB</language>
<approved>false</approved>
</translation>
<translation>
<language>de-DE</language>
<approved>false</approved>
</translation>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-CL</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-FR</language>
<approved>false</approved>
</translation>
<translation>
<language>ru-RU</language>
<approved>false</approved>
</translation>
<translation>
<language>tr-TR</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>record</name> <name>record</name>
<description/> <description/>

View file

@ -194,6 +194,8 @@
"settings.pointer_lock_help": "Sperrt und versteckt den Mauszeiger.", "settings.pointer_lock_help": "Sperrt und versteckt den Mauszeiger.",
"settings.precise_lighting": "", "settings.precise_lighting": "",
"settings.precise_lighting_help": "", "settings.precise_lighting_help": "",
"settings.probabilistic_lighting": "",
"settings.probabilistic_lighting_help": "",
"settings.record": "Spielvideos aufnehmen", "settings.record": "Spielvideos aufnehmen",
"settings.record_download": "Video herunterladen ({{size}} MB)", "settings.record_download": "Video herunterladen ({{size}} MB)",
"settings.record_help": "Holen Sie sich ein Video von jedem Level.", "settings.record_help": "Holen Sie sich ein Video von jedem Level.",

View file

@ -194,6 +194,8 @@
"settings.pointer_lock_help": "Locks and hides the mouse cursor.", "settings.pointer_lock_help": "Locks and hides the mouse cursor.",
"settings.precise_lighting": "Precise lighting", "settings.precise_lighting": "Precise lighting",
"settings.precise_lighting_help": "Use a smaller grid for background light effect", "settings.precise_lighting_help": "Use a smaller grid for background light effect",
"settings.probabilistic_lighting": "Persistence of vision",
"settings.probabilistic_lighting_help": "Improve performance when there are more than 150 coins by reusing some of the light of the previous frame",
"settings.record": "Record gameplay videos", "settings.record": "Record gameplay videos",
"settings.record_download": "Download video ({{size}} MB)", "settings.record_download": "Download video ({{size}} MB)",
"settings.record_help": "Get a video of each level.", "settings.record_help": "Get a video of each level.",

View file

@ -194,6 +194,8 @@
"settings.pointer_lock_help": "Bloquea y oculta el cursor del mouse.", "settings.pointer_lock_help": "Bloquea y oculta el cursor del mouse.",
"settings.precise_lighting": "", "settings.precise_lighting": "",
"settings.precise_lighting_help": "", "settings.precise_lighting_help": "",
"settings.probabilistic_lighting": "",
"settings.probabilistic_lighting_help": "",
"settings.record": "Grabar vídeos de juego", "settings.record": "Grabar vídeos de juego",
"settings.record_download": "Descargar vídeo ({{size}} MB)", "settings.record_download": "Descargar vídeo ({{size}} MB)",
"settings.record_help": "Obtenga un vídeo de cada nivel.", "settings.record_help": "Obtenga un vídeo de cada nivel.",

View file

@ -194,6 +194,8 @@
"settings.pointer_lock_help": "Cache aussi le curseur de la souris.", "settings.pointer_lock_help": "Cache aussi le curseur de la souris.",
"settings.precise_lighting": "", "settings.precise_lighting": "",
"settings.precise_lighting_help": "", "settings.precise_lighting_help": "",
"settings.probabilistic_lighting": "",
"settings.probabilistic_lighting_help": "",
"settings.record": "Enregistrer des vidéos de jeu", "settings.record": "Enregistrer des vidéos de jeu",
"settings.record_download": "Télécharger la vidéo ({{size}} MB)", "settings.record_download": "Télécharger la vidéo ({{size}} MB)",
"settings.record_help": "Obtenez une vidéo de chaque niveau.", "settings.record_help": "Obtenez une vidéo de chaque niveau.",

View file

@ -194,6 +194,8 @@
"settings.pointer_lock_help": "Фиксирует и скрывает курсор мыши.", "settings.pointer_lock_help": "Фиксирует и скрывает курсор мыши.",
"settings.precise_lighting": "", "settings.precise_lighting": "",
"settings.precise_lighting_help": "", "settings.precise_lighting_help": "",
"settings.probabilistic_lighting": "",
"settings.probabilistic_lighting_help": "",
"settings.record": "Запись видеороликов игрового процесса", "settings.record": "Запись видеороликов игрового процесса",
"settings.record_download": "Скачать видео ({{size}} МБ)", "settings.record_download": "Скачать видео ({{size}} МБ)",
"settings.record_help": "Получите видеозапись каждого уровня.", "settings.record_help": "Получите видеозапись каждого уровня.",

View file

@ -194,6 +194,8 @@
"settings.pointer_lock_help": "Fare imlecini kilitler ve gizler.", "settings.pointer_lock_help": "Fare imlecini kilitler ve gizler.",
"settings.precise_lighting": "", "settings.precise_lighting": "",
"settings.precise_lighting_help": "", "settings.precise_lighting_help": "",
"settings.probabilistic_lighting": "",
"settings.probabilistic_lighting_help": "",
"settings.record": "Oyun videolarını kaydedin", "settings.record": "Oyun videolarını kaydedin",
"settings.record_download": "Videoyu indir ({{size}} MB)", "settings.record_download": "Videoyu indir ({{size}} MB)",
"settings.record_help": "Her seviyenin videosunu edinin.", "settings.record_help": "Her seviyenin videosunu edinin.",

View file

@ -40,6 +40,11 @@ export const options = {
name: t("settings.precise_lighting"), name: t("settings.precise_lighting"),
help: t("settings.precise_lighting_help"), help: t("settings.precise_lighting_help"),
}, },
probabilistic_lighting: {
default: false,
name: t("settings.probabilistic_lighting"),
help: t("settings.probabilistic_lighting_help"),
},
contrast: { contrast: {
default: false, default: false,
name: t("settings.contrast"), name: t("settings.contrast"),

View file

@ -55,7 +55,9 @@ export function getHaloScale() {
return 16 * (isOptionOn("precise_lighting") ? 1 : 2); return 16 * (isOptionOn("precise_lighting") ? 1 : 2);
} }
let framesCounter=0
export function render(gameState: GameState) { export function render(gameState: GameState) {
framesCounter++
startWork("render:init"); startWork("render:init");
const level = currentLevelInfo(gameState); const level = currentLevelInfo(gameState);
@ -109,11 +111,15 @@ export function render(gameState: GameState) {
""; "";
// Clear // Clear
if (!isOptionOn("basic") && level.svg && level.color === "#000000") { if (!isOptionOn("basic") && level.svg && level.color === "#000000") {
// TODO only if many coins on screen
const skipN = isOptionOn('probabilistic_lighting') && liveCount(gameState.coins)> 150? 3 : 0
const shouldSkip = index=> skipN ? (framesCounter + index) % (skipN+1) !==0 : false
const haloScale = getHaloScale(); const haloScale = getHaloScale();
startWork("render:halo:clear"); startWork("render:halo:clear");
haloCanvasCtx.globalCompositeOperation = "source-over"; haloCanvasCtx.globalCompositeOperation = "source-over";
haloCanvasCtx.globalAlpha = 0.99; haloCanvasCtx.globalAlpha = skipN ? 0.1:0.99
haloCanvasCtx.fillStyle = level.color; haloCanvasCtx.fillStyle = level.color;
haloCanvasCtx.fillRect(0, 0, width / haloScale, height / haloScale); haloCanvasCtx.fillRect(0, 0, width / haloScale, height / haloScale);
@ -122,7 +128,8 @@ export function render(gameState: GameState) {
haloCanvasCtx.globalAlpha = haloCanvasCtx.globalAlpha =
0.1 + (0.5 * 10) / (liveCount(gameState.coins) + 10); 0.1 + (0.5 * 10) / (liveCount(gameState.coins) + 10);
startWork("render:halo:coins"); startWork("render:halo:coins");
forEachLiveOne(gameState.coins, (coin) => { forEachLiveOne(gameState.coins, (coin,index) => {
if(shouldSkip(index)) return
const color = getCoinRenderColor(gameState, coin); const color = getCoinRenderColor(gameState, coin);
drawFuzzyBall( drawFuzzyBall(
haloCanvasCtx, haloCanvasCtx,
@ -134,7 +141,8 @@ export function render(gameState: GameState) {
}); });
startWork("render:halo:balls"); startWork("render:halo:balls");
gameState.balls.forEach((ball) => { gameState.balls.forEach((ball,index) => {
if(shouldSkip(index)) return
haloCanvasCtx.globalAlpha = 0.3 * (1 - ballTransparency(ball, gameState)); haloCanvasCtx.globalAlpha = 0.3 * (1 - ballTransparency(ball, gameState));
drawFuzzyBall( drawFuzzyBall(
haloCanvasCtx, haloCanvasCtx,
@ -149,6 +157,7 @@ export function render(gameState: GameState) {
haloCanvasCtx.globalAlpha = 0.05; haloCanvasCtx.globalAlpha = 0.05;
gameState.bricks.forEach((color, index) => { gameState.bricks.forEach((color, index) => {
if (!color) return; if (!color) return;
if(shouldSkip(index)) return
const x = brickCenterX(gameState, index), const x = brickCenterX(gameState, index),
y = brickCenterY(gameState, index); y = brickCenterY(gameState, index);
drawFuzzyBall( drawFuzzyBall(
@ -163,7 +172,8 @@ export function render(gameState: GameState) {
startWork("render:halo:particles"); startWork("render:halo:particles");
haloCanvasCtx.globalCompositeOperation = "screen"; haloCanvasCtx.globalCompositeOperation = "screen";
forEachLiveOne(gameState.particles, (flash) => { forEachLiveOne(gameState.particles, (flash,index) => {
if(shouldSkip(index)) return
const { x, y, time, color, size, duration } = flash; const { x, y, time, color, size, duration } = flash;
const elapsed = gameState.levelTime - time; const elapsed = gameState.levelTime - time;
haloCanvasCtx.globalAlpha = haloCanvasCtx.globalAlpha =
@ -567,12 +577,19 @@ export function render(gameState: GameState) {
) { ) {
ctx.imageSmoothingEnabled = isOptionOn("smooth_lighting") || false; ctx.imageSmoothingEnabled = isOptionOn("smooth_lighting") || false;
haloCanvasCtx.fillStyle = "#FFFFFF"; if(isOptionOn('probabilistic_lighting')) {
haloCanvasCtx.globalAlpha = 0.25; ctx.globalAlpha = 1;
haloCanvasCtx.globalCompositeOperation = "screen"; ctx.globalCompositeOperation = "soft-light";
haloCanvasCtx.fillRect(0, 0, haloCanvas.width, haloCanvas.height); }else{
ctx.globalAlpha = 1;
haloCanvasCtx.fillStyle = "#FFFFFF";
haloCanvasCtx.globalAlpha = 0.25;
haloCanvasCtx.globalCompositeOperation = "screen";
haloCanvasCtx.fillRect(0, 0, haloCanvas.width, haloCanvas.height);
ctx.globalAlpha = 1;
ctx.globalCompositeOperation = "overlay"; ctx.globalCompositeOperation = "overlay";
}
ctx.drawImage(haloCanvas, 0, 0, width, height); ctx.drawImage(haloCanvas, 0, 0, width, height);
ctx.imageSmoothingEnabled = false; ctx.imageSmoothingEnabled = false;
@ -604,13 +621,6 @@ export function render(gameState: GameState) {
); );
} }
// if(isOptionOn('mobile-mode')) {
// ctx.globalCompositeOperation = "source-over";
// ctx.globalAlpha = 0.5;
// ctx.fillStyle = 'black'
// ctx.fillRect(0,gameState.gameZoneHeight, gameState.canvasWidth, gameState.canvasHeight-gameState.gameZoneHeight)
// }
// ctx.globalAlpha=1
startWork("render:askForWakeLock"); startWork("render:askForWakeLock");
askForWakeLock(gameState); askForWakeLock(gameState);
@ -958,6 +968,7 @@ export function drawFuzzyBall(
x: number, x: number,
y: number, y: number,
) { ) {
width=Math.max(width,2)
const key = "fuzzy-circle" + color + "_" + width; const key = "fuzzy-circle" + color + "_" + width;
if (!color?.startsWith("#")) debugger; if (!color?.startsWith("#")) debugger;