ObjParser.java 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. package min3d.parser;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.io.InputStreamReader;
  6. import java.util.Calendar;
  7. import java.util.StringTokenizer;
  8. import app.mar.utils.files.FileManager;
  9. import min3d.Min3d;
  10. import min3d.Shared;
  11. import min3d.core.Object3dContainer;
  12. import min3d.vos.Color4;
  13. import min3d.vos.Number3d;
  14. import min3d.vos.Uv;
  15. import android.content.Context;
  16. import android.content.res.Resources;
  17. import android.graphics.Bitmap;
  18. import android.util.Log;
  19. /**
  20. * Parses Wavefront OBJ files. Basic version, this is still a work in progress!
  21. *
  22. * TODO: proper error handling TODO: handle multiple objects TODO: handle groups
  23. * TODO: a lot more :-) *
  24. *
  25. * @author dennis.ippel
  26. *
  27. */
  28. public class ObjParser extends AParser implements IParser {
  29. private final String VERTEX = "v";
  30. private final String FACE = "f";
  31. private final String TEXCOORD = "vt";
  32. private final String NORMAL = "vn";
  33. private final String OBJECT = "o";
  34. private final String MATERIAL_LIB = "mtllib";
  35. private final String USE_MATERIAL = "usemtl";
  36. private final String NEW_MATERIAL = "newmtl";
  37. private final String DIFFUSE_COLOR = "Kd";
  38. private final String DIFFUSE_TEX_MAP = "map_Kd";
  39. /**
  40. * Creates a new OBJ parser instance
  41. *
  42. * @param resources
  43. * @param resourceID
  44. */
  45. public ObjParser(Context a, Resources resources, String resourceID, boolean generateMipMap) {
  46. super(a, resources, resourceID, generateMipMap);
  47. System.out.println("Parser:"+resourceID);
  48. System.err.println("Parser:"+resourceID);
  49. }
  50. public ObjParser(Context a, String is, boolean generateMipMap) {
  51. super(a, is, generateMipMap);
  52. System.out.println("Parser:"+resourceID);
  53. System.err.println("Parser:"+resourceID);
  54. }
  55. @Override
  56. public void parse() {
  57. long startTime = Calendar.getInstance().getTimeInMillis();
  58. InputStream fileIn = null;
  59. if(mStream==null)
  60. {
  61. fileIn =resources.openRawResource(resources.getIdentifier(
  62. resourceID, null, null));
  63. }else fileIn = mStream;
  64. BufferedReader buffer = new BufferedReader(
  65. new InputStreamReader(fileIn));
  66. String line;
  67. co = new ParseObjectData(vertices, texCoords, normals);
  68. parseObjects.add(co);
  69. Log.d(Min3d.TAG, "Start parsing object " + resourceID);
  70. Log.d(Min3d.TAG, "Start time " + startTime);
  71. try {
  72. while ((line = buffer.readLine()) != null) {
  73. // remove duplicate whitespace
  74. // line = line.replaceAll("\\s+", " ");
  75. // String[] parts = line.split(" ");
  76. StringTokenizer parts = new StringTokenizer(line, " ");
  77. int numTokens = parts.countTokens();
  78. if (numTokens == 0)
  79. continue;
  80. String type = parts.nextToken();
  81. if (type.equals(VERTEX)) {
  82. Number3d vertex = new Number3d();
  83. vertex.x = Float.parseFloat(parts.nextToken());
  84. vertex.y = Float.parseFloat(parts.nextToken());
  85. vertex.z = Float.parseFloat(parts.nextToken());
  86. vertices.add(vertex);
  87. } else if (type.equals(FACE)) {
  88. if (numTokens == 4) {
  89. co.numFaces++;
  90. co.faces.add(new ObjFace(line, currentMaterialKey, 3));
  91. } else if (numTokens == 5) {
  92. co.numFaces += 2;
  93. co.faces.add(new ObjFace(line, currentMaterialKey, 4));
  94. }
  95. } else if (type.equals(TEXCOORD)) {
  96. Uv texCoord = new Uv();
  97. texCoord.u = Float.parseFloat(parts.nextToken());
  98. texCoord.v = Float.parseFloat(parts.nextToken()) * -1f;
  99. texCoords.add(texCoord);
  100. } else if (type.equals(NORMAL)) {
  101. Number3d normal = new Number3d();
  102. normal.x = Float.parseFloat(parts.nextToken());
  103. normal.y = Float.parseFloat(parts.nextToken());
  104. normal.z = Float.parseFloat(parts.nextToken());
  105. normals.add(normal);
  106. } else if (type.equals(MATERIAL_LIB)) {
  107. readMaterialLib(parts.nextToken());
  108. } else if (type.equals(USE_MATERIAL)) {
  109. currentMaterialKey = parts.nextToken();
  110. } else if (type.equals(OBJECT)) {
  111. String objName = parts.hasMoreTokens() ? parts.nextToken() : "";
  112. if(firstObject)
  113. {
  114. Log.d(Min3d.TAG, "Create object " + objName);
  115. co.name = objName;
  116. firstObject = false;
  117. }
  118. else
  119. {
  120. Log.d(Min3d.TAG, "Create object " + objName);
  121. co = new ParseObjectData(vertices, texCoords, normals);
  122. co.name = objName;
  123. parseObjects.add(co);
  124. }
  125. }
  126. }
  127. } catch (IOException e) {
  128. e.printStackTrace();
  129. }
  130. long endTime = Calendar.getInstance().getTimeInMillis();
  131. Log.d(Min3d.TAG, "End time " + (endTime - startTime));
  132. }
  133. public Object3dContainer getParsedObject() {
  134. Log.d(Min3d.TAG, "Start object creation");
  135. Object3dContainer obj = new Object3dContainer(0, 0);
  136. int numObjects = parseObjects.size();
  137. Bitmap texture = null;
  138. if(textureAtlas.hasBitmaps())
  139. {
  140. textureAtlas.generate();
  141. texture = textureAtlas.getBitmap();
  142. Shared.textureManager().addTextureId(texture, textureAtlas.getId(), generateMipMap);
  143. }
  144. for (int i = 0; i < numObjects; i++) {
  145. ParseObjectData o = parseObjects.get(i);
  146. Log.d(Min3d.TAG, "Creating object " + o.name);
  147. obj.addChild(o.getParsedObject(materialMap, textureAtlas));
  148. }
  149. if(textureAtlas.hasBitmaps())
  150. {
  151. if(texture != null) texture.recycle();
  152. }
  153. Log.d(Min3d.TAG, "Object creation finished");
  154. cleanup();
  155. return obj;
  156. }
  157. private void readMaterialLib(String libID) {
  158. InputStream fileIn=null;
  159. StringBuffer libIDSbuf = new StringBuffer(libID);
  160. int dotIndex = libIDSbuf.lastIndexOf(".");
  161. if (dotIndex > -1)
  162. libIDSbuf = libIDSbuf.replace(dotIndex, dotIndex + 1, "_");
  163. if(mStream==null) {
  164. StringBuffer resourceID = new StringBuffer(packageID);
  165. resourceID.append(":raw/");
  166. resourceID.append(libIDSbuf.toString());
  167. Log.e("OBJParser", "Load MTL '" + resourceID.toString() + "'");
  168. fileIn = resources.openRawResource(resources.getIdentifier(
  169. resourceID.toString(), null, null));
  170. }else {
  171. try {
  172. fileIn = FileManager.openFile(mContext, packageID+libID);
  173. } catch (Exception e) {
  174. e.printStackTrace();
  175. }
  176. }
  177. BufferedReader buffer = new BufferedReader(
  178. new InputStreamReader(fileIn));
  179. String line;
  180. String currentMaterial = "";
  181. try {
  182. while ((line = buffer.readLine()) != null) {
  183. String[] parts = line.split(" ");
  184. if (parts.length == 0)
  185. continue;
  186. String type = parts[0];
  187. if (type.equals(NEW_MATERIAL)) {
  188. if (parts.length > 1) {
  189. currentMaterial = parts[1];
  190. materialMap.put(currentMaterial, new Material(
  191. currentMaterial));
  192. }
  193. } else if(type.equals(DIFFUSE_COLOR) && !type.equals(DIFFUSE_TEX_MAP)) {
  194. Color4 diffuseColor = new Color4(Float.parseFloat(parts[1]) * 255.0f, Float.parseFloat(parts[2]) * 255.0f, Float.parseFloat(parts[3]) * 255.0f, 255.0f);
  195. materialMap.get(currentMaterial).diffuseColor = diffuseColor;
  196. } else if (type.equals(DIFFUSE_TEX_MAP)) {
  197. if (parts.length > 1) {
  198. materialMap.get(currentMaterial).diffuseTextureMap = parts[1];
  199. StringBuffer texture = new StringBuffer(packageID);
  200. if(mStream==null) texture.append(":drawable/");
  201. StringBuffer textureName = new StringBuffer(parts[1]);
  202. dotIndex = textureName.lastIndexOf(".");
  203. if (dotIndex > -1)
  204. texture.append(textureName.substring(0, dotIndex));
  205. else
  206. texture.append(textureName);
  207. System.out.println("Drawable = "+texture.toString());
  208. /*int bmResourceID = resources.getIdentifier(texture
  209. .toString(), null, null);
  210. Bitmap b = Utils.makeBitmapFromResourceId(bmResourceID);*/
  211. textureAtlas.addBitmapAsset(new BitmapAsset(currentMaterial, texture.toString()));
  212. }
  213. }
  214. }
  215. } catch (IOException e) {
  216. e.printStackTrace();
  217. }
  218. }
  219. @Override
  220. protected void cleanup() {
  221. super.cleanup();
  222. materialMap.clear();
  223. }
  224. private class ObjFace extends ParseObjectFace {
  225. public ObjFace(String line, String materialKey, int faceLength) {
  226. super();
  227. this.materialKey = materialKey;
  228. this.faceLength = faceLength;
  229. boolean emptyVt = line.indexOf("//") > -1;
  230. if(emptyVt) line = line.replace("//", "/");
  231. StringTokenizer parts = new StringTokenizer(line);
  232. parts.nextToken();
  233. StringTokenizer subParts = new StringTokenizer(parts.nextToken(), "/");
  234. int partLength = subParts.countTokens();
  235. hasuv = partLength >= 2 && !emptyVt;
  236. hasn = partLength == 3 || (partLength == 2 && emptyVt);
  237. v = new int[faceLength];
  238. if (hasuv)
  239. uv = new int[faceLength];
  240. if (hasn)
  241. n = new int[faceLength];
  242. for (int i = 1; i < faceLength + 1; i++) {
  243. if (i > 1)
  244. subParts = new StringTokenizer(parts.nextToken(), "/");
  245. int index = i - 1;
  246. v[index] = (short) (Short.parseShort(subParts.nextToken()) - 1);
  247. if (hasuv)
  248. uv[index] = (short) (Short.parseShort(subParts.nextToken()) - 1);
  249. if (hasn)
  250. n[index] = (short) (Short.parseShort(subParts.nextToken()) - 1);
  251. }
  252. }
  253. }
  254. }