/* GLSpanner.java * * Copyright (c) 2003, Tuomas J. Lukka * * This file is part of Fenfire. * * Fenfire is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Fenfire is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General * Public License for more details. * * You should have received a copy of the GNU Lesser General * Public License along with Fenfire; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * */ /* * Written by Tuomas J. Lukka */ package org.fenfire.util; import java.util.*; import java.io.File; import java.io.IOException; import java.awt.Point; import java.awt.Dimension; import org.nongnu.libvob.memory.*; import org.nongnu.libvob.gl.*; import org.nongnu.libvob.util.ImageSize; import org.nongnu.alph.PageSpan; import org.nongnu.alph.impl.PageImageScroll; /** A static class for loading Image spans into OpenGL * textures. */ public class GLSpanner { public static boolean dbg = false; private static void pa(String s) { System.out.println(s); } static MipzipMemoryConsumer currentlyLoaded = null; static MemoryPartitioner pool; static { String mem_str = System.getProperty("GFX_MEM", "16"); int mem = Integer.parseInt(mem_str); if (mem < 0) throw new Error("Negative memory! "+ mem); if (dbg) pa("Spoolable memory allocated = "+mem); pool = new MemoryPartitioner(mem * 1024 * 1024); } /** Irrevocably stop using the memorypartitioner interface * for allocating textures. */ public static void dangerouslyOverrideMemoryPartitioner() { if(pool != null) { pool.stop(); pool = null; } } private static class SpanSB { PageImageScroll sb; SpanPage[] pages; SpanSB(PageImageScroll sb) { this.sb = sb; PageSpan sp = (PageSpan)sb.getCurrent(); pages = new SpanPage[sp.length()]; } SpanPage getPage(int i) { if(i < 0 || i >= pages.length) return null; if(pages[i] == null) { pages[i] = new SpanPage(sb, i); } return pages[i]; } } public static class SpanPage { /** The consumer inside which this page is loaded. */ private MipzipMemoryConsumer consumer; /** The width and height of the real page inside * the texture, in *TEXTURE* coordinates. */ public final float x1, y1; /** The width and height in pagespan units of the real page. */ public final int w, h; float getX(float spx) { return spx / (float)w * x1; } float getY(float spy) { return spy / (float)h * y1; } /** Cause the texture to be * requested. * @param importance 0..1, how much focus * this texture has. * @param pixels The maximum measure on screen * of the drawn area. */ public GL.Texture getTexture(float importance, float pixels) { if(pool == null) { if(currentlyLoaded != consumer) { if(currentlyLoaded != null) currentlyLoaded.loadToBaseLevelSynch(1000); currentlyLoaded = consumer; currentlyLoaded.loadToBaseLevelSynch(0); } } return consumer.getTexture(importance, pixels); } SpanPage(PageImageScroll sb, int page) { String file = sb.imageFilename(page); float resmult = sb.imageFileResolution(page) / sb.coordinateResolution() ; // Get the size of the orig. image Dimension d = ImageSize.readSize(new File(file)); if(d == null) { pa("Image cannot be loaded: "+file); throw new Error(); } w = (int)(d.width / resmult); h = (int)(d.height / resmult); MipzipLoader l; File f = new File(file + (GL.workaroundStupidBuggyAtiDrivers? ".mipzipBLAH" : ".mipzip")); try { l = new MipzipLoader(f); } catch(IOException e) { e.printStackTrace(); throw new Error("MipzipLoader threw '" + e + "' for " + f); } Dimension largest = l.getLevelSize(0); x1 = d.width / (float)largest.width; y1 = d.height / (float)largest.height; consumer = new MipzipMemoryConsumer(pool, l); } } public static class SpanRect { public final SpanPage page; /** The *TEXTURE* coordinates of this rectangle. */ public final float x0, y0, x1, y1; private float pixelmult; /** Cause the texture to be * requested. * @param importance 0..1, how much focus * this texture has. * @param pixels The maximum measure on screen * of the drawn area. */ public GL.Texture getTexture(float importance, float pixels) { GL.Texture tex = page.getTexture(importance, pixelmult * pixels); String er = GLUtil.checkMipmap(tex); if(er != null) { pa("MIPMAPS NOT CONSISTENT! "+er+" "+page); } return tex; } private SpanRect(SpanPage page, PageSpan sp) { this.page = page; Point p =sp.getLocation(); Dimension s =sp.getSize(); x0 = page.getX(p.x); y0 = page.getY(p.y); x1 = page.getX(p.x + s.width); y1 = page.getY(p.y + s.height); pixelmult = (float)Math.max( 1.0 / (.0001 + (x1 - x0)), 1.0 / (.0001 + (y1 - y0))); } } static Map span2rect = new WeakHashMap(); static Map sb2spansb = new WeakHashMap(); /** Get the texrect for a given pagespan. * This method will return immediately, either * with the texrect for the right texrect or with null, * if no texture is currently obtainable. * @param sp The span * @param importance The importance of the request, to be given to MemoryPartitioner. * 1 = at focus, 0 = very peripheral * @param pixScale The number of pixels per imagespan unit: the resolution needed. */ public static SpanRect getSpanRect(PageSpan sp) { SpanRect r = (SpanRect)span2rect.get(sp); if(r == null) { PageImageScroll sb = (PageImageScroll)sp.getScrollBlock(); SpanSB ssb = (SpanSB)sb2spansb.get(sb); if(ssb == null) { ssb = new SpanSB(sb); sb2spansb.put(sb, ssb); } SpanPage p = ssb.getPage(sp.offset()); r = new SpanRect(p, sp); span2rect.put(sp, r); } return r; } public static void clearCache() { span2rect = new WeakHashMap(); sb2spansb = new WeakHashMap(); } }