Skip to content

Commit d24e5c8

Browse files
Add image and handle calculations on the fly
1 parent 0a24ac1 commit d24e5c8

6 files changed

Lines changed: 193 additions & 66 deletions

File tree

images/tree.jpg

4.17 MB
Loading

public/app.js

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
const MAX_DIM = 1200;
21
// Maximum tiles the WASM module will store (matches _MAX_TUILES in hexagonify_wasm.ml).
32
const MAX_TUILES_WASM = 2000;
43

@@ -46,6 +45,8 @@ const EXPORTS_CODES_METHODES = {
4645
hex_tronque: "methode_hex_tronque",
4746
};
4847

48+
const METHODES_WASM_REPLI = ["hex", "square"];
49+
4950
let wasm = null;
5051
let loadedImage = null;
5152
let renderToken = 0;
@@ -249,13 +250,6 @@ function couleurContourCss() {
249250
return `rgba(${r},${g},${b},${(state.outlineOpacity / 100).toFixed(3)})`;
250251
}
251252

252-
function dimensionsScalees(imgEl) {
253-
let w = imgEl.naturalWidth, h = imgEl.naturalHeight;
254-
if (w > MAX_DIM) { h = Math.round(h * MAX_DIM / w); w = MAX_DIM; }
255-
if (h > MAX_DIM) { w = Math.round(w * MAX_DIM / h); h = MAX_DIM; }
256-
return [w, h];
257-
}
258-
259253
function lireSommetsTuile(ti) {
260254
const n = Number(wasm.tuile_n_sommets(ti));
261255
if (!Number.isInteger(n) || n < 3 || n > 64) return null;
@@ -286,9 +280,31 @@ function entierSecurise(valeur, secours, minimum = null, maximum = null) {
286280
return n;
287281
}
288282

283+
function genererTuilesAvecRepli(w, h, cote, methodeDemandee) {
284+
const essais = [methodeDemandee, ...METHODES_WASM_REPLI.filter((nom) => nom !== methodeDemandee)];
285+
let derniereErreur = null;
286+
287+
for (const nom of essais) {
288+
const code = entierSecurise(METHODES[nom], METHODES.hex, 0);
289+
try {
290+
const nTuiles = Number(wasm.generer_tuiles(w, h, cote, code));
291+
if (!Number.isInteger(nTuiles) || nTuiles < 0) {
292+
throw new Error(`Nombre de tuiles invalide renvoye par WASM: ${nTuiles}`);
293+
}
294+
return { nTuiles, methodeUtilisee: nom, methodeDemandee };
295+
} catch (err) {
296+
derniereErreur = err;
297+
console.warn(`[pixel2polygon] Mode ${nom} indisponible dans le WASM :`, err);
298+
}
299+
}
300+
301+
throw derniereErreur ?? new Error("Aucune methode de rendu WASM disponible.");
302+
}
303+
289304
function afficherSource(imgEl) {
290305
const srcCanvas = document.getElementById("source-canvas");
291-
const [w, h] = dimensionsScalees(imgEl);
306+
const w = imgEl.naturalWidth;
307+
const h = imgEl.naturalHeight;
292308
srcCanvas.width = w;
293309
srcCanvas.height = h;
294310
srcCanvas.getContext("2d").drawImage(imgEl, 0, 0, w, h);
@@ -318,12 +334,11 @@ async function rendreSortie() {
318334
ctx.fillStyle = `rgb(${bgCouleur[0]},${bgCouleur[1]},${bgCouleur[2]})`;
319335
ctx.fillRect(0, 0, w, h);
320336

321-
const code = entierSecurise(METHODES[state.method], METHODES.hex, 0);
322337
let cote = entierSecurise(state.side, 30, 1);
323338
const coteDemande = cote;
324339
const coteMin = coteSuretePourImage(w, h, state.method);
325340
if (cote < coteMin) cote = coteMin;
326-
const nTuiles = Number(wasm.generer_tuiles(w, h, cote, code));
341+
const { nTuiles, methodeUtilisee } = genererTuilesAvecRepli(w, h, cote, state.method);
327342
if (cote !== coteDemande) {
328343
status.textContent = `Taille ajustee a ${cote}px (limite du mode ${state.method}).`;
329344
}
@@ -334,9 +349,6 @@ async function rendreSortie() {
334349
const tileSizeDisp = document.getElementById("tile-size-display");
335350
if (tileSizeDisp) tileSizeDisp.textContent = String(cote);
336351
}
337-
if (!Number.isInteger(nTuiles) || nTuiles < 0) {
338-
throw new Error(`Nombre de tuiles invalide renvoye par WASM: ${nTuiles}`);
339-
}
340352
const indices = Array.from({ length: nTuiles }, (_, i) => i);
341353
indices.sort((a, b) => lireNombreSommetsTuile(a) - lireNombreSommetsTuile(b));
342354

@@ -359,9 +371,12 @@ async function rendreSortie() {
359371
if (couleur) dessinerTuile(ctx, sommets, couleur, state.outlineWidth, cssContour);
360372
}
361373

374+
const libelleMode = methodeUtilisee === state.method
375+
? `mode ${state.method}`
376+
: `mode ${state.method} (repli WASM vers ${methodeUtilisee})`;
362377
status.textContent = tuilesInvalides > 0
363-
? `Rendu termine : ${nTuiles - tuilesInvalides}/${nTuiles} tuiles valides pour le mode ${state.method}.`
364-
: `Rendu termine : ${nTuiles} tuiles pour le mode ${state.method}.`;
378+
? `Rendu termine : ${nTuiles - tuilesInvalides}/${nTuiles} tuiles valides pour le ${libelleMode}.`
379+
: `Rendu termine : ${nTuiles} tuiles pour le ${libelleMode}.`;
365380
btnDl.disabled = false;
366381
} catch (err) {
367382
console.error("[pixel2polygon] Echec du rendu :", err);

public/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ <h4>Compilation</h4>
268268

269269
</main>
270270

271-
<script type="module" src="app.js?v=2026-03-31-4"></script>
271+
<script type="module" src="app.js?v=2026-04-01-1"></script>
272272
</body>
273273

274274
</html>

scripts/compile_wasm.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
importer io
22
importer importlib
33
importer os
4+
importer re
45
importer shutil
56
importer sys
67
depuis pathlib importer Path
@@ -55,7 +56,7 @@ déf generer_wat_et_wasm(source):
5556
soit wasmtime = importlib.import_module("wasmtime")
5657
soit programme = charger_programme(source)
5758
soit texte_wat = WATCodeGenerator().generate(programme)
58-
texte_wat = texte_wat.replace('(memory (export "memory") 4)', '(memory (export "memory") 16)')
59+
texte_wat = re.sub(r'\(memory \(export "memory"\) \d+\)', '(memory (export "memory") 4096)', texte_wat, count=1)
5960
soit octets_wasm = wasmtime.wat2wasm(texte_wat)
6061
retour [texte_wat, octets_wasm]
6162

src/hexagonify_wasm.ml

Lines changed: 112 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@ _vus_n = []
246246
_vus_cx = []
247247
_vus_cy = []
248248
_methode_active = 0
249+
_gen_larg = 0.0
250+
_gen_haut = 0.0
251+
_gen_a = 0.0
249252

250253

251254
déf _coord_vers_entier(valeur):
@@ -273,6 +276,73 @@ déf _hors_champ(min_x, max_x, min_y, max_y, larg, haut):
273276
retour 0
274277

275278

279+
déf _hex_visible(x, y, larg, haut, a):
280+
soit demi_larg = espacement_horiz(a) / 2.0
281+
soit min_x = x - demi_larg
282+
soit max_x = x + demi_larg
283+
soit min_y = y - a
284+
soit max_y = y + a
285+
retour 1 - _hors_champ(min_x, max_x, min_y, max_y, larg, haut)
286+
287+
288+
déf _compter_hex_visibles(larg, haut, a):
289+
soit hs = espacement_horiz(a)
290+
soit vs = espacement_vert(a)
291+
soit rangs = _nb_pas_inclusifs(-2.0 * a, haut + 2.0 * a, vs)
292+
soit cols = _nb_pas_inclusifs(-hs, larg + hs, hs)
293+
soit total = 0
294+
pour rang dans range(rangs):
295+
soit y = -2.0 * a + rang * vs
296+
soit decal = (rang % 2) * (hs / 2.0)
297+
pour col dans range(cols):
298+
soit x = -hs + decal + col * hs
299+
si _hex_visible(x, y, larg, haut, a) == 1:
300+
total = total + 1
301+
retour total
302+
303+
304+
déf _hex_centre_x_par_index(index, larg, haut, a):
305+
soit hs = espacement_horiz(a)
306+
soit vs = espacement_vert(a)
307+
soit rangs = _nb_pas_inclusifs(-2.0 * a, haut + 2.0 * a, vs)
308+
soit cols = _nb_pas_inclusifs(-hs, larg + hs, hs)
309+
soit courant = 0
310+
pour rang dans range(rangs):
311+
soit y = -2.0 * a + rang * vs
312+
soit decal = (rang % 2) * (hs / 2.0)
313+
pour col dans range(cols):
314+
soit x = -hs + decal + col * hs
315+
si _hex_visible(x, y, larg, haut, a) == 1:
316+
si courant == index:
317+
retour x
318+
courant = courant + 1
319+
retour 0.0
320+
321+
322+
déf _hex_centre_y_par_index(index, larg, haut, a):
323+
soit hs = espacement_horiz(a)
324+
soit vs = espacement_vert(a)
325+
soit rangs = _nb_pas_inclusifs(-2.0 * a, haut + 2.0 * a, vs)
326+
soit cols = _nb_pas_inclusifs(-hs, larg + hs, hs)
327+
soit courant = 0
328+
pour rang dans range(rangs):
329+
soit y = -2.0 * a + rang * vs
330+
soit decal = (rang % 2) * (hs / 2.0)
331+
pour col dans range(cols):
332+
soit x = -hs + decal + col * hs
333+
si _hex_visible(x, y, larg, haut, a) == 1:
334+
si courant == index:
335+
retour y
336+
courant = courant + 1
337+
retour 0.0
338+
339+
340+
déf _compter_carres(larg, haut, a):
341+
soit cols = entier(math.ceil(larg / a))
342+
soit rangs = entier(math.ceil(haut / a))
343+
retour cols * rangs
344+
345+
276346
déf _ajouter_tuile_4(x0, y0, x1, y1, x2, y2, x3, y3, larg, haut):
277347
soit min_x = min(min(x0, x1), min(x2, x3))
278348
soit max_x = max(max(x0, x1), max(x2, x3))
@@ -366,42 +436,11 @@ déf _nb_pas_inclusifs(debut, fin, pas):
366436
# ── Generateurs de tuiles ─────────────────────────────────────
367437

368438
déf _gen_hex(larg, haut, a):
369-
hs = espacement_horiz(a)
370-
vs = espacement_vert(a)
371-
rangs = _nb_pas_inclusifs(-2.0 * a, haut + 2.0 * a, vs)
372-
cols = _nb_pas_inclusifs(-hs, larg + hs, hs)
373-
pour rang dans range(rangs):
374-
y = -2.0 * a + rang * vs
375-
decal = (rang % 2) * (hs / 2.0)
376-
pour col dans range(cols):
377-
x = -hs + decal + col * hs
378-
soit x0 = sommet_hex_x(x, y, a, 0)
379-
soit y0 = sommet_hex_y(x, y, a, 0)
380-
soit x1 = sommet_hex_x(x, y, a, 1)
381-
soit y1 = sommet_hex_y(x, y, a, 1)
382-
soit x2 = sommet_hex_x(x, y, a, 2)
383-
soit y2 = sommet_hex_y(x, y, a, 2)
384-
soit x3 = sommet_hex_x(x, y, a, 3)
385-
soit y3 = sommet_hex_y(x, y, a, 3)
386-
soit x4 = sommet_hex_x(x, y, a, 4)
387-
soit y4 = sommet_hex_y(x, y, a, 4)
388-
soit x5 = sommet_hex_x(x, y, a, 5)
389-
soit y5 = sommet_hex_y(x, y, a, 5)
390-
_ajouter_tuile_6(x0, y0, x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, larg, haut)
391-
retour 0
439+
retour _compter_hex_visibles(larg, haut, a)
392440

393441

394442
déf _gen_carre(larg, haut, a):
395-
cols = entier(math.ceil(larg / a))
396-
rangs = entier(math.ceil(haut / a))
397-
pour col dans range(cols):
398-
x = col * a
399-
pour rang dans range(rangs):
400-
y = rang * a
401-
x2 = min(larg, x + a)
402-
y2 = min(haut, y + a)
403-
_ajouter_tuile_4(x, y, x2, y, x2, y2, x, y2, larg, haut)
404-
retour 0
443+
retour _compter_carres(larg, haut, a)
405444

406445

407446
déf _gen_triangle(larg, haut, a):
@@ -652,18 +691,21 @@ déf _gen_hex_tronque(larg, haut, a):
652691
# ── Dispatch et acces aux tuiles ──────────────────────────────
653692

654693
déf generer_tuiles(larg, haut, a, methode):
655-
global _methode_active
694+
global _methode_active, _gen_larg, _gen_haut, _gen_a
656695
_tuiles_reinit()
657696
si larg != larg ou haut != haut ou a != a ou methode != methode:
658697
retour 0
659698
si a <= 0:
660699
retour 0
661700
m = entier(methode)
662701
_methode_active = m
702+
_gen_larg = larg
703+
_gen_haut = haut
704+
_gen_a = a
663705
si m == 0:
664-
_gen_hex(larg, haut, a)
706+
retour _gen_hex(larg, haut, a)
665707
si m == 1:
666-
_gen_carre(larg, haut, a)
708+
retour _gen_carre(larg, haut, a)
667709
si m == 2:
668710
_gen_triangle(larg, haut, a)
669711
si m == 3:
@@ -697,12 +739,44 @@ déf tuile_n_sommets(i):
697739

698740

699741
déf tuile_sommet_x(i, j):
700-
global _tuiles_xs, _tuiles_off
742+
global _tuiles_xs, _tuiles_off, _methode_active, _gen_larg, _gen_haut, _gen_a
743+
si _methode_active == 0:
744+
soit cx = _hex_centre_x_par_index(entier(i), _gen_larg, _gen_haut, _gen_a)
745+
soit cy = _hex_centre_y_par_index(entier(i), _gen_larg, _gen_haut, _gen_a)
746+
retour sommet_hex_x(cx, cy, _gen_a, entier(j))
747+
si _methode_active == 1:
748+
soit cols = entier(math.ceil(_gen_larg / _gen_a))
749+
soit col = entier(i) % cols
750+
soit x = col * _gen_a
751+
soit x2 = min(_gen_larg, x + _gen_a)
752+
si entier(j) == 0:
753+
retour x
754+
si entier(j) == 1:
755+
retour x2
756+
si entier(j) == 2:
757+
retour x2
758+
retour x
701759
retour _tuiles_xs[entier(_tuiles_off[entier(i)]) + entier(j)] / 100.0
702760

703761

704762
déf tuile_sommet_y(i, j):
705-
global _tuiles_ys, _tuiles_off
763+
global _tuiles_ys, _tuiles_off, _methode_active, _gen_larg, _gen_haut, _gen_a
764+
si _methode_active == 0:
765+
soit cx = _hex_centre_x_par_index(entier(i), _gen_larg, _gen_haut, _gen_a)
766+
soit cy = _hex_centre_y_par_index(entier(i), _gen_larg, _gen_haut, _gen_a)
767+
retour sommet_hex_y(cx, cy, _gen_a, entier(j))
768+
si _methode_active == 1:
769+
soit cols = entier(math.ceil(_gen_larg / _gen_a))
770+
soit rang = entier(i) // cols
771+
soit y = rang * _gen_a
772+
soit y2 = min(_gen_haut, y + _gen_a)
773+
si entier(j) == 0:
774+
retour y
775+
si entier(j) == 1:
776+
retour y
777+
si entier(j) == 2:
778+
retour y2
779+
retour y2
706780
retour _tuiles_ys[entier(_tuiles_off[entier(i)]) + entier(j)] / 100.0
707781

708782

0 commit comments

Comments
 (0)