ObjParser.java 8.8 KB

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