// (c) Tuomas J. Lukka package org.fenfire.view; import java.awt.Point; import java.awt.Dimension; import org.fenfire.util.*; import org.nongnu.libvob.*; import org.nongnu.libvob.gl.*; import org.nongnu.alph.*; /** A single pagespan enfilade laid out on the plane. */ public class PageSpanLayout { public static boolean dbg = false; private void pa(String s) { System.out.println(s); } public static final float scale = 72 * 6; public static float dicefactor = .5f; public interface PageSpanPaperMaker { PageSpanPaper getPaper(GLSpanner.SpanPage p, PageSpan sp); } public static class DefaultPageSpanPaperMaker implements PageSpanPaperMaker { public PageSpanPaper getPaper(GLSpanner.SpanPage p, PageSpan sp) { return new PageSpanPaper(p, sp.getScrollBlock().hashCode()); } } static public final DefaultPageSpanPaperMaker defaultPageSpanPaperMaker = new DefaultPageSpanPaperMaker(); public boolean useBg = true; public boolean useText = true; private int npages; private PageSpan[] pages; private PageSpanPaper[] psps; private float[] xywh; public float w; // XXX Kludge to be public public float h; /** Allocate the structure to hold a given number of pages. */ private void alloc(int size) { npages = size; pages = new PageSpan[npages]; psps = new PageSpanPaper[npages]; xywh = new float[npages * 4]; // x, y, w, h in PAPER coordinates w = 0; h = 0; } /** (To be called with increasing p): add a page. */ private void page(int p, PageSpan sp, PageSpanPaperMaker pageSpanPaperMaker) { pages[p] = sp; GLSpanner.SpanRect rect = GLSpanner.getSpanRect(pages[p]); psps[p] = pageSpanPaperMaker.getPaper(rect.page, sp); Point l_p = pages[p].getLocation(); Dimension d_p = pages[p].getSize(); xywh[4*p + 0] = psps[p].getX(l_p.x); xywh[4*p + 1] = psps[p].getY(l_p.y); xywh[4*p + 2] = psps[p].getX(d_p.width); xywh[4*p + 3] = psps[p].getY(d_p.height); if(dbg) pa("Page "+p+" "+ xywh[4*p+0]+" "+ xywh[4*p+1]+" "+ xywh[4*p+2]+" "+ xywh[4*p+3]+" "+ pages[p]); w += scale * xywh[4*p + 2]; if(h < scale * xywh[4*p + 3]) h = scale * xywh[4*p + 3]; } public PageSpanLayout(Enfilade1D enf) { this(enf, defaultPageSpanPaperMaker); } public PageSpanLayout(Enfilade1D enf, PageSpanPaperMaker maker) { alloc(enf.length()); for(int p = 0; p < npages; p++) { // XXX INEFFICIENT! page(p, (PageSpan)enf.sub(p, p+1).getList().get(0), maker); } } public PageSpanLayout(PageSpan sp) { this(sp, defaultPageSpanPaperMaker); } public PageSpanLayout(PageSpan sp, PageSpanPaperMaker maker) { alloc(sp.length()); for(int p = 0; p < npages; p++) { page(p, (PageSpan)sp.subSpan(p, p+1), maker); } } /** Get the extents (in the output coordinates) * of a given page span. * Currently, only the first intersecting page * is used, but this may change. */ public float[] getExtents(PageSpan s, float[] xywh_out) { if(xywh_out == null) xywh_out = new float[4]; float curw = 0; for(int p = 0; p < npages; p++) { if(s.intersects(pages[p])) { Point l_c = s.getLocation(); Dimension d_c = s.getSize(); xywh_out[0] = curw + scale * psps[p].getX(l_c.x); xywh_out[2] = scale * psps[p].getX(d_c.width); xywh_out[1] = scale * ( psps[p].getX(l_c.x) - xywh[4*p + 1]); xywh_out[3] = scale * psps[p].getX(d_c.height); if(dbg) pa("Center found: "+p+" "+pages[p]+" "+ xywh_out[0] + " " + xywh_out[1] + " " + xywh_out[2] + " " + xywh_out[3] + " " ); return xywh_out; } curw += scale * xywh[4*p + 2]; } return null; } public void place(VobScene vs, int into, float importance, float pixelscale) { place(vs, into, importance, pixelscale, -1); } /** Place this layout into the given coordinate system. * Note that the layout is not affected by the * box size of the coordinate system. * @param cullCS The coordinate system against which * all objects should be culled. */ public void place(VobScene vs, int into, float importance, float pixelscale, int cullCS) { float curx = 0; // Now we can draw the pages. for(int p = 0; p < npages; p++) { // We want a coordinate system // whose box is exactly the span int around = vs.orthoBoxCS(into, pages[p], 0, curx, 0, scale, scale, xywh[4*p+2], xywh[4*p+3]); if(cullCS >= 0) around = vs.cullCS(around, "CULL", cullCS); // and then translate to the whole page. int tr = vs.translateCS(around, "T", -xywh[4*p+0], -xywh[4*p+1]); curx += scale * xywh[4*p + 2]; psps[p].request(importance, scale * pixelscale); vs.map.put(GLRen.createPaperQuad(psps[p].getPaper(useBg, useText), xywh[4*p + 0], xywh[4*p + 1], xywh[4*p + 0]+xywh[4*p + 2], xywh[4*p + 1]+xywh[4*p + 3], 1, dicefactor, 0), tr, 0); } } /** Place this layout strictly fitted into the given * box. * Note that this won't interpolate nicely to * "place". */ public void placeBoxed(VobScene vs, int into, float importance, float pixelscale) { int unit = vs.unitSqCS(into, "PSPCV.UNIT"); int scaled = vs.scaleCS(unit, "PSPCV.SCALED", 1.0f / w, 1.0f / h); place(vs, scaled, importance, pixelscale); } /** Make a request for loading the textures into memory. */ public void request(float x, float y, float radius, float importanceAt, float importanceOutside, float pixelscale) { if(dbg) pa("Request: "+x+" "+y+" "+radius); float curx = 0; for(int p = 0; p < npages; p++) { float dx = Math.abs((curx + .5f * scale * xywh[4*p+2]) - x) - .5f*scale * xywh[4*p+2]; float dy = Math.abs((.5f * scale * xywh[4*p+3]) - y) - .5f*scale * xywh[4*p+3]; if(dbg) pa("RequestCoords: "+xywh[4*p+0]+" "+xywh[4*p+1]+" "+ xywh[4*p+2]+" "+xywh[4*p+3]); float dist = Math.max(dx, dy); if(dist < 0) { psps[p].request(importanceAt, pixelscale); } else if(dist < radius) { if(dbg) pa("Request DO: "+dx+" "+dy); psps[p].request(importanceOutside * (1-dist/radius), pixelscale); } curx += scale * xywh[4*p + 2]; } } }