ObjParser.java 8.0 KB

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