/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.opengl; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.IntBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.microedition.khronos.opengles.*; /** * {@hide} */ public abstract class Object3D { private boolean mHasTexcoords = false; private float mBoundsMinX = Float.MAX_VALUE; private float mBoundsMaxX = Float.MIN_VALUE; private float mBoundsMinY = Float.MAX_VALUE; private float mBoundsMaxY = Float.MIN_VALUE; private float mBoundsMinZ = Float.MAX_VALUE; private float mBoundsMaxZ = Float.MIN_VALUE; private IntBuffer mVertexBuffer; private IntBuffer mNormalBuffer; private IntBuffer mTexcoordBuffer; // All groups, by name private Map<String, Group> mGroups; // All materials, by name private Map<String, Material> mMaterials; // All texture maps, by name private Map<String, Texture> mTextures; public Object3D() { reset(); } /** * Override this method with an implementation that contructs * and InputStream from the given filename. For example, if the * source files are to be retrieved using an AssetManager, * the implementation would use AssetManager.load() to * get the input stream. */ public abstract InputStream readFile(String filename) throws IOException; private void reset() { mVertexBuffer = mNormalBuffer = mTexcoordBuffer = null; mGroups = new HashMap<String,Group>(); mMaterials = new HashMap<String,Material>(); mTextures = new HashMap<String,Texture>(); } public Material getMaterial(String name) { Material mat = mMaterials.get(name); return mat; } public Texture getTexture(String name) { return mTextures.get(name); } public IntBuffer getVertexBuffer() { return mVertexBuffer; } public IntBuffer getNormalBuffer() { return mNormalBuffer; } public IntBuffer getTexcoordBuffer() { return mTexcoordBuffer; } public int getNumTriangles() { int numTriangles = 0; Iterator<Group> iter = mGroups.values().iterator(); while (iter.hasNext()) { numTriangles += iter.next().getNumTriangles(); } return numTriangles; } public boolean hasTexcoords() { return mHasTexcoords; } public float getBoundsMinX() { return mBoundsMinX; } public float getBoundsMaxX() { return mBoundsMaxX; } public float getBoundsMinY() { return mBoundsMinY; } public float getBoundsMaxY() { return mBoundsMaxY; } public float getBoundsMinZ() { return mBoundsMinZ; } public float getBoundsMaxZ() { return mBoundsMaxZ; } public void loadTexture(String name) throws IOException { InputStream is = readFile(name + ".raw"); Texture texture = new Texture(is); mTextures.put(name, texture); } private static void verifyByte(DataInputStream dis, int b) throws IOException { int x = dis.read() & 0xff; if (x != b) { throw new RuntimeException("Bad byte: " + x + " (expected " + b + ")"); } } public void load(String filename) throws IOException { reset(); DataInputStream dis = new DataInputStream(readFile(filename)); verifyByte(dis, 'g' + 128); verifyByte(dis, 'l'); verifyByte(dis, 'e'); verifyByte(dis, 's'); int numTuples = dis.readInt(); this.mBoundsMinX = dis.readFloat(); this.mBoundsMaxX = dis.readFloat(); this.mBoundsMinY = dis.readFloat(); this.mBoundsMaxY = dis.readFloat(); this.mBoundsMinZ = dis.readFloat(); this.mBoundsMaxZ = dis.readFloat(); this.mHasTexcoords = dis.readInt() == 1; int intsPerTuple = mHasTexcoords ? 8 : 6; int numInts = numTuples*intsPerTuple; int len = 4*numTuples*(mHasTexcoords ? 8 : 6); byte[] tmp = new byte[len]; int tidx = 0; while (tidx < len) { tidx += dis.read(tmp, tidx, len - tidx); } if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) { for (int i = 0; i < len; i += 4) { byte tmp0 = tmp[i]; byte tmp1 = tmp[i + 1]; byte tmp2 = tmp[i + 2]; byte tmp3 = tmp[i + 3]; tmp[i] = tmp3; tmp[i + 1] = tmp2; tmp[i + 2] = tmp1; tmp[i + 3] = tmp0; } } ByteBuffer allbb = ByteBuffer.allocateDirect(len); allbb.order(ByteOrder.nativeOrder()); allbb.put(tmp); allbb.position(0); allbb.limit(4*3*numTuples); ByteBuffer vbb = allbb.slice(); this.mVertexBuffer = vbb.asIntBuffer(); mVertexBuffer.position(0); if (mHasTexcoords) { allbb.position(allbb.limit()); allbb.limit(allbb.position() + 4*2*numTuples); ByteBuffer tbb = allbb.slice(); this.mTexcoordBuffer = tbb.asIntBuffer(); mTexcoordBuffer.position(0); } allbb.position(allbb.limit()); allbb.limit(allbb.position() + 4*3*numTuples); ByteBuffer nbb = allbb.slice(); this.mNormalBuffer = nbb.asIntBuffer(); mNormalBuffer.position(0); int numMaterials = dis.readInt(); for (int i = 0; i < numMaterials; i++) { Material mat = new Material(this); mat.load(dis); mMaterials.put(mat.getName(), mat); } int numGroups = dis.readInt(); for (int i = 0; i < numGroups; i++) { Group g = new Group(this); g.load(dis); mGroups.put(g.getName(), g); } } public void draw(GL10 gl) { Iterator<Group> iter = mGroups.values().iterator(); while (iter.hasNext()) { iter.next().draw(gl); } } }