Home | History | Annotate | Download | only in RenderUtils
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils;
     17 
     18 import android.content.res.Resources;
     19 import android.util.Log;
     20 
     21 import java.io.BufferedReader;
     22 import java.io.IOException;
     23 import java.io.InputStream;
     24 import java.io.InputStreamReader;
     25 import java.util.ArrayList;
     26 import java.util.StringTokenizer;
     27 
     28 /**
     29  * Imports an .obj file into an ObjectData class so that it can be rendered by OpenGl. Based on the
     30  * .obj importer from Rajawali.
     31  */
     32 public class ObjImporter {
     33     protected static final String TAG = "ObjImporter";
     34     protected static final String VERTEX = "v";
     35     protected static final String FACE = "f";
     36     protected static final String NORMAL = "vn";
     37 
     38     protected static class ObjIndexData {
     39 
     40         public ArrayList<Integer> vertexIndices;
     41         public ArrayList<Integer> texCoordIndices;
     42         public ArrayList<Integer> colorIndices;
     43         public ArrayList<Integer> normalIndices;
     44 
     45         public ObjIndexData() {
     46             vertexIndices = new ArrayList<Integer>();
     47             texCoordIndices = new ArrayList<Integer>();
     48             colorIndices = new ArrayList<Integer>();
     49             normalIndices = new ArrayList<Integer>();
     50         }
     51     }
     52 
     53     public static class ObjectData {
     54         float[] mVertexData;
     55         float[] mNormalsData;
     56         int[] mIndicesData;
     57 
     58         protected ObjectData(float[] vertexData, float[] normalsData, int[] indicesData) {
     59             mVertexData = vertexData;
     60             mNormalsData = normalsData;
     61             mIndicesData = indicesData;
     62         }
     63 
     64         public float[] getVertexData() {
     65             return mVertexData;
     66         }
     67 
     68         public float[] getNormalsData() {
     69             return mNormalsData;
     70         }
     71 
     72         public int[] getIndicesData() {
     73             return mIndicesData;
     74         }
     75     }
     76 
     77     public static ObjectData parse(Resources mResources, int mResourceId) {
     78         BufferedReader buffer = null;
     79         InputStream fileIn = mResources.openRawResource(mResourceId);
     80         buffer = new BufferedReader(new InputStreamReader(fileIn));
     81         String line;
     82         ObjIndexData currObjIndexData = new ObjIndexData();
     83 
     84         ArrayList<Float> vertices = new ArrayList<Float>();
     85         ArrayList<Float> texCoords = new ArrayList<Float>();
     86         ArrayList<Float> normals = new ArrayList<Float>();
     87 
     88         try {
     89             while ((line = buffer.readLine()) != null) {
     90                 // Skip comments and empty lines.
     91                 if (line.length() == 0 || line.charAt(0) == '#')
     92                     continue;
     93                 StringTokenizer parts = new StringTokenizer(line, " ");
     94                 int numTokens = parts.countTokens();
     95 
     96                 if (numTokens == 0)
     97                     continue;
     98                 String type = parts.nextToken();
     99 
    100                 if (type.equals(VERTEX)) {
    101                     vertices.add(Float.parseFloat(parts.nextToken()));
    102                     vertices.add(Float.parseFloat(parts.nextToken()));
    103                     vertices.add(Float.parseFloat(parts.nextToken()));
    104                 } else if (type.equals(FACE)) {
    105                     boolean isQuad = numTokens == 5;
    106                     int[] quadvids = new int[4];
    107                     int[] quadtids = new int[4];
    108                     int[] quadnids = new int[4];
    109 
    110                     boolean emptyVt = line.indexOf("//") > -1;
    111                     if (emptyVt) line = line.replace("//", "/");
    112 
    113                     parts = new StringTokenizer(line);
    114 
    115                     parts.nextToken();
    116                     StringTokenizer subParts = new StringTokenizer(parts.nextToken(), "/");
    117                     int partLength = subParts.countTokens();
    118 
    119                     boolean hasuv = partLength >= 2 && !emptyVt;
    120                     boolean hasn = partLength == 3 || (partLength == 2 && emptyVt);
    121                     int idx;
    122 
    123                     for (int i = 1; i < numTokens; i++) {
    124                         if (i > 1)
    125                             subParts = new StringTokenizer(parts.nextToken(), "/");
    126                         idx = Integer.parseInt(subParts.nextToken());
    127 
    128                         if (idx < 0) idx = (vertices.size() / 3) + idx;
    129                         else idx -= 1;
    130                         if (!isQuad)
    131                             currObjIndexData.vertexIndices.add(idx);
    132                         else
    133                             quadvids[i - 1] = idx;
    134                         if (hasuv) {
    135                             idx = Integer.parseInt(subParts.nextToken());
    136                             if (idx < 0) idx = (texCoords.size() / 2) + idx;
    137                             else idx -= 1;
    138                             if (!isQuad)
    139                                 currObjIndexData.texCoordIndices.add(idx);
    140                             else
    141                                 quadtids[i - 1] = idx;
    142                         }
    143                         if (hasn) {
    144                             idx = Integer.parseInt(subParts.nextToken());
    145                             if (idx < 0) idx = (normals.size() / 3) + idx;
    146                             else idx -= 1;
    147                             if (!isQuad)
    148                                 currObjIndexData.normalIndices.add(idx);
    149                             else
    150                                 quadnids[i - 1] = idx;
    151                         }
    152                     }
    153 
    154                     if (isQuad) {
    155                         int[] indices = new int[]{0, 1, 2, 0, 2, 3};
    156 
    157                         for (int i = 0; i < 6; ++i) {
    158                             int index = indices[i];
    159                             currObjIndexData.vertexIndices.add(quadvids[index]);
    160                             currObjIndexData.texCoordIndices.add(quadtids[index]);
    161                             currObjIndexData.normalIndices.add(quadnids[index]);
    162                         }
    163                     }
    164                 } else if (type.equals(NORMAL)) {
    165                     normals.add(Float.parseFloat(parts.nextToken()));
    166                     normals.add(Float.parseFloat(parts.nextToken()));
    167                     normals.add(Float.parseFloat(parts.nextToken()));
    168                 }
    169             }
    170 
    171             buffer.close();
    172         } catch (IOException e) {
    173             Log.e(TAG, "failed to parse", e);
    174         }
    175 
    176         int i;
    177         float[] aVertices = new float[currObjIndexData.vertexIndices.size() * 3];
    178         float[] aNormals = new float[currObjIndexData.normalIndices.size() * 3];
    179         int[] aIndices = new int[currObjIndexData.vertexIndices.size()];
    180 
    181         for (i = 0; i < currObjIndexData.vertexIndices.size(); ++i) {
    182             int faceIndex = currObjIndexData.vertexIndices.get(i) * 3;
    183             int vertexIndex = i * 3;
    184             try {
    185                 aVertices[vertexIndex] = vertices.get(faceIndex);
    186                 aVertices[vertexIndex + 1] = vertices.get(faceIndex + 1);
    187                 aVertices[vertexIndex + 2] = vertices.get(faceIndex + 2);
    188                 aIndices[i] = i;
    189             } catch (ArrayIndexOutOfBoundsException e) {
    190                 Log.d(TAG, "Obj array index out of bounds: " + vertexIndex + ", " + faceIndex);
    191             }
    192         }
    193         for (i = 0; i < currObjIndexData.normalIndices.size(); ++i) {
    194             int normalIndex = currObjIndexData.normalIndices.get(i) * 3;
    195             int ni = i * 3;
    196             if (normals.size() == 0) {
    197                 Log.e(TAG, "There are no normals specified for this model. " +
    198                         "Please re-export with normals.");
    199                 throw new RuntimeException("[" + TAG + "] There are no normals specified " +
    200                         "for this model. Please re-export with normals.");
    201             }
    202             aNormals[ni] = normals.get(normalIndex);
    203             aNormals[ni + 1] = normals.get(normalIndex + 1);
    204             aNormals[ni + 2] = normals.get(normalIndex + 2);
    205         }
    206 
    207         return new ObjectData(aVertices, aNormals, aIndices);
    208     }
    209 }
    210