1 package min3d.parser;
\r
3 import java.io.FileNotFoundException;
\r
4 import java.io.FileOutputStream;
\r
5 import java.io.IOException;
\r
6 import java.io.InputStream;
\r
7 import java.util.ArrayList;
\r
8 import java.util.Collections;
\r
9 import java.util.Comparator;
\r
10 import java.util.HashMap;
\r
13 import min3d.Shared;
\r
15 import min3d.animation.AnimationObject3d;
\r
16 import min3d.core.Object3dContainer;
\r
17 import min3d.vos.Color4;
\r
18 import min3d.vos.Number3d;
\r
19 import min3d.vos.Uv;
\r
20 import android.content.res.Resources;
\r
21 import android.graphics.Bitmap;
\r
22 import android.graphics.Bitmap.Config;
\r
23 import android.util.Log;
\r
26 * Abstract parser class with basic parsing functionality.
\r
28 * @author dennis.ippel
\r
31 public abstract class AParser implements IParser {
\r
32 protected Resources resources;
\r
33 protected String resourceID;
\r
34 protected String packageID;
\r
35 protected String currentMaterialKey;
\r
36 protected ArrayList<ParseObjectData> parseObjects;
\r
37 protected ParseObjectData co;
\r
38 protected boolean firstObject;
\r
39 protected TextureAtlas textureAtlas;
\r
40 protected ArrayList<Number3d> vertices;
\r
41 protected ArrayList<Uv> texCoords;
\r
42 protected ArrayList<Number3d> normals;
\r
43 protected boolean generateMipMap;
\r
44 protected HashMap<String, Material> materialMap;
\r
48 vertices = new ArrayList<Number3d>();
\r
49 texCoords = new ArrayList<Uv>();
\r
50 normals = new ArrayList<Number3d>();
\r
51 parseObjects = new ArrayList<ParseObjectData>();
\r
52 textureAtlas = new TextureAtlas();
\r
54 materialMap = new HashMap<String, Material>();
\r
57 public AParser(Resources resources, String resourceID, Boolean generateMipMap)
\r
60 this.resources = resources;
\r
61 this.resourceID = resourceID;
\r
62 if (resourceID.indexOf(":") > -1)
\r
63 this.packageID = resourceID.split(":")[0];
\r
64 this.generateMipMap = generateMipMap;
\r
67 protected void cleanup()
\r
69 parseObjects.clear();
\r
70 textureAtlas.cleanup();
\r
77 * Override this in the concrete parser
\r
79 public Object3dContainer getParsedObject() {
\r
84 * Override this in the concrete parser if applicable
\r
86 public AnimationObject3d getParsedAnimationObject() {
\r
90 protected String readString(InputStream stream) throws IOException {
\r
91 String result = new String();
\r
93 while ((inByte = (byte) stream.read()) != 0)
\r
94 result += (char) inByte;
\r
98 protected int readInt(InputStream stream) throws IOException {
\r
99 return stream.read() | (stream.read() << 8) | (stream.read() << 16)
\r
100 | (stream.read() << 24);
\r
103 protected int readShort(InputStream stream) throws IOException {
\r
104 return (stream.read() | (stream.read() << 8));
\r
107 protected float readFloat(InputStream stream) throws IOException {
\r
108 return Float.intBitsToFloat(readInt(stream));
\r
112 * Override this in the concrete parser
\r
114 public void parse() {
\r
119 * Contains texture information. UV offsets and scaling is stored here.
\r
120 * This is used with texture atlases.
\r
122 * @author dennis.ippel
\r
125 protected class BitmapAsset
\r
128 * The texture bitmap
\r
130 public Bitmap bitmap;
\r
132 * The texture identifier
\r
138 public String resourceID;
\r
140 * U-coordinate offset
\r
142 public float uOffset;
\r
144 * V-coordinate offset
\r
146 public float vOffset;
\r
148 * U-coordinate scaling value
\r
150 public float uScale;
\r
152 * V-coordinate scaling value
\r
154 public float vScale;
\r
155 public boolean useForAtlasDimensions;
\r
158 * Creates a new BitmapAsset object
\r
162 public BitmapAsset(String key, String resourceID)
\r
165 this.resourceID = resourceID;
\r
166 useForAtlasDimensions = false;
\r
171 * When a model contains per-face textures a texture atlas is created. This
\r
172 * combines multiple textures into one and re-calculates the UV coordinates.
\r
174 * @author dennis.ippel
\r
177 protected class TextureAtlas {
\r
179 * The texture bitmaps that should be combined into one.
\r
181 private ArrayList<BitmapAsset> bitmaps;
\r
183 * The texture atlas bitmap
\r
185 private Bitmap atlas;
\r
188 * Creates a new texture atlas instance.
\r
190 public TextureAtlas() {
\r
191 bitmaps = new ArrayList<BitmapAsset>();
\r
193 private String atlasId;
\r
196 * Adds a bitmap to the atlas
\r
200 public void addBitmapAsset(BitmapAsset ba) {
\r
201 BitmapAsset existingBA = getBitmapAssetByResourceID(ba.resourceID);
\r
203 if(existingBA == null)
\r
205 int bmResourceID = resources.getIdentifier(ba.resourceID, null, null);
\r
206 if(bmResourceID == 0)
\r
208 Log.d(Min3d.TAG, "Texture not found: " + ba.resourceID);
\r
212 Log.d(Min3d.TAG, "Adding texture " + ba.resourceID);
\r
214 Bitmap b = Utils.makeBitmapFromResourceId(bmResourceID);
\r
215 ba.useForAtlasDimensions = true;
\r
220 ba.bitmap = existingBA.bitmap;
\r
226 public BitmapAsset getBitmapAssetByResourceID(String resourceID)
\r
228 int numBitmaps = bitmaps.size();
\r
230 for(int i=0; i<numBitmaps; i++)
\r
232 if(bitmaps.get(i).resourceID.equals(resourceID))
\r
233 return bitmaps.get(i);
\r
240 * Generates a new texture atlas
\r
242 public void generate() {
\r
243 Collections.sort(bitmaps, new BitmapHeightComparer());
\r
245 if(bitmaps.size() == 0) return;
\r
247 BitmapAsset largestBitmap = bitmaps.get(0);
\r
248 int totalWidth = 0;
\r
249 int numBitmaps = bitmaps.size();
\r
253 for (int i = 0; i < numBitmaps; i++) {
\r
254 if(bitmaps.get(i).useForAtlasDimensions)
\r
255 totalWidth += bitmaps.get(i).bitmap.getWidth();
\r
258 atlas = Bitmap.createBitmap(totalWidth, largestBitmap.bitmap
\r
259 .getHeight(), Config.ARGB_8888);
\r
261 for (int i = 0; i < numBitmaps; i++) {
\r
262 BitmapAsset ba = bitmaps.get(i);
\r
263 BitmapAsset existingBA = getBitmapAssetByResourceID(ba.resourceID);
\r
265 if(ba.useForAtlasDimensions)
\r
267 Bitmap b = ba.bitmap;
\r
268 int w = b.getWidth();
\r
269 int h = b.getHeight();
\r
270 int[] pixels = new int[w * h];
\r
272 b.getPixels(pixels, 0, w, 0, 0, w, h);
\r
273 atlas.setPixels(pixels, 0, w, uOffset, vOffset, w, h);
\r
275 ba.uOffset = (float) uOffset / totalWidth;
\r
277 ba.uScale = (float) w / (float) totalWidth;
\r
278 ba.vScale = (float) h / (float) largestBitmap.bitmap.getHeight();
\r
285 ba.uOffset = existingBA.uOffset;
\r
286 ba.vOffset = existingBA.vOffset;
\r
287 ba.uScale = existingBA.uScale;
\r
288 ba.vScale = existingBA.vScale;
\r
292 FileOutputStream fos;
\r
294 fos = new FileOutputStream("/data/screenshot.png");
\r
295 atlas.compress(Bitmap.CompressFormat.PNG, 100, fos);
\r
298 } catch (FileNotFoundException e) {
\r
299 // TODO Auto-generated catch block
\r
300 e.printStackTrace();
\r
301 } catch (IOException e) {
\r
302 // TODO Auto-generated catch block
\r
303 e.printStackTrace();
\r
306 setId(Shared.textureManager().getNewAtlasId());
\r
310 * Returns the generated texture atlas bitmap
\r
314 public Bitmap getBitmap() {
\r
319 * Indicates whether bitmaps have been added to the atlas.
\r
323 public boolean hasBitmaps() {
\r
324 return bitmaps.size() > 0;
\r
328 * Compares the height of two BitmapAsset objects.
\r
330 * @author dennis.ippel
\r
333 private class BitmapHeightComparer implements Comparator<BitmapAsset> {
\r
334 public int compare(BitmapAsset b1, BitmapAsset b2) {
\r
335 int height1 = b1.bitmap.getHeight();
\r
336 int height2 = b2.bitmap.getHeight();
\r
338 if (height1 < height2) {
\r
340 } else if (height1 == height2) {
\r
349 * Returns a bitmap asset with a specified name.
\r
351 * @param materialKey
\r
354 public BitmapAsset getBitmapAssetByName(String materialKey) {
\r
355 int numBitmaps = bitmaps.size();
\r
357 for (int i = 0; i < numBitmaps; i++) {
\r
358 if (bitmaps.get(i).key.equals(materialKey))
\r
359 return bitmaps.get(i);
\r
365 public void cleanup()
\r
367 int numBitmaps = bitmaps.size();
\r
369 for (int i = 0; i < numBitmaps; i++) {
\r
370 bitmaps.get(i).bitmap.recycle();
\r
373 if(atlas != null) atlas.recycle();
\r
380 public void setId(String newAtlasId) {
\r
381 atlasId = newAtlasId;
\r
384 public String getId() {
\r
389 protected class Material {
\r
390 public String name;
\r
391 public String diffuseTextureMap;
\r
392 public Color4 diffuseColor;
\r
394 public Material(String name) {
\r