I'm writing a Java LWJGL 3D game-engine. I decided to rewrite my mesh class and the .obj loader. The mesh class works fine when putting in data manually, but wehn loading from an .obj-file it gives some strange results: (it's supposed to be a dragon but lokks like a 2D ... something)
public static Mesh loadMesh(String fileName) throws IOException
{
String splitArray[] = fileName.split("\\.");
String ext = splitArray[splitArray.length-1];
if(!ext.equals("obj"))
System.err.println("Error: Engine can only load .obj files, try converting the file: " + fileName);
ArrayList<Vector3f> vertices = new ArrayList<Vector3f>();
ArrayList<Integer> vindices = new ArrayList<Integer>();
ArrayList<Integer> tindices = new ArrayList<Integer>();
ArrayList<Integer> nindices = new ArrayList<Integer>();
ArrayList<Vector3f> normals = new ArrayList<Vector3f>();
ArrayList<Vector2f> texCoords = new ArrayList<Vector2f>();
BufferedReader reader = new BufferedReader(new FileReader("./res/models/"+fileName));
String line = "";
while((line=reader.readLine())!=null)
{
String[] p = line.split(" ");
if(line.startsWith("v"))
{
vertices.add(new Vector3f(Float.valueOf(p[1]),
Float.valueOf(p[2]),
Float.valueOf(p[3])));
}
if(line.startsWith("vn"))
{
normals.add(new Vector3f(Float.valueOf(p[1]),
Float.valueOf(p[2]),
Float.valueOf(p[3])));
}
if(line.startsWith("vt"))
{
texCoords.add(new Vector2f(Float.valueOf(p[1]),
Float.valueOf(p[2])));
}
if(line.startsWith("f"))
{
String[] arg1 = p[1].split("/");
String[] arg2 = p[2].split("/");
String[] arg3 = p[3].split("/");
vindices.add(Integer.parseInt(arg1[0]));
if(arg1.length>1)
tindices.add(Integer.parseInt(arg1[1]));
if(arg1.length>2)
nindices.add(Integer.parseInt(arg1[3]));
vindices.add(Integer.parseInt(arg2[0]));
if(arg1.length>1)
tindices.add(Integer.parseInt(arg2[1]));
if(arg2.length>2)
nindices.add(Integer.parseInt(arg2[3]));
vindices.add(Integer.parseInt(arg3[0]));
if(arg1.length>1)
tindices.add(Integer.parseInt(arg3[1]));
if(arg3.length>2)
nindices.add(Integer.parseInt(arg3[3]));
}
}
float[] vdata = new float[vertices.size() * 3];
float[] tdata = new float[texCoords.size() * 2];
float[] ndata = new float[normals.size() * 3];
for(int i = 0; i < vdata.length; i++)
{
vdata[i] = vertices.get(Integer.valueOf(vindices.get(i))).getX();
vdata[i++] = vertices.get(Integer.valueOf(vindices.get(i))).getY();
vdata[i++] = vertices.get(Integer.valueOf(vindices.get(i))).getZ();
}
for(int i = 0; i < ndata.length; i++)
{
ndata[i] = normals.get(Integer.valueOf(nindices.get(i))).getX();
ndata[i++] = normals.get(Integer.valueOf(nindices.get(i))).getY();
ndata[i++] = normals.get(Integer.valueOf(nindices.get(i))).getZ();
}
for(int i = 0; i < tdata.length; i++)
{
tdata[i] = texCoords.get(Integer.valueOf(tindices.get(i))).getX();
tdata[i++] = texCoords.get(Integer.valueOf(tindices.get(i))).getY();
}
return new Mesh(vdata, tdata, ndata);
}
thats my .obj-file loader. Can't see what is wrong...
Upon closer inspection there are some nice bugs:
vindices.add(Integer.parseInt(arg1[0]));
if(arg1.length>1)
tindices.add(Integer.parseInt(arg1[1]));
if(arg1.length>2)
nindices.add(Integer.parseInt(arg1[3])); // this should be 2 for the normals
and
for(int i = 0; i < vdata.length; i++)
{
vdata[i] = vertices.get(Integer.valueOf(vindices.get(i))).getX(); //i=0
vdata[i++] = vertices.get(Integer.valueOf(vindices.get(i))).getY(); //i=0 and counted up afterwards
vdata[i++] = vertices.get(Integer.valueOf(vindices.get(i))).getZ();//i=1 and counted up afterwards
}
This is what makes the mesh two-dimensional.
I would suggest using eigther ++i or
for(int i = 0; i < vdata.length; i+=3)
{
vdata[i] = vertices.get(Integer.valueOf(vindices.get(i))).getX();
vdata[i+1] = vertices.get(Integer.valueOf(vindices.get(i))).getY();
vdata[i+2] = vertices.get(Integer.valueOf(vindices.get(i))).getZ();
}
Related
I have 5 files text.
I merge these files into 1 file. That file contain about 60 sentences.
I want to clustering that file to 5 cluster.
I am using weka to clustering.
public static void doClustering(String pathSentences, int numberCluster) throws IOException {
Helper.deleteAllFileInFolder("results");
//so cum bang so cau trong file / so cau trung binh trong 1 file
HashMap<Integer, String> sentences = new HashMap<>();
HashMap<Integer, Integer> clustering = new HashMap<>();
try {
StringToWordVector filter = new StringToWordVector();
SimpleKMeans kmeans = new SimpleKMeans();
FastVector atts = new FastVector(5);
atts.addElement(new Attribute("text", (FastVector) null));
Instances docs = new Instances("text_files", atts, 0);
Scanner sc = new Scanner(new File(pathSentences));
int count = 0;
while (sc.hasNextLine()) {
String content = sc.nextLine();
double[] newInst = new double[1];
newInst[0] = (double) docs.attribute(0).addStringValue(content);
docs.add(new SparseInstance(1.0, newInst));
sentences.put(sentences.size(), content);
clustering.put(clustering.size(), -1);
}
NGramTokenizer tokenizer = new NGramTokenizer();
tokenizer.setNGramMinSize(10);
tokenizer.setNGramMaxSize(10);
tokenizer.setDelimiters("\\W");
filter.setTokenizer(tokenizer);
filter.setInputFormat(docs);
filter.setLowerCaseTokens(true);
filter.setWordsToKeep(1);
Instances filteredData = Filter.useFilter(docs, filter);
kmeans.setPreserveInstancesOrder(true);
kmeans.setNumClusters(numberCluster);
kmeans.buildClusterer(filteredData);
int[] assignments = kmeans.getAssignments();
int i = 0;
for (int clusterNum : assignments) {
clustering.put(i, clusterNum);
i++;
}
PrintWriter[] pw = new PrintWriter[numberCluster];
for (int j = 0; j < numberCluster; j++) {
pw[j] = new PrintWriter(new File("results/result" + j + ".txt"));
}
sentences.entrySet().stream().forEach((entry) -> {
Integer key = entry.getKey();
String value = entry.getValue();
Integer cluster = clustering.get(key);
pw[cluster].println(value);
});
for (int j = 0; j < numberCluster; j++) {
pw[j].close();
}
} catch (Exception e) {
System.out.println("Error K means " + e);
}
}
When I change the order of the input file, the clustering results also vary.
Can you help me fix it. Thanks you so much.
k-means is a randomized algorithm.
It picks some instances as initial seeds, then searches for a local optimum.
So of course it will produce different results!
If they vary a lot, this indicates it did not work well. If your data is good for k-means, then most runs will produce very similar results (except for permutation of labels).
I am trying to populate a list view from an ArrayList but for some reason it only grabs the last record. The array holds the data correctly and if I change the I to a number it will print the selected value.
My code is below any help would be appreciated.
ArrayList<String> tests = new ArrayList();
for(HashMap<String, String> test : outageData){
String outagenumber = test.get("outagenum");
Log.v("Outage",outagenumber);
tests.add(outagenumber);
}
SectionListItem[] exampleArray = null;
for(int i = 0; i < tests.size(); i++) {
exampleArray = new SectionListItem[]{
new SectionListItem("test", tests.get(i)),
};
}
CustomOutageDetailListAdapter adapter = new CustomOutageDetailListAdapter(this, exampleArray);
sectionAdapter = new SectionListAdapter(getLayoutInflater(),
adapter);
This is the adapter for fill List.
public class SectionOutageListItem {
public Object item;
public String section;
public SectionOutageListItem(final Object item, final String section) {
super();
this.item = item;
this.section = section;
}
#Override
public String toString() {
return item.toString();
}
}
Updated Code:
SectionOutageListItem[] exampleArray = new SectionOutageListItem[outnums.size()];
for(int i = 0; i < outnums.size(); i++) {
exampleArray[i] =
new SectionOutageListItem("Impact", impacted.get(i), "Outage No. " + outnums.get(i)),
new SectionOutageListItem("status", status.get(i), "Outage No. " + outnums.get(i));
}
CustomOutageDetailListAdapter adapter = new CustomOutageDetailListAdapter(this, exampleArray);
sectionAdapter = new SectionOutageListAdapter(getLayoutInflater(),
adapter);
The issue is here:
for(int i = 0; i < tests.size(); i++) {
exampleArray = new SectionListItem[]{
new SectionListItem("test", tests.get(i)),
};
}
For each element in tests, you are creating a new exampleArray with a single item.
You should use:
SectionListItem[] exampleArray = new SectionListItem[tests.size()];
for(int i = 0; i < tests.size(); i++) {
exampleArray[i] = new SectionListItem("test", tests.get(i)),
}
Update this code:
SectionListItem[] exampleArray = null;
for(int i = 0; i < tests.size(); i++) {
exampleArray = new SectionListItem[]{
new SectionListItem("test", tests.get(i)),
};
}
with:
SectionListItem[] exampleArray = new SectionListItem[tests.size()];
for(int i = 0; i < tests.size(); i++) {
exampleArray[i]= new SectionListItem("test", tests.get(i));
}
I am calling a RPGIV program from java, the rpgiv program returnes multi record as an output parameter.
I tried the following to return all the rows returned from rpgiv.
// Define Output Data Structure
AS400DataType[] outputData =
{
new AS400Text(20), // parentOperationsItemId;
new AS400Text(10), // parentOperationsItemType;
new AS400Text(10), // parentOperationsItemSubType;
new AS400Text(20), // parentKnownbyId;
new AS400Text(10), // parentInternalStatus;
new AS400Text(1), // parentLeafIndicator;
new AS400Text(20), // childOperationsItemId;
new AS400Text(10), // childOperationsItemType;
new AS400Text(10), // childOperationsItemSubType;
new AS400Text(20), // childKnownbyId;
new AS400Text(10), // childInternalStatus;
new AS400Text(1), // childLeafIndicator;
new AS400Text(10) // InternalStatus;
};
AS400Structure [] outputDataConverter2 = new AS400Structure[3];
outputDataConverter2[0] = new AS400Structure(outputData);
outputDataConverter2[1] = new AS400Structure(outputData);
outputDataConverter2[2] = new AS400Structure(outputData);
Object[] dataInputInformation =
{
sSqlSelect,
sFetchDirection,
sOperationsItemId,
sparentOperationsItemTypeList,
sparentOperationsItemSubTpeList,
sparentInternalStatusList,
schildOperationsItemType,
schildOperationsItemSubTpeList,
schildInternalStatusList,
sLinkStatus
};
Object[] dataInputInformationControl =
{
sPosition,
new BigDecimal(sRowsFetched)
};
// Set up the parameter list
ProgramParameter[] parameterList = new ProgramParameter[4];
parameterList[0] = new ProgramParameter(7); //ReturnStatus
parameterList[1] = new ProgramParameter(inputDataConverter.toBytes(dataInputInformation)); //Input
parameterList[2] = new ProgramParameter(inputDataControlConverter.toBytes(dataInputInformationControl)); //Control
parameterList[3] = new ProgramParameter(outputDataConverter2[0].getByteLength()*3); //Output
try
{
// Set the program name and parameter list.
program.setProgram(programName, parameterList);
// Run Function
if (program.run() != true)
{
// Calling Error
AS400Message[] messagelist = program.getMessageList();
for (int i = 0; i < messagelist.length; ++i)
{
output[0].ReturnStatus += messagelist[i] + "\n";
}
}
else
{
// Set the output
output[0] = new GetPlannedRoute();
output[1] = new GetPlannedRoute();
output[2] = new GetPlannedRoute();
output[0].SetOutput(parameterList, outputDataConverter2[0]);
output[1].SetOutput(parameterList, outputDataConverter2[1]);
output[2].SetOutput(parameterList, outputDataConverter2[2]);
}
}
This is in the output class
public void SetOutput(ProgramParameter[] parameterList, AS400Structure outputPlannedRouteConverter)
{
ReturnStatus = P6Entity.CallingRPGFunction.ConvertReturnStatus(parameterList[0]);
Object[] outputData = (Object[]) outputPlannedRouteConverter.toObject(parameterList[3].getOutputData());
parentOperationsItemId = ((String) outputData[0]).trim();
parentOperationsItemType = ((String) outputData[1]).trim();
parentOperationsItemSubType = ((String) outputData[2]).trim();
parentKnownbyId = ((String) outputData[3]).trim();
parentInternalStatus = ((String) outputData[4]).trim();
parentLeafIndicator = ((String) outputData[5]).trim();
childOperationsItemId = ((String) outputData[6]).trim();
childOperationsItemType = ((String) outputData[7]).trim();
childOperationsItemSubType = ((String) outputData[8]).trim();
childKnownbyId = ((String) outputData[9]).trim();
childInternalStatus = ((String) outputData[10]).trim();
childLeafIndicator = ((String) outputData[11]).trim();
InternalStatus = ((String) outputData[12]).trim();
}
I am not sure how to define parameterList[3] to be able to receive multiple rows back or multiple data structures. And how to get a specific instance of the output parameterList[3].
The RPGIV code:
https://www.dropbox.com/s/a29wf1ft0f07sx1/functionCode.txt?dl=0
The * FetchedData Occures OCCURS(64) INZ is the output data set that I want to return to java.
Edited to show how to convert a packed value.
Let's cut this down a bit. Here is a small RPG program that has a similar structure to yours:
D V00001 DS OCCURS(64)
D F0000G 20A
D F0000H 10A
D F0000I 10A
D F0000J 20A
D F0000K 9p 0
D F0000L 1A
D F0000M 20A
D F0000N 10A
D F0000O 10A
D F0000P 20A
D F0000Q 10A
D F0000R 1A
D F0000S 10A
c *entry plist
c parm v00001
// populate the first entry
%occur(v00001) = 1;
F0000G = *ALL'1234567890';
F0000H = *ALL'A';
F0000I = *ALL'B';
F0000J = *ALL'C';
F0000K = 123456789;
F0000L = *ALL'E';
F0000M = *ALL'F';
F0000N = *ALL'G';
F0000O = *ALL'H';
F0000P = *ALL'I';
F0000Q = *ALL'J';
F0000R = *ALL'K';
F0000S = *ALL'a';
// populate the 2nd entry
%occur(v00001) = 2;
F0000G = *ALL'1234567890';
F0000H = *ALL'1234567890';
F0000I = *ALL'1234567890';
F0000J = *ALL'1234567890';
F0000K = 200;
F0000L = *ALL'1234567890';
F0000M = *ALL'1234567890';
F0000N = *ALL'1234567890';
F0000O = *ALL'1234567890';
F0000P = *ALL'1234567890';
F0000Q = *ALL'1234567890';
F0000R = *ALL'1234567890';
F0000S = *ALL'b';
// populate the third entry
%occur(v00001) = 3;
F0000G = *ALL'1234567890';
F0000H = *ALL'1234567890';
F0000I = *ALL'1234567890';
F0000J = *ALL'1234567890';
F0000K = 300;
F0000L = *ALL'1234567890';
F0000M = *ALL'1234567890';
F0000N = *ALL'1234567890';
F0000O = *ALL'1234567890';
F0000P = *ALL'1234567890';
F0000Q = *ALL'1234567890';
F0000R = *ALL'1234567890';
F0000S = *ALL'c';
// reset back to the beginning
%occur(v00001) = 1;
dump(a);
*inlr = *on;
Here is the Java (I AM NOT A Java PROGRAMMER!) that successfully reads the various 'records':
public String testSO(AS400 system, String programName) {
boolean success = false;
final int ONE_ROW_LEN = 147;
final int DS_ROWS = 64;
AS400Text dsText = new AS400Text(ONE_ROW_LEN * DS_ROWS);
AS400Text p0000g = new AS400Text(20);
AS400Text p0000h = new AS400Text(10);
AS400Text p0000i = new AS400Text(10);
AS400Text p0000j = new AS400Text(20);
int p0000k; // packed(9, 0) is 5 bytes
AS400Text p0000l = new AS400Text( 1);
AS400Text p0000m = new AS400Text(20);
AS400Text p0000n = new AS400Text(10);
AS400Text p0000o = new AS400Text(10);
AS400Text p0000p = new AS400Text(20);
AS400Text p0000q = new AS400Text(10);
AS400Text p0000r = new AS400Text( 1);
AS400Text p0000s = new AS400Text(10);
String ds = null;
String returnString = null;
try
{
ProgramCall program = new ProgramCall(system);
// Set up the parameter list
ProgramParameter[] parameterList = new ProgramParameter[1];
parameterList[0] = new ProgramParameter(ONE_ROW_LEN * DS_ROWS);
program.setProgram(programName, parameterList);
success = program.run();
if(success!=true){
AS400Message[] messagelist = program.getMessageList();
System.out.println("\nMessages received:\n");
for (int i = 0; i < messagelist.length; i++) {
System.out.println(messagelist[i]);
}
} else {
// RPG is returning a giant chunk of memory
//allBytes = parameterList[0].getOutputData();
ds = (String)dsText.toObject(parameterList[0].getOutputData());
System.out.println("ds=" + ds);
System.out.println("ds len=" + ds.length());
// Need to index our way into the block of memory
// zero-based!
int row = 0;
int x = row * ONE_ROW_LEN;
System.out.println("x=" + x);
// parse out the individual elements for this row
int len = p0000g.getByteLength();
String s0000g = ds.substring(x, x+len);
x += len;
len = p0000h.getByteLength();
String s0000h = ds.substring(x, x+len);
x += len;
len = p0000i.getByteLength();
String s0000i = ds.substring(x, x+len);
x += len;
len = p0000j.getByteLength();
String s0000j = ds.substring(x, x+len);
// this is packed(9, 0)
x += len;
len = 5;
byte[] b0000k = dsText.toBytes(ds.substring(x, x+len));
BigDecimal d0000k = (BigDecimal)new AS400PackedDecimal(9, 0).toObject(b0000k);
p0000k = d0000k.intValue();
String s0000k = d0000k.toString();
x += len;
len = p0000l.getByteLength();
String s0000l = ds.substring(x, x+len);
x += len;
len = p0000m.getByteLength();
String s0000m = ds.substring(x, x+len);
x += len;
len = p0000n.getByteLength();
String s0000n = ds.substring(x, x+len);
x += len;
len = p0000o.getByteLength();
String s0000o = ds.substring(x, x+len);
x += len;
len = p0000p.getByteLength();
String s0000p = ds.substring(x, x+len);
x += len;
len = p0000q.getByteLength();
String s0000q = ds.substring(x, x+len);
x += len;
len = p0000r.getByteLength();
String s0000r = ds.substring(x, x+len);
x += len;
len = p0000s.getByteLength();
String s0000s = ds.substring(x, x+len);
returnString = s0000s;
System.out.println("Return=" + returnString);
System.out.println("g=" + s0000g);
System.out.println("h=" + s0000h);
System.out.println("i=" + s0000i);
System.out.println("i=" + s0000i);
System.out.println("j=" + s0000j);
System.out.println("k=" + s0000k);
System.out.println("l=" + s0000l);
System.out.println("m=" + s0000m);
System.out.println("n=" + s0000n);
System.out.println("o=" + s0000o);
System.out.println("p=" + s0000p);
System.out.println("q=" + s0000q);
System.out.println("r=" + s0000r);
System.out.println("r=" + s0000s);
}
} catch (Exception e) {
System.out.println("\ne:\n");
System.out.println(e);
System.out.println("\nStack trace:\n");
e.printStackTrace();
}
return returnString;
}
The key part to understand in the Java are that with this design, Parameter.getOutputData() is returning byte[]. I am not a Java programmer, so my Java code is ugly. I cast the returned byte[] to String and assigned it as a block to ds. I then brute-forced a section of code that substrings out the individual variables one by one. If I knew more Java I'd probably have put that junk in a constructor and maybe exposed it as a List.
Having posted all that, there is no way I would operate this way with production code. I would have the IBM programmers write me a wrapper around the SuperUltimateBlockFetch - that wrapper would call SuperUltimateBlockFetch and build a result set for use by Java. They could even make it into a stored procedure. This would decouple your dependence on understanding the internals of how the RPG structure is built and make it much more natural to deal with the individual variables in the Java code. Then all you would do would be to call the stored procedure and write a while rs.next() loop.
I would suggest that you not try to pass the data as parameters.
Instead, use a data queue to pass the data back.
Have the java program create a data queue and pass it's name to the RPG program as a parameter.
The RPG program would then send the data to the queue using the QSNDDTAQ API.
When control returns to the Java program, have it read the entries from the data queue.
In my Java Project, i want to read values from txt file to List method.Values seems like;
1 kjhjhhkj 788
4 klkkld3 732
89 jksdsdsd 23
Number of row changable. I have tried this codes and getting same values in all indexes.
What can i do?
String[] dizi = new String[3];
List<String[]> listOfLists = new ArrayList<String[]>();
File f = new File("input.txt");
try {
Scanner s = new Scanner(f);
while (s.hasNextLine()) {
int i = 0;
while (s.hasNext() && i < 3) {
dizi[i] = s.next();
i++;
}
listOfLists.add(dizi);
}
} catch (FileNotFoundException e) {
System.out.println("Dosyaya ba?lanmaya çal???l?rken hata olu?tu");
}
int q = listOfLists.size();
for (int z = 0; z < q; z++) {
for (int k = 0; k < 3; k++) {
System.out.print(listOfLists.get(z)[k] + " ");
}
}
String [] dizi = new String [3];
dizi is a global variable getting overridden eveytime in the loop. Thats why you are getting same values at all indexes
Make a new instance everytime before adding to the list.
You put the same reference to the list, create a new array in while loop.
while (s.hasNextLine()){
String[] dizi = new String[3]; //new array
int i = 0;
while (s.hasNext() && i < 3)
{
dizi[i] = s.next();
i++;
}
listOfLists.add(dizi);
}
I apologize for asking such a question, but I am lost and cannot figure out what to do.
I am reading the book Beginning Android Games 2nd Edition. I actually finished reading the book just today. I planned on making my own small 3D Game, just to test my knowledge. Well, my issue is that the ObjLoader that we made for the framework in the book won't show my .obj file. It either just crashes, shows some triangles, or fills have the screen a grayish color. I have tried making these .obj files in AutoDesk Maya 2013, Wings 3D, and Blender. But none of them show my object I designed. Even just a simple cube. Again, I'm sorry for asking such a question, but I would like to know if there is something special I need to do during exporting to get this ObjLoader to load it? I know for a fact that I am doing the loading correct. It works for the .obj provided. Here is the ObjLoader's code(straight from the book). Thanks in advance.
package com.badlogic.androidgames.framework.gl;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import com.badlogic.androidgames.framework.impl.GLGame;
public class ObjLoader {
public static Vertices3 load(GLGame game, String file) {
InputStream in = null;
try {
in = game.getFileIO().readAsset(file);
List<String> lines = readLines(in);
float[] vertices = new float[lines.size() * 3];
float[] normals = new float[lines.size() * 3];
float[] uv = new float[lines.size() * 2];
int numVertices = 0;
int numNormals = 0;
int numUV = 0;
int numFaces = 0;
int[] facesVerts = new int[lines.size() * 3];
int[] facesNormals = new int[lines.size() * 3];
int[] facesUV = new int[lines.size() * 3];
int vertexIndex = 0;
int normalIndex = 0;
int uvIndex = 0;
int faceIndex = 0;
for (int i = 0; i < lines.size(); i++) {
String line = lines.get(i);
if (line.startsWith("v ")) {
String[] tokens = line.split("[ ]+");
vertices[vertexIndex] = Float.parseFloat(tokens[1]);
vertices[vertexIndex + 1] = Float.parseFloat(tokens[2]);
vertices[vertexIndex + 2] = Float.parseFloat(tokens[3]);
vertexIndex += 3;
numVertices++;
continue;
}
if (line.startsWith("vn ")) {
String[] tokens = line.split("[ ]+");
normals[normalIndex] = Float.parseFloat(tokens[1]);
normals[normalIndex + 1] = Float.parseFloat(tokens[2]);
normals[normalIndex + 2] = Float.parseFloat(tokens[3]);
normalIndex += 3;
numNormals++;
continue;
}
if (line.startsWith("vt")) {
String[] tokens = line.split("[ ]+");
uv[uvIndex] = Float.parseFloat(tokens[1]);
uv[uvIndex + 1] = Float.parseFloat(tokens[2]);
uvIndex += 2;
numUV++;
continue;
}
if (line.startsWith("f ")) {
String[] tokens = line.split("[ ]+");
String[] parts = tokens[1].split("/");
facesVerts[faceIndex] = getIndex(parts[0], numVertices);
if (parts.length > 2)
facesNormals[faceIndex] = getIndex(parts[2], numNormals);
if (parts.length > 1)
facesUV[faceIndex] = getIndex(parts[1], numUV);
faceIndex++;
parts = tokens[2].split("/");
facesVerts[faceIndex] = getIndex(parts[0], numVertices);
if (parts.length > 2)
facesNormals[faceIndex] = getIndex(parts[2], numNormals);
if (parts.length > 1)
facesUV[faceIndex] = getIndex(parts[1], numUV);
faceIndex++;
parts = tokens[3].split("/");
facesVerts[faceIndex] = getIndex(parts[0], numVertices);
if (parts.length > 2)
facesNormals[faceIndex] = getIndex(parts[2], numNormals);
if (parts.length > 1)
facesUV[faceIndex] = getIndex(parts[1], numUV);
faceIndex++;
numFaces++;
continue;
}
}
float[] verts = new float[(numFaces * 3)
* (3 + (numNormals > 0 ? 3 : 0) + (numUV > 0 ? 2 : 0))];
for (int i = 0, vi = 0; i < numFaces * 3; i++) {
int vertexIdx = facesVerts[i] * 3;
verts[vi++] = vertices[vertexIdx];
verts[vi++] = vertices[vertexIdx + 1];
verts[vi++] = vertices[vertexIdx + 2];
if (numUV > 0) {
int uvIdx = facesUV[i] * 2;
verts[vi++] = uv[uvIdx];
verts[vi++] = 1 - uv[uvIdx + 1];
}
if (numNormals > 0) {
int normalIdx = facesNormals[i] * 3;
verts[vi++] = normals[normalIdx];
verts[vi++] = normals[normalIdx + 1];
verts[vi++] = normals[normalIdx + 2];
}
}
Vertices3 model = new Vertices3(game.getGLGraphics(), numFaces * 3,
0, false, numUV > 0, numNormals > 0);
model.setVertices(verts, 0, verts.length);
return model;
} catch (Exception ex) {
throw new RuntimeException("couldn't load '" + file + "'", ex);
} finally {
if (in != null)
try {
in.close();
} catch (Exception ex) {
}
}
}
static int getIndex(String index, int size) {
int idx = Integer.parseInt(index);
if (idx < 0)
return size + idx;
else
return idx - 1;
}
static List<String> readLines(InputStream in) throws IOException {
List<String> lines = new ArrayList<String>();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = null;
while ((line = reader.readLine()) != null)
lines.add(line);
return lines;
}
}