Hendidura del lomo en las páginas y en la hoja que gira
En doble página va en el centro, en una página en el lado del lomo según el sentido de lectura y en una página ancha en su centro. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+37
-8
@@ -1481,6 +1481,12 @@ async function viewReader(mangaId, chapterId, startPage) {
|
||||
scheduleLeafTextures()
|
||||
}
|
||||
const imgReady = im => im.complete && im.naturalWidth > 0
|
||||
// Lado de la hendidura del lomo: l o r (borde de la página) o m (página doble, en el centro).
|
||||
const gutterOf = (i, n) => {
|
||||
if (wide.has(i)) return 'm'
|
||||
const rtl = settings.dir === 'rtl'
|
||||
return shown.length === 2 ? (rtl === (n === 0) ? 'l' : 'r') : rtl ? 'r' : 'l'
|
||||
}
|
||||
// Hacia una página que aún no ha llegado, la actual se queda (con un indicador tras un momento) hasta que
|
||||
// llegue o pasen 4 s, en vez de pasar la hoja y dejar negro debajo. Si se pide otra página mientras,
|
||||
// manda la última.
|
||||
@@ -1494,7 +1500,7 @@ async function viewReader(mangaId, chapterId, startPage) {
|
||||
const stage = document.createElement('div')
|
||||
stage.className = 'stage'
|
||||
stage.classList.toggle('two', shown.length === 2)
|
||||
stage.innerHTML = shown.map(i => `<img data-i="${i}" src="${pages[i]}" alt="" draggable="false">`).join('')
|
||||
stage.innerHTML = shown.map((i, n) => `<img data-i="${i}" data-gutter="${gutterOf(i, n)}" src="${pages[i]}" alt="" draggable="false">`).join('')
|
||||
const imgs = [...stage.querySelectorAll('img')]
|
||||
if ($('.stage', box) && dir && !wantDrag && !imgs.every(imgReady)) {
|
||||
waitTimer = setTimeout(() => box.classList.add('waiting'), 200)
|
||||
@@ -1534,6 +1540,7 @@ async function viewReader(mangaId, chapterId, startPage) {
|
||||
else { box.replaceChildren(stage) }
|
||||
stage.querySelectorAll('img').forEach(img => img.addEventListener('load', () => {
|
||||
const i = Number(img.dataset.i)
|
||||
if (isWide(img)) img.dataset.gutter = 'm'
|
||||
if (isWide(img) && !wide.has(i)) {
|
||||
wide.add(i)
|
||||
if (shown.length === 2 && shown.includes(i)) goTo(shown[0], false, true) // reagrupar
|
||||
@@ -1645,19 +1652,28 @@ async function viewReader(mangaId, chapterId, startPage) {
|
||||
gl.attachShader(prog, shader(gl.FRAGMENT_SHADER, `#version 300 es
|
||||
precision highp float;
|
||||
uniform sampler2D uFront, uBack;
|
||||
uniform bool uPaper;
|
||||
uniform bool uPaper, uSpineLeft, uSpread;
|
||||
in vec2 vUV;
|
||||
in float vC;
|
||||
out vec4 color;
|
||||
// La hendidura del lomo: los mismos puntos que data-gutter en style.css, para que no salte al empezar el giro.
|
||||
float gutter(float d) {
|
||||
if (d < 0.012) return mix(0.4, 0.6, d / 0.012);
|
||||
if (d < 0.03) return mix(0.6, 0.8, (d - 0.012) / 0.018);
|
||||
if (d < 0.06) return mix(0.8, 0.93, (d - 0.03) / 0.03);
|
||||
if (d < 0.1) return mix(0.93, 1.0, (d - 0.06) / 0.04);
|
||||
return 1.0;
|
||||
}
|
||||
void main() {
|
||||
vec4 t;
|
||||
float b;
|
||||
float fromSpine = uSpineLeft ? vUV.x : 1.0 - vUV.x;
|
||||
if (gl_FrontFacing) {
|
||||
t = texture(uFront, vUV, -0.5);
|
||||
b = 1.0 - (1.0 - vC) * 0.3;
|
||||
b = (1.0 - (1.0 - vC) * 0.3) * gutter(uSpread ? abs(vUV.x - 0.5) * 2.0 : fromSpine);
|
||||
} else {
|
||||
t = uPaper ? vec4(0.914, 0.898, 0.863, 1.0) : texture(uBack, vec2(1.0 - vUV.x, vUV.y), -0.5);
|
||||
b = 1.0 - (1.0 + vC) * 0.3;
|
||||
b = (1.0 - (1.0 + vC) * 0.3) * gutter(fromSpine);
|
||||
}
|
||||
color = vec4(t.rgb * b, t.a);
|
||||
}`))
|
||||
@@ -1743,7 +1759,7 @@ async function viewReader(mangaId, chapterId, startPage) {
|
||||
canvas.addEventListener('webglcontextlost', () => { if (leafGL?.gl === gl) { leafGL = null; leafTextures.clear() } })
|
||||
leafGL = { canvas, gl, prog, posBuf, uvBuf, aniso, shadowProg, shadowVao, shadowBuf, shadowCount: m, shadowData: new Float32Array(shadowSegs * 16 * 5),
|
||||
uSize: gl.getUniformLocation(shadowProg, 'uSize'), positions: new Float32Array(count * 4), uvs: new Float32Array(count * 2), indexCount: n,
|
||||
uView: gl.getUniformLocation(prog, 'uView'), uPaper: gl.getUniformLocation(prog, 'uPaper'), maxSize: gl.getParameter(gl.MAX_TEXTURE_SIZE) }
|
||||
uView: gl.getUniformLocation(prog, 'uView'), uPaper: gl.getUniformLocation(prog, 'uPaper'), uSpineLeft: gl.getUniformLocation(prog, 'uSpineLeft'), uSpread: gl.getUniformLocation(prog, 'uSpread'), maxSize: gl.getParameter(gl.MAX_TEXTURE_SIZE) }
|
||||
return leafGL
|
||||
}
|
||||
function leafTexture(im) {
|
||||
@@ -1817,6 +1833,8 @@ async function viewReader(mangaId, chapterId, startPage) {
|
||||
const scale = pw / W
|
||||
gl.scissor(Math.round(paper.l * scale), Math.round((H - paper.t - paper.h) * scale), Math.round(paper.w * scale), Math.round(paper.h * scale))
|
||||
gl.uniform1i(L.uPaper, back ? 0 : 1)
|
||||
gl.uniform1i(L.uSpineLeft, spineLeft ? 1 : 0)
|
||||
gl.uniform1i(L.uSpread, frontIm.dataset.gutter === 'm' ? 1 : 0)
|
||||
gl.activeTexture(gl.TEXTURE0)
|
||||
gl.bindTexture(gl.TEXTURE_2D, front)
|
||||
gl.activeTexture(gl.TEXTURE1)
|
||||
@@ -2033,10 +2051,15 @@ async function viewReader(mangaId, chapterId, startPage) {
|
||||
spineLeft = sign > 0
|
||||
const keep = document.createElement('img')
|
||||
keep.className = 'leafkeep'
|
||||
keep.dataset.gutter = stay.dataset.gutter
|
||||
keep.src = stay.src
|
||||
place(keep, rel(stay))
|
||||
box.append(keep)
|
||||
extra.push(keep)
|
||||
// Su hendidura es transparente: sin negro detrás, se vería la página nueva y la hendidura se aclararía.
|
||||
const keepBack = document.createElement('i')
|
||||
keepBack.className = 'leafkeepback'
|
||||
place(keepBack, rel(stay))
|
||||
box.append(keepBack, keep)
|
||||
extra.push(keepBack, keep)
|
||||
old.style.visibility = 'hidden' // la hoja y la copia ocupan su lugar
|
||||
} else {
|
||||
// Una página: el lomo está a la izquierda en izq→der y a la derecha en der→izq. Hacia delante, la
|
||||
@@ -2375,7 +2398,13 @@ async function viewReader(mangaId, chapterId, startPage) {
|
||||
render()
|
||||
})
|
||||
$('#fit').addEventListener('change', e => { settings.fit = e.target.value; savePrefs(); render() })
|
||||
$('#dir').addEventListener('change', e => { settings.dir = e.target.value; box.dataset.dir = settings.dir; syncDirUi(); savePrefs() })
|
||||
$('#dir').addEventListener('change', e => {
|
||||
settings.dir = e.target.value
|
||||
box.dataset.dir = settings.dir
|
||||
box.querySelectorAll('.stage img').forEach((im, n) => { im.dataset.gutter = gutterOf(Number(im.dataset.i), n) })
|
||||
syncDirUi()
|
||||
savePrefs()
|
||||
})
|
||||
$('#filter').addEventListener('change', e => { settings.filter = e.target.value; saveGlobal(); applyFilter() })
|
||||
$('#anim').value = settings.anim
|
||||
$('#anim').addEventListener('change', e => { settings.anim = e.target.value; saveGlobal() })
|
||||
|
||||
Reference in New Issue
Block a user