3 |
* |
* |
4 |
* Copyright (c) 2003, : Tuomas J. Lukka |
* Copyright (c) 2003, : Tuomas J. Lukka |
5 |
* |
* |
6 |
* This file is part of Gzz. |
* This file is part of Libvob. |
7 |
* |
* |
8 |
* Gzz is free software; you can redistribute it and/or modify it under |
* Libvob is free software; you can redistribute it and/or modify it under |
9 |
* the terms of the GNU Lesser General Public License as published by |
* the terms of the GNU Lesser General Public License as published by |
10 |
* the Free Software Foundation; either version 2 of the License, or |
* the Free Software Foundation; either version 2 of the License, or |
11 |
* (at your option) any later version. |
* (at your option) any later version. |
12 |
* |
* |
13 |
* Gzz is distributed in the hope that it will be useful, but WITHOUT |
* Libvob is distributed in the hope that it will be useful, but WITHOUT |
14 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
15 |
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General |
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General |
16 |
* Public License for more details. |
* Public License for more details. |
17 |
* |
* |
18 |
* You should have received a copy of the GNU Lesser General |
* You should have received a copy of the GNU Lesser General |
19 |
* Public License along with Gzz; if not, write to the Free |
* Public License along with Libvob; if not, write to the Free |
20 |
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
21 |
* MA 02111-1307 USA |
* MA 02111-1307 USA |
22 |
* |
* |
45 |
public static boolean dbg = false; |
public static boolean dbg = false; |
46 |
final static void pa(String s) { System.out.println(s); } |
final static void pa(String s) { System.out.println(s); } |
47 |
|
|
|
/** I have a hunch that zlib might not be re-entrant |
|
|
* and that that would be causing our problems, |
|
|
* since loading a level synchronously |
|
|
* at the beginning mixed everything. |
|
|
*/ |
|
|
private static Object zlibLock = new Object(); |
|
|
|
|
48 |
private int goalBaseLevel = -15; |
private int goalBaseLevel = -15; |
49 |
private int currentBaseLevel = 1000; |
private int currentBaseLevel = 1000; |
50 |
|
|
58 |
private Background bg = null; |
private Background bg = null; |
59 |
private float priority = 0; |
private float priority = 0; |
60 |
|
|
61 |
/** The file in which the mipmaps are stored. |
private final MipzipFile mipzipFile; |
62 |
*/ |
|
63 |
private final File mipzipFile; |
public MipzipFile getMipzipFile() { |
64 |
|
return mipzipFile; |
65 |
|
} |
66 |
|
|
67 |
/** The texture. |
/** The texture. |
68 |
*/ |
*/ |
69 |
private final GL.Texture tex; |
private final GL.Texture tex; |
70 |
|
|
|
/** The compressed format. |
|
|
*/ |
|
|
private final String texFormat; |
|
|
private final boolean compressedFormat; |
|
71 |
|
|
72 |
private int bitsPerTexel; |
private int bitsPerTexel; |
73 |
|
|
|
/** The opened Zip file. At any given |
|
|
* time, may be null or open. |
|
|
* Use getZipFile() to get it inside these classes. |
|
|
*/ |
|
|
private ZipFile zip; |
|
|
|
|
74 |
private final Level[] levels; |
private final Level[] levels; |
75 |
|
|
|
/** The size of the original image embedded in the mipzip file, in texture coordinates. |
|
|
*/ |
|
|
public final float origWidth, origHeight; |
|
76 |
|
|
77 |
private String filterSettings; |
private String filterSettings; |
78 |
|
|
84 |
reFilter(); |
reFilter(); |
85 |
} |
} |
86 |
|
|
|
/** Open (if not already open) and return the ZipFile. |
|
|
*/ |
|
|
synchronized private ZipFile getZipFile() throws IOException { |
|
|
if(zip == null) |
|
|
zip = new ZipFile(mipzipFile); |
|
|
return zip; |
|
|
} |
|
|
|
|
|
synchronized private byte[] readEntry(String name) throws IOException { |
|
|
synchronized(zlibLock) { |
|
|
ZipFile f = getZipFile(); |
|
|
ZipEntry e = f.getEntry(name); |
|
|
byte[] loadedData = new byte[(int)e.getSize()]; |
|
|
InputStream i = f.getInputStream(e); |
|
|
int offs = 0; |
|
|
while(offs < loadedData.length) { |
|
|
int res = i.read(loadedData, offs, loadedData.length - offs); |
|
|
if(res < 0) throw new IOException("EOF"); |
|
|
offs += res; |
|
|
} |
|
|
i.close(); |
|
|
f.close(); zip = null; |
|
|
return loadedData; |
|
|
} |
|
|
} |
|
|
|
|
87 |
private static final int STATE_NONE = 1, |
private static final int STATE_NONE = 1, |
88 |
STATE_DATALOADED = 2, |
STATE_DATALOADED = 2, |
89 |
STATE_INTEXTURE = 3; |
STATE_INTEXTURE = 3; |
102 |
*/ |
*/ |
103 |
int level; |
int level; |
104 |
|
|
|
/** Sizes of the mipmap levels. |
|
|
*/ |
|
|
Dimension size; |
|
|
|
|
105 |
/** The data loaded from the disk. |
/** The data loaded from the disk. |
106 |
*/ |
*/ |
107 |
byte[] loadedData; |
byte[] loadedData; |
118 |
" "+state); |
" "+state); |
119 |
if(state != STATE_NONE) return; |
if(state != STATE_NONE) return; |
120 |
if(loadedData == null) |
if(loadedData == null) |
121 |
loadedData = readEntry(""+level); |
loadedData = mipzipFile.getLevelData(level); |
122 |
state = STATE_DATALOADED; |
state = STATE_DATALOADED; |
123 |
} |
} |
124 |
|
|
132 |
pa("TexImage "+MipzipLoader.this+" "+level+ |
pa("TexImage "+MipzipLoader.this+" "+level+ |
133 |
" "+state); |
" "+state); |
134 |
if(state != STATE_DATALOADED) return; |
if(state != STATE_DATALOADED) return; |
135 |
if(compressedFormat) |
Dimension size = mipzipFile.getLevelSize(level); |
136 |
tex.compressedTexImage(level, texFormat, |
if(mipzipFile.getIsCompressedFormat()) |
137 |
|
tex.compressedTexImage(level, mipzipFile.getTexFormat(), |
138 |
size.width, size.height, 0, |
size.width, size.height, 0, |
139 |
loadedData); |
loadedData); |
140 |
else |
else |
141 |
tex.texImage2D(level, "RGB", size.width, size.height, |
tex.texImage2D(level, "RGB", size.width, size.height, |
142 |
0, texFormat, "BYTE", loadedData); |
0, mipzipFile.getTexFormat(), "BYTE", loadedData); |
143 |
|
|
144 |
state = STATE_INTEXTURE; |
state = STATE_INTEXTURE; |
145 |
loadedData = null; |
loadedData = null; |
182 |
|
|
183 |
/** Create a level. |
/** Create a level. |
184 |
* @param l The mipmap level index |
* @param l The mipmap level index |
|
* @param s The size string from the comment in the file, e.g."64x128" |
|
185 |
*/ |
*/ |
186 |
Level(int l, String s) throws IOException { |
Level(int l) throws IOException { |
187 |
this.level = l; |
this.level = l; |
|
int i = s.indexOf('x'); |
|
|
if(i < 0) throw new IOException("Invalid size string"); |
|
|
int w = Integer.parseInt(s.substring(0,i)); |
|
|
int h = Integer.parseInt(s.substring(i+1)); |
|
|
size = new Dimension(w, h); |
|
188 |
} |
} |
189 |
|
|
190 |
} |
} |
376 |
public int getMemory(int level) { |
public int getMemory(int level) { |
377 |
if(level < 0) level = 0; |
if(level < 0) level = 0; |
378 |
if(level > levels.length-1) level = levels.length-1; |
if(level > levels.length-1) level = levels.length-1; |
379 |
int bytesForLevel = levels[level].size.width * levels[level].size.height * bitsPerTexel / 8; |
Dimension size = mipzipFile.getLevelSize(level); |
380 |
|
int bytesForLevel = size.width * size.height * bitsPerTexel / 8; |
381 |
int totalBytes = (bytesForLevel * 4) / 3; |
int totalBytes = (bytesForLevel * 4) / 3; |
382 |
return totalBytes; |
return totalBytes; |
383 |
} |
} |
401 |
* shown in 100x100 square (or like). |
* shown in 100x100 square (or like). |
402 |
*/ |
*/ |
403 |
public int getLevelForQuality(float quality) { |
public int getLevelForQuality(float quality) { |
404 |
int maxdim = Math.max(levels[0].size.height, levels[0].size.width); |
Dimension size = mipzipFile.getLevelSize(0); |
405 |
|
int maxdim = Math.max(size.height, size.width); |
406 |
float ratio = maxdim / quality; |
float ratio = maxdim / quality; |
407 |
int l = (int)(Math.log(ratio) / LG2); |
int l = (int)(Math.log(ratio) / LG2); |
408 |
int lc = Math.max(0, l); |
int lc = Math.max(0, l); |
418 |
} |
} |
419 |
|
|
420 |
public float getQuality(int level) { |
public float getQuality(int level) { |
421 |
int maxdim = Math.max(levels[level].size.height, |
Dimension size = mipzipFile.getLevelSize(level); |
422 |
levels[level].size.width); |
int maxdim = Math.max(size.height, |
423 |
|
size.width); |
424 |
return maxdim; |
return maxdim; |
425 |
} |
} |
426 |
|
|
434 |
* The return value must not be altered! |
* The return value must not be altered! |
435 |
*/ |
*/ |
436 |
public Dimension getLevelSize(int level) { |
public Dimension getLevelSize(int level) { |
437 |
return levels[level].size; |
return mipzipFile.getLevelSize(level); |
438 |
} |
} |
439 |
|
|
440 |
/** Create a new MipzipLoader for the given mipzip file. |
/** Create a new MipzipLoader for the given mipzip file. |
441 |
* Must be run in the GL thread. |
* Must be run in the GL thread. |
442 |
*/ |
*/ |
443 |
public MipzipLoader(File mipzipFile) throws IOException { |
public MipzipLoader(File file) throws IOException { |
444 |
this.mipzipFile = mipzipFile; |
this.mipzipFile = new MipzipFile(file); |
445 |
this.tex = GL.createTexture(); |
this.tex = GL.createTexture(); |
446 |
synchronized(zlibLock) { |
bitsPerTexel = GL.bitsPerTexel(mipzipFile.getTexFormat()); |
|
ZipFile f = getZipFile(); |
|
|
if(dbg) { |
|
|
pa("Creating new mipzip loader: "+mipzipFile); |
|
|
for(Enumeration e = f.entries(); e.hasMoreElements(); ) { |
|
|
pa("Entry: " + e.nextElement()); |
|
|
} |
|
|
} |
|
|
ZipEntry e = f.getEntry("texformat"); |
|
|
if(e == null) throw new IOException("Invalid format: no texformat in mipzip"); |
|
|
this.texFormat = e.getComment(); |
|
|
this.compressedFormat = texFormat.indexOf("COMPRESS") != -1; |
|
|
|
|
|
e = f.getEntry("origsize"); |
|
|
if(e == null) throw new IOException("Invalid format: no origsize in mipzip"); |
|
|
String origSize = e.getComment(); |
|
|
|
|
|
{ |
|
|
int i = origSize.indexOf('x'); |
|
|
if(i < 0) throw new IOException("Invalid size string"); |
|
|
origWidth = Float.parseFloat(origSize.substring(0,i)); |
|
|
origHeight = Float.parseFloat(origSize.substring(i+1)); |
|
|
} |
|
447 |
|
|
448 |
|
levels = new Level[this.mipzipFile.getNLevels()]; |
449 |
|
for(int i=0; i<levels.length; i++) |
450 |
|
levels[i] = new Level(i); |
451 |
|
|
|
ArrayList l = new ArrayList(); |
|
|
for(int i=0; i<100; i++) { |
|
|
e = f.getEntry(""+i); |
|
|
if(e == null) break; |
|
|
l.add(new Level(i, e.getComment())); |
|
|
} |
|
|
levels = (Level[])l.toArray(new Level[l.size()]); |
|
|
if( levels[levels.length-1].size.width != 1 || |
|
|
levels[levels.length-1].size.height != 1 ) { |
|
|
throw new IOException("Not all levels there!"); |
|
|
} |
|
|
} |
|
|
bitsPerTexel = GL.bitsPerTexel(texFormat); |
|
452 |
if(bitsPerTexel < 0) { |
if(bitsPerTexel < 0) { |
453 |
if(dbg) pa("Warning: memory consumption for "+ |
pa("------- Warning: memory consumption for "+ |
454 |
texFormat+" not known, assuming 32bpt"); |
mipzipFile.getTexFormat()+" not known, assuming 32bpt"); |
455 |
bitsPerTexel = 32; |
bitsPerTexel = 32; |
456 |
} |
} |
457 |
maxBaseLevel = levels.length - 3; |
maxBaseLevel = levels.length - 3; |