package com.telenav;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import org.lwjgl.BufferUtils;
import static org.lwjgl.opengl.GL11.*;
public class GLM {
public static final float M_PI = 3.14159265f;
public static final int GLM_NONE = 0; /* render with only vertices */
public static final int GLM_FLAT = 1 << 0; /* render with facet normals */
public static final int GLM_SMOOTH = 1 << 1; /* render with vertex normals */
public static final int GLM_TEXTURE = 1 << 2; /* render with texture coords */
public static final int GLM_COLOR = 1 << 3; /* render with colors */
public static final int GLM_MATERIAL = 1 << 4; /* render with materials */
/*
* GLMmaterial: Structure that defines a material in a model.
*/
public class GLMmaterial {
public String name; /* name of material */
public float[] diffuse = new float[4]; /* diffuse component */
public float[] ambient = new float[4]; /* ambient component */
public float[] specular = new float[4]; /* specular component */
public float[] emmissive = new float[4]; /* emmissive component */
public float shininess; /* specular exponent */
}
/*
* GLMtriangle: Structure that defines a triangle in a model.
*/
public class GLMtriangle {
public int[] vindices = new int[3]; /* array of triangle vertex indices */
public int[] nindices = new int[3]; /* array of triangle normal indices */
public int[] tindices = new int[3]; /*
* array of triangle texcoord
* indices
*/
public int findex; /* index of triangle facet normal */
}
/*
* GLMgroup: Structure that defines a group in a model.
*/
public class GLMgroup {
public String name; /* name of this group */
public ArrayList<Integer> triangles = new ArrayList<Integer>(); /*
* array
* of
* triangle
* indices
*/
public int material; /* index to material for group */
}
/*
* GLMmodel: Structure that defines a model.
*/
public class GLMmodel {
public String pathname; /* path to this model */
public String mtllibname; /* name of the material library */
public ArrayList<float[]> vertices = new ArrayList<float[]>(); /*
* array
* of
* vertices
*/
public ArrayList<float[]> normals = new ArrayList<float[]>(); /*
* array of
* normals
*/
public ArrayList<float[]> texcoords = new ArrayList<float[]>(); /*
* array
* of
* texture
* coordinates
*/
public ArrayList<float[]> facetnorms = new ArrayList<float[]>(); /*
* array
* of
* facetnorms
*/
public ArrayList<GLMtriangle> triangles = new ArrayList<GLMtriangle>(); /*
* array
* of
* triangles
*/
public ArrayList<GLMmaterial> materials = new ArrayList<GLMmaterial>(); /*
* array
* of
* materials
*/
public ArrayList<GLMgroup> groups = new ArrayList<GLMgroup>(); /*
* linked
* list
* of
* groups
*/
public float[] position = new float[3]; /* position of the model */
}
/* _GLMnode: general purpose node */
public class GLMnode {
public int index;
public boolean averaged;
public GLMnode next;
}
/* glmMax: returns the maximum of two floats */
public static float glmMax(float a, float b) {
if (b > a)
return b;
return a;
}
/* glmAbs: returns the absolute value of a float */
public static float glmAbs(float f) {
if (f < 0)
return -f;
return f;
}
/*
* glmDot: compute the dot product of two vectors
*
* u - array of 3 floats (float u[3]) v - array of 3 floats (float v[3])
*/
public static float glmDot(float[] u, float[] v) {
return u[0] * v[0] + u[1] * v[1] + u[2] * v[2];
}
/*
* glmCross: compute the cross product of two vectors
*
* u - array of 3 floats (float u[3]) v - array of 3 floats (float v[3]) n -
* array of 3 floats (float n[3]) to return the cross product in
*/
public static float[] glmCross(float[] u, float[] v) {
float[] n = new float[3];
n[0] = u[1] * v[2] - u[2] * v[1];
n[1] = u[2] * v[0] - u[0] * v[2];
n[2] = u[0] * v[1] - u[1] * v[0];
return n;
}
/*
* glmNormalize: normalize a vector
*
* v - array of 3 floats (float v[3]) to be normalized
*/
public static float[] glmNormalize(float[] v) {
float l;
l = (float) Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
v[0] /= l;
v[1] /= l;
v[2] /= l;
return v;
}
/*
* glmEqual: compares two vectors and returns GL_TRUE if they are equal
* (within a certain threshold) or GL_FALSE if not. An epsilon that works
* fairly well is 0.000001.
*
* u - array of 3 floats (float u[3]) v - array of 3 floats (float v[3])
*/
public static boolean glmEqual(float[] u, float[] v, float epsilon) {
if (glmAbs(u[0] - v[0]) < epsilon && glmAbs(u[1] - v[1]) < epsilon && glmAbs(u[2] - v[2]) < epsilon) {
return true;
}
return false;
}
/*
* glmWeldVectors: eliminate (weld) vectors that are within an epsilon of
* each other.
*
* vectors - array of float[3]'s to be welded numvectors - number of
* float[3]'s in vectors epsilon - maximum difference between vectors
*/
public float[] glmWeldVectors(float[] vectors, int numvectors, float epsilon) {
float[] copies;
int copied;
int i, j;
copies = new float[(numvectors + 1) * 3];
System.arraycopy(vectors, 0, copies, 0, (numvectors + 1) * 3);
copied = 1;
boolean duplicate = false;
for (i = 1; i <= numvectors; i++) {
for (j = 1; j <= copied; j++) {
if (glmEqual(new float[] { vectors[3 * i], vectors[3 * (i + 1)], vectors[3 * (i + 2)] }, new float[] {
copies[3 * j], copies[3 * (j + 1)], copies[3 * (j + 2)] }, epsilon)) {
duplicate = true;
/*
* set the first component of this vector to point at the
* correct index into the new copies array
*/
vectors[3 * i + 0] = (float) j;
break;
}
}
if (duplicate) {
duplicate = false;
continue;
}
/* must not be any duplicates -- add to the copies array */
copies[3 * copied + 0] = vectors[3 * i + 0];
copies[3 * copied + 1] = vectors[3 * i + 1];
copies[3 * copied + 2] = vectors[3 * i + 2];
j = copied; /* pass this along for below */
copied++;
}
numvectors = copied - 1;
return copies;
}
/* glmFindGroup: Find a group in the model */
public GLMgroup glmFindGroup(GLMmodel model, String name) {
ArrayList<GLMgroup> groups = model.groups;
for (GLMgroup group : groups) {
if (name.equals(group.name)) {
return group;
}
}
return null;
}
/* glmAddGroup: Add a group to the model */
public GLMgroup glmAddGroup(GLMmodel model, String name) {
GLMgroup group = glmFindGroup(model, name);
if (group == null) {
group = new GLMgroup();
group.name = name;
group.material = 0;
model.groups.add(group);
}
return group;
}
/* glmFindGroup: Find a material in the model */
public int glmFindMaterial(GLMmodel model, String name) {
int i;
/*
* XXX doing a linear search on a string key'd list is pretty lame, but
* it works and is fast enough for now.
*/
for (i = 0; i < model.materials.size(); i++) {
if (model.materials.get(i).name.equals(name)) {
return i;
}
}
return 0;
}
/*
* glmReadMTL: read a wavefront material library file
*
* model - properly initialized GLMmodel structure name - name of the
* material library
*/
public void glmReadMTL(GLMmodel model, String name) throws Exception {
GLMmaterial material = null;
FileInputStream fis = new FileInputStream(new File(model.pathname).getParent() + File.separator + name);
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
String line;
while (true) {
line = br.readLine();
if (line == null) {
if (material != null) {
model.materials.add(material);
}
break;
}
line = line.trim();
if (line.startsWith("#")) {
continue;
} else if (line.startsWith("newmtl")) {
if (material != null) {
model.materials.add(material);
}
material = new GLMmaterial();
material.name = line.substring("newmtl".length()).trim();
material.shininess = 65.0f;
material.diffuse[0] = 0.8f;
material.diffuse[1] = 0.8f;
material.diffuse[2] = 0.8f;
material.diffuse[3] = 1.0f;
material.ambient[0] = 0.2f;
material.ambient[1] = 0.2f;
material.ambient[2] = 0.2f;
material.ambient[3] = 1.0f;
material.specular[0] = 0.0f;
material.specular[1] = 0.0f;
material.specular[2] = 0.0f;
material.specular[3] = 1.0f;
} else if (line.startsWith("Ns")) {
/* wavefront shininess is from [0, 1000], so scale for OpenGL */
material.shininess = Float.valueOf(line.substring("Ns".length()).trim());
material.shininess /= 1000.0;
material.shininess *= 128.0;
} else if (line.startsWith("Kd")) {
material.diffuse[0] = Float.valueOf(line.substring("Kd".length()).trim().split(" ")[0]);
material.diffuse[1] = Float.valueOf(line.substring("Kd".length()).trim().split(" ")[1]);
material.diffuse[2] = Float.valueOf(line.substring("Kd".length()).trim().split(" ")[2]);
} else if (line.startsWith("Ks")) {
material.specular[0] = Float.valueOf(line.substring("Ks".length()).trim().split(" ")[0]);
material.specular[1] = Float.valueOf(line.substring("Ks".length()).trim().split(" ")[1]);
material.specular[2] = Float.valueOf(line.substring("Ks".length()).trim().split(" ")[2]);
} else if (line.startsWith("Ka")) {
material.ambient[0] = Float.valueOf(line.substring("Ka".length()).trim().split(" ")[0]);
material.ambient[1] = Float.valueOf(line.substring("Ka".length()).trim().split(" ")[1]);
material.ambient[2] = Float.valueOf(line.substring("Ka".length()).trim().split(" ")[2]);
}
}
}
/*
* glmWriteMTL: write a wavefront material library file
*
* model - properly initialized GLMmodel structure modelpath - pathname of
* the model being written mtllibname - name of the material library to be
* written
*/
public void glmWriteMTL(GLMmodel model, String modelpath, String mtllibname) throws Exception {
FileOutputStream fos = new FileOutputStream(new File(modelpath).getParent() + File.separator + mtllibname);
StringBuffer sb = new StringBuffer();
sb.append("# \n");
sb.append("# Wavefront MTL generated by GLM library\n");
sb.append("# \n");
sb.append("# GLM library\n");
sb.append("# Nate Robins\n");
sb.append("# http://www.pobox.com/~ndr\n");
sb.append("# \n\n");
for (GLMmaterial material : model.materials) {
sb.append("newmtl " + material.name + "\n");
sb.append("Ka " + material.ambient[0] + " " + material.ambient[1] + " " + material.ambient[2] + "\n");
sb.append("Kd " + material.diffuse[0] + " " + material.diffuse[1] + " " + material.diffuse[2] + "\n");
sb.append("Ks " + material.specular[0] + " " + material.specular[1] + " " + material.specular[2] + "\n");
sb.append("Ns " + (material.shininess/ 128.0 * 1000.0) + "\n\n");
}
fos.write(sb.toString().getBytes());
fos.flush();
fos.close();
}
/*
* glmUnitize: "unitize" a model by translating it to the origin and scaling
* it to fit in a unit cube around the origin. Returns the scalefactor used.
*
* model - properly initialized GLMmodel structure
*/
public float glmUnitize(GLMmodel model) {
int i;
float maxx, minx, maxy, miny, maxz, minz;
float cx, cy, cz, w, h, d;
float scale;
/* get the max/mins */
maxx = minx = model.vertices.get(0)[0];
maxy = miny = model.vertices.get(0)[1];
maxz = minz = model.vertices.get(0)[2];
for (i = 1; i < model.vertices.size(); i++) {
if (maxx < model.vertices.get(i)[0])
maxx = model.vertices.get(i)[0];
if (minx > model.vertices.get(i)[0])
minx = model.vertices.get(i)[0];
if (maxy < model.vertices.get(i)[1])
maxy = model.vertices.get(i)[1];
if (miny > model.vertices.get(i)[1])
miny = model.vertices.get(i)[1];
if (maxz < model.vertices.get(i)[2])
maxz = model.vertices.get(i)[2];
if (minz > model.vertices.get(i)[2])
minz = model.vertices.get(i)[2];
}
/* calculate model width, height, and depth */
w = glmAbs(maxx) + glmAbs(minx);
h = glmAbs(maxy) + glmAbs(miny);
d = glmAbs(maxz) + glmAbs(minz);
/* calculate center of the model */
cx = (maxx + minx) / 2.0f;
cy = (maxy + miny) / 2.0f;
cz = (maxz + minz) / 2.0f;
/* calculate unitizing scale factor */
scale = 2.0f / glmMax(glmMax(w, h), d);
/* translate around center then scale */
for (i = 1; i < model.vertices.size(); i++) {
model.vertices.get(i)[0] -= cx;
model.vertices.get(i)[1] -= cy;
model.vertices.get(i)[2] -= cz;
model.vertices.get(i)[0] *= scale;
model.vertices.get(i)[1] *= scale;
model.vertices.get(i)[2] *= scale;
}
return scale;
}
/*
* glmDimensions: Calculates the dimensions (width, height, depth) of a
* model.
*
* model - initialized GLMmodel structure dimensions - array of 3 floats
* (float dimensions[3])
*/
public float[] glmDimensions(GLMmodel model, float[] dimensions) {
int i;
float maxx, minx, maxy, miny, maxz, minz;
/* get the max/mins */
maxx = minx = model.vertices.get(0)[0];
maxy = miny = model.vertices.get(0)[1];
maxz = minz = model.vertices.get(0)[2];
for (i = 1; i <= model.vertices.size(); i++) {
if (maxx < model.vertices.get(i)[0])
maxx = model.vertices.get(i)[0];
if (minx > model.vertices.get(i)[0])
minx = model.vertices.get(i)[0];
if (maxy < model.vertices.get(i)[1])
maxy = model.vertices.get(i)[1];
if (miny > model.vertices.get(i)[1])
miny = model.vertices.get(i)[1];
if (maxz < model.vertices.get(i)[2])
maxz = model.vertices.get(i)[2];
if (minz > model.vertices.get(i)[2])
minz = model.vertices.get(i)[2];
}
/* calculate model width, height, and depth */
dimensions[0] = glmAbs(maxx) + glmAbs(minx);
dimensions[1] = glmAbs(maxy) + glmAbs(miny);
dimensions[2] = glmAbs(maxz) + glmAbs(minz);
return dimensions;
}
/*
* glmScale: Scales a model by a given amount.
*
* model - properly initialized GLMmodel structure scale - scalefactor (0.5
* = half as large, 2.0 = twice as large)
*/
public void glmScale(GLMmodel model, float scale) {
int i;
for (i = 1; i <= model.vertices.size(); i++) {
model.vertices.get(i)[0] *= scale;
model.vertices.get(i)[1] *= scale;
model.vertices.get(i)[2] *= scale;
}
}
/*
* glmReverseWinding: Reverse the polygon winding for all polygons in this
* model. Default winding is counter-clockwise. Also changes the direction
* of the normals.
*
* model - properly initialized GLMmodel structure
*/
public void glmReverseWinding(GLMmodel model) {
int i, swap;
for (i = 0; i < model.triangles.size(); i++) {
swap = model.triangles.get(i).vindices[0];
model.triangles.get(i).vindices[0] = model.triangles.get(i).vindices[2];
model.triangles.get(i).vindices[2] = swap;
if (model.normals.size() > 0) {
swap = model.triangles.get(i).nindices[0];
model.triangles.get(i).nindices[0] = model.triangles.get(i).nindices[2];
model.triangles.get(i).nindices[2] = swap;
}
if (model.texcoords.size() > 0) {
swap = model.triangles.get(i).tindices[0];
model.triangles.get(i).tindices[0] = model.triangles.get(i).tindices[2];
model.triangles.get(i).tindices[2] = swap;
}
}
/* reverse facet normals */
for (i = 1; i <= model.facetnorms.size(); i++) {
model.facetnorms.get(i)[0] = -model.facetnorms.get(i)[0];
model.facetnorms.get(i)[1] = -model.facetnorms.get(i)[1];
model.facetnorms.get(i)[2] = -model.facetnorms.get(i)[2];
}
/* reverse vertex normals */
for (i = 1; i <= model.normals.size(); i++) {
model.normals.get(i)[0] = -model.normals.get(i)[0];
model.normals.get(i)[1] = -model.normals.get(i)[1];
model.normals.get(i)[2] = -model.normals.get(i)[2];
}
}
/*
* glmFacetNormals: Generates facet normals for a model (by taking the cross
* product of the two vectors derived from the sides of each triangle).
* Assumes a counter-clockwise winding.
*
* model - initialized GLMmodel structure
*/
public void glmFacetNormals(GLMmodel model) {
int i;
float[] u = new float[3];
float[] v = new float[3];
/* clobber any old facetnormals */
model.facetnorms = new ArrayList<float[]>();
model.facetnorms.add(null);
for (i = 0; i < model.triangles.size(); i++) {
model.triangles.get(i).findex = i + 1;
u[0] = model.vertices.get(model.triangles.get(i).vindices[1])[0]
- model.vertices.get(model.triangles.get(i).vindices[0])[0];
u[1] = model.vertices.get(model.triangles.get(i).vindices[1])[1]
- model.vertices.get(model.triangles.get(i).vindices[0])[1];
u[2] = model.vertices.get(model.triangles.get(i).vindices[1])[2]
- model.vertices.get(model.triangles.get(i).vindices[0])[2];
v[0] = model.vertices.get(model.triangles.get(i).vindices[2])[0]
- model.vertices.get(model.triangles.get(i).vindices[0])[0];
v[1] = model.vertices.get(model.triangles.get(i).vindices[2])[1]
- model.vertices.get(model.triangles.get(i).vindices[0])[1];
v[2] = model.vertices.get(model.triangles.get(i).vindices[2])[2]
- model.vertices.get(model.triangles.get(i).vindices[0])[2];
float[] facenorm = glmCross(u, v);
facenorm = glmNormalize(facenorm);
model.facetnorms.add(facenorm);
}
}
/*
* glmVertexNormals: Generates smooth vertex normals for a model. First
* builds a list of all the triangles each vertex is in. Then loops through
* each vertex in the the list averaging all the facet normals of the
* triangles each vertex is in. Finally, sets the normal index in the
* triangle for the vertex to the generated smooth normal. If the dot
* product of a facet normal and the facet normal associated with the first
* triangle in the list of triangles the current vertex is in is greater
* than the cosine of the angle parameter to the function, that facet normal
* is not added into the average normal calculation and the corresponding
* vertex is given the facet normal. This tends to preserve hard edges. The
* angle to use depends on the model, but 90 degrees is usually a good
* start.
*
* model - initialized GLMmodel structure angle - maximum angle (in degrees)
* to smooth across
*/
public void glmVertexNormals(GLMmodel model, float angle) {
GLMnode node;
ArrayList<GLMnode> members;
int numnormals;
float[] average = new float[3];
float dot, cos_angle;
int i, avg;
/* calculate the cosine of the angle (in degrees) */
cos_angle = (float) Math.cos(angle * M_PI / 180.0);
/* nuke any previous normals */
model.normals = new ArrayList<float[]>();
for (i = 0; i < model.triangles.size() + 1; i++) {
model.normals.add(new float[] { 0, 0, 0 });
}
/*
* allocate a structure that will hold a linked list of triangle indices
* for each vertex
*/
members = new ArrayList<GLMnode>();
for (i = 0; i <= model.vertices.size(); i++) {
members.add(null);
}
/* for every triangle, create a node for each vertex in it */
for (i = 0; i < model.triangles.size(); i++) {
// f 3 4 1 2 341 312
node = new GLMnode();
node.index = i;
node.next = members.get(model.triangles.get(i).vindices[0]);
members.set(model.triangles.get(i).vindices[0], node);
node = new GLMnode();
node.index = i;
node.next = members.get(model.triangles.get(i).vindices[1]);
members.set(model.triangles.get(i).vindices[1], node);
node = new GLMnode();
node.index = i;
node.next = members.get(model.triangles.get(i).vindices[2]);
members.set(model.triangles.get(i).vindices[2], node);
}
/* calculate the average normal for each vertex */
numnormals = 1;
for (i = 1; i <= model.vertices.size(); i++) {
/*
* calculate an average normal for this vertex by averaging the
* facet normal of every triangle this vertex is in
*/
node = members.get(i);
if (node == null) {
System.out.println("glmVertexNormals(): vertex w/o a triangle\n");
}
average[0] = 0.0f;
average[1] = 0.0f;
average[2] = 0.0f;
avg = 0;
while (node != null) {
/*
* only average if the dot product of the angle between the two
* facet normals is greater than the cosine of the threshold
* angle -- or, said another way, the angle between the two
* facet normals is less than (or equal to) the threshold angle
*/
dot = glmDot(model.facetnorms.get(model.triangles.get(node.index).findex), model.facetnorms
.get(model.triangles.get(members.get(i).index).findex));
if (dot > cos_angle) {
node.averaged = true;
average[0] += model.facetnorms.get(model.triangles.get(node.index).findex)[0];
average[1] += model.facetnorms.get(model.triangles.get(node.index).findex)[1];
average[2] += model.facetnorms.get(model.triangles.get(node.index).findex)[2];
avg = 1; /* we averaged at least one normal! */
} else {
node.averaged = false;
}
node = node.next;
}
if (avg != 0) {
/* normalize the averaged normal */
average = glmNormalize(average);
/* add the normal to the vertex normals list */
model.normals.set(numnormals, new float[] { average[0], average[1], average[2] });
avg = numnormals;
numnormals++;
}
/* set the normal of this vertex in each triangle it is in */
node = members.get(i);
while (node != null) {
if (node.averaged) {
/* if this node was averaged, use the average normal */
if (model.triangles.get(node.index).vindices[0] == i)
model.triangles.get(node.index).nindices[0] = avg;
else if (model.triangles.get(node.index).vindices[1] == i)
model.triangles.get(node.index).nindices[1] = avg;
else if (model.triangles.get(node.index).vindices[2] == i)
model.triangles.get(node.index).nindices[2] = avg;
} else {
/* if this node wasn't averaged, use the facet normal */
model.normals.get(numnormals)[0] = model.facetnorms.get(model.triangles.get(node.index).findex)[0];
model.normals.get(numnormals)[1] = model.facetnorms.get(model.triangles.get(node.index).findex)[1];
model.normals.get(numnormals)[2] = model.facetnorms.get(model.triangles.get(node.index).findex)[2];
if (model.triangles.get(node.index).vindices[0] == i)
model.triangles.get(node.index).nindices[0] = numnormals;
else if (model.triangles.get(node.index).vindices[1] == i)
model.triangles.get(node.index).nindices[1] = numnormals;
else if (model.triangles.get(node.index).vindices[2] == i)
model.triangles.get(node.index).nindices[2] = numnormals;
numnormals++;
}
node = node.next;
}
}
numnormals--;
/*
* pack the normals array (we previously allocated the maximum number of
* normals that could possibly be created (numtriangles * 3), so get rid
* of some of them (usually alot unless none of the facet normals were
* averaged))
*/
// normals = model.normals;
// model.normals = new ArrayList<float[]>();
// for (i = 1; i <= numnormals; i++) {
// model.normals.add(normals.get(i));
// }
}
/*
* glmLinearTexture: Generates texture coordinates according to a linear
* projection of the texture map. It generates these by linearly mapping the
* vertices onto a square.
*
* model - pointer to initialized GLMmodel structure
*/
public void glmLinearTexture(GLMmodel model) {
float[] dimensions = new float[3];
float x, y, scalefactor;
int i;
model.texcoords = new ArrayList<float[]>();
dimensions = glmDimensions(model, dimensions);
scalefactor = (float) (2.0 / glmAbs(glmMax(glmMax(dimensions[0], dimensions[1]), dimensions[2])));
/* do the calculations */
for (i = 1; i <= model.vertices.size(); i++) {
x = model.vertices.get(i)[0] * scalefactor;
y = model.vertices.get(i)[2] * scalefactor;
model.texcoords.add(new float[] { (x + 1.0f) / 2.0f, (y + 1.0f) / 2.0f });
}
/* go through and put texture coordinate indices in all the triangles */
for (GLMgroup group : model.groups) {
for (i = 0; i < group.triangles.size(); i++) {
model.triangles.get(group.triangles.get(i)).tindices[0] = model.triangles.get(group.triangles.get(i)).vindices[0];
model.triangles.get(group.triangles.get(i)).tindices[1] = model.triangles.get(group.triangles.get(i)).vindices[1];
model.triangles.get(group.triangles.get(i)).tindices[2] = model.triangles.get(group.triangles.get(i)).vindices[2];
}
}
}
/*
* glmSpheremapTexture: Generates texture coordinates according to a
* spherical projection of the texture map. Sometimes referred to as
* spheremap, or reflection map texture coordinates. It generates these by
* using the normal to calculate where that vertex would map onto a sphere.
* Since it is impossible to map something flat perfectly onto something
* spherical, there is distortion at the poles. This particular
* implementation causes the poles along the X axis to be distorted.
*
* model - pointer to initialized GLMmodel structure
*/
public void glmSpheremapTexture(GLMmodel model) {
float theta, phi, rho, x, y, z, r;
int i;
model.texcoords = new ArrayList<float[]>();
for (i = 1; i <= model.normals.size(); i++) {
z = model.normals.get(i)[0]; /* re-arrange for pole distortion */
y = model.normals.get(i)[1];
x = model.normals.get(i)[2];
r = (float) Math.sqrt((x * x) + (y * y));
rho = (float) Math.sqrt((r * r) + (z * z));
if (r == 0.0) {
theta = 0.0f;
phi = 0.0f;
} else {
if (z == 0.0)
phi = 3.14159265f / 2.0f;
else
phi = (float) Math.acos(z / rho);
if (y == 0.0)
theta = 3.141592365f / 2.0f;
else
theta = (float) (Math.asin(y / r) + (3.14159265 / 2.0));
}
model.texcoords.add(new float[] { theta / 3.14159265f, phi / 3.14159265f });
}
/* go through and put texcoord indices in all the triangles */
for (GLMgroup group : model.groups) {
for (i = 0; i < group.triangles.size(); i++) {
model.triangles.get(group.triangles.get(i)).tindices[0] = model.triangles.get(group.triangles.get(i)).vindices[0];
model.triangles.get(group.triangles.get(i)).tindices[1] = model.triangles.get(group.triangles.get(i)).vindices[1];
model.triangles.get(group.triangles.get(i)).tindices[2] = model.triangles.get(group.triangles.get(i)).vindices[2];
}
}
}
/*
* glmReadOBJ: Reads a model description from a Wavefront .OBJ file. Returns
* a pointer to the created object which should be free'd with glmDelete().
*
* filename - name of the file containing the Wavefront .OBJ format data.
*/
public GLMmodel glmReadOBJ(String filename) throws Exception {
GLMmodel model;
File file = new File(filename);
/* allocate a new model */
model = new GLMmodel();
model.pathname = filename;
model.vertices.add(new float[] { 0, 0, 0 });
model.position[0] = 0.0f;
model.position[1] = 0.0f;
model.position[2] = 0.0f;
ArrayList<GLMmaterial> materialList = new ArrayList<GLMmaterial>();
GLMmaterial material = null;
FileInputStream fis = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
String line;
GLMgroup group = null;
int v, n, t;
while (true) {
line = br.readLine();
if (line == null) {
if (material != null) {
materialList.add(material);
}
break;
}
line = line.trim();
if (line.startsWith("#")) {
continue;
} else if (line.startsWith("m")) {
glmReadMTL(model, line.split(" ")[1]);
continue;
} else if (line.startsWith("v ")) {
/* vertex */
String[] vertexStrs = line.substring("v ".length()).trim().split(" ");
float[] vertex = new float[] { Float.valueOf(vertexStrs[0]), Float.valueOf(vertexStrs[1]),
Float.valueOf(vertexStrs[2]) };
model.vertices.add(vertex);
continue;
} else if (line.startsWith("vn")) {
/* normal */
String[] normalStrs = line.substring("vn".length()).trim().split(" ");
float[] normal = new float[] { Float.valueOf(normalStrs[0]), Float.valueOf(normalStrs[1]),
Float.valueOf(normalStrs[2]) };
model.normals.add(normal);
continue;
} else if (line.startsWith("vt")) {
/* texcoord */
String[] texcoordStrs = line.substring("vt".length()).trim().split(" ");
float[] texcoord = new float[] { Float.valueOf(texcoordStrs[0]), Float.valueOf(texcoordStrs[1]) };
model.texcoords.add(texcoord);
continue;
} else if (line.startsWith("g ") || line.startsWith("group")) {
String groupName = line.split(" ")[1];
group = glmFindGroup(model, groupName);
if (group == null) {
group = glmAddGroup(model, groupName);
}
continue;
} else if (line.startsWith("u")) {
String materialName = line.split(" ")[1];
group.material = glmFindMaterial(model, materialName);
continue;
} else if (line.startsWith("f")) {
/* face */
/* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */
String[] lineStrs = line.split(" ");
if (lineStrs[1].contains("//")) {
/* v//n */
GLMtriangle triangle = new GLMtriangle();
v = Integer.valueOf(lineStrs[1].split("//")[0]);
n = Integer.valueOf(lineStrs[1].split("//")[1]);
triangle.vindices[0] = v < 0 ? v + model.vertices.size() : v;
triangle.nindices[0] = n < 0 ? n + model.normals.size() : n;
v = Integer.valueOf(lineStrs[2].split("//")[0]);
n = Integer.valueOf(lineStrs[2].split("//")[1]);
triangle.vindices[1] = v < 0 ? v + model.vertices.size() : v;
triangle.nindices[1] = n < 0 ? n + model.normals.size() : n;
v = Integer.valueOf(lineStrs[3].split("//")[0]);
n = Integer.valueOf(lineStrs[3].split("//")[1]);
triangle.vindices[2] = v < 0 ? v + model.vertices.size() : v;
triangle.nindices[2] = n < 0 ? n + model.normals.size() : n;
model.triangles.add(triangle);
group.triangles.add(model.triangles.size() - 1);
for (int i = 4; i < lineStrs.length; i++) {
GLMtriangle newtriangle = new GLMtriangle();
newtriangle.vindices[0] = model.triangles.get(model.triangles.size() - 1).vindices[0];
newtriangle.nindices[0] = model.triangles.get(model.triangles.size() - 1).nindices[0];
newtriangle.vindices[1] = model.triangles.get(model.triangles.size() - 1).vindices[2];
newtriangle.nindices[1] = model.triangles.get(model.triangles.size() - 1).nindices[2];
v = Integer.valueOf(lineStrs[i].split("//")[0]);
n = Integer.valueOf(lineStrs[i].split("//")[1]);
newtriangle.vindices[2] = v < 0 ? v + model.vertices.size() : v;
newtriangle.nindices[2] = n < 0 ? n + model.normals.size() : n;
model.triangles.add(newtriangle);
group.triangles.add(model.triangles.size() - 1);
}
} else if (lineStrs[1].contains("/") && lineStrs[1].split("/").length == 3) {
/* v/t/n */
GLMtriangle triangle = new GLMtriangle();
v = Integer.valueOf(lineStrs[1].split("/")[0]);
t = Integer.valueOf(lineStrs[1].split("/")[1]);
n = Integer.valueOf(lineStrs[1].split("/")[2]);
triangle.vindices[0] = v < 0 ? v + model.vertices.size() : v;
triangle.tindices[0] = t < 0 ? t + model.texcoords.size() : t;
triangle.nindices[0] = n < 0 ? n + model.normals.size() : n;
v = Integer.valueOf(lineStrs[2].split("/")[0]);
t = Integer.valueOf(lineStrs[2].split("/")[1]);
n = Integer.valueOf(lineStrs[2].split("/")[2]);
triangle.vindices[1] = v < 0 ? v + model.vertices.size() : v;
triangle.tindices[1] = t < 0 ? t + model.texcoords.size() : t;
triangle.nindices[1] = n < 0 ? n + model.normals.size() : n;
v = Integer.valueOf(lineStrs[3].split("/")[0]);
t = Integer.valueOf(lineStrs[3].split("/")[1]);
n = Integer.valueOf(lineStrs[3].split("/")[2]);
triangle.vindices[2] = v < 0 ? v + model.vertices.size() : v;
triangle.tindices[2] = t < 0 ? t + model.texcoords.size() : t;
triangle.nindices[2] = n < 0 ? n + model.normals.size() : n;
model.triangles.add(triangle);
group.triangles.add(model.triangles.size() - 1);
for (int i = 4; i < lineStrs.length; i++) {
GLMtriangle newtriangle = new GLMtriangle();
newtriangle.vindices[0] = model.triangles.get(model.triangles.size() - 1).vindices[0];
newtriangle.tindices[0] = model.triangles.get(model.triangles.size() - 1).tindices[0];
newtriangle.nindices[0] = model.triangles.get(model.triangles.size() - 1).nindices[0];
newtriangle.vindices[1] = model.triangles.get(model.triangles.size() - 1).vindices[2];
newtriangle.tindices[1] = model.triangles.get(model.triangles.size() - 1).tindices[2];
newtriangle.nindices[1] = model.triangles.get(model.triangles.size() - 1).nindices[2];
v = Integer.valueOf(lineStrs[i].split("/")[0]);
t = Integer.valueOf(lineStrs[i].split("/")[1]);
n = Integer.valueOf(lineStrs[i].split("/")[2]);
newtriangle.vindices[2] = v < 0 ? v + model.vertices.size() : v;
newtriangle.tindices[2] = t < 0 ? t + model.texcoords.size() : t;
newtriangle.nindices[2] = n < 0 ? n + model.normals.size() : n;
model.triangles.add(newtriangle);
group.triangles.add(model.triangles.size() - 1);
}
} else if (lineStrs[1].contains("/") && lineStrs[1].split("/").length == 2) {
/* v/t */
GLMtriangle triangle = new GLMtriangle();
v = Integer.valueOf(lineStrs[1].split("/")[0]);
t = Integer.valueOf(lineStrs[1].split("/")[1]);
triangle.vindices[0] = v < 0 ? v + model.vertices.size() : v;
triangle.tindices[0] = t < 0 ? t + model.texcoords.size() : t;
v = Integer.valueOf(lineStrs[2].split("/")[0]);
t = Integer.valueOf(lineStrs[2].split("/")[1]);
triangle.vindices[1] = v < 0 ? v + model.vertices.size() : v;
triangle.tindices[1] = t < 0 ? t + model.texcoords.size() : t;
v = Integer.valueOf(lineStrs[3].split("/")[0]);
t = Integer.valueOf(lineStrs[3].split("/")[1]);
triangle.vindices[2] = v < 0 ? v + model.vertices.size() : v;
triangle.tindices[2] = t < 0 ? t + model.texcoords.size() : t;
model.triangles.add(triangle);
group.triangles.add(model.triangles.size() - 1);
for (int i = 4; i < lineStrs.length; i++) {
GLMtriangle newtriangle = new GLMtriangle();
newtriangle.vindices[0] = model.triangles.get(model.triangles.size() - 1).vindices[0];
newtriangle.tindices[0] = model.triangles.get(model.triangles.size() - 1).tindices[0];
newtriangle.vindices[1] = model.triangles.get(model.triangles.size() - 1).vindices[2];
newtriangle.tindices[1] = model.triangles.get(model.triangles.size() - 1).tindices[2];
v = Integer.valueOf(lineStrs[i].split("/")[0]);
t = Integer.valueOf(lineStrs[i].split("/")[1]);
newtriangle.vindices[2] = v < 0 ? v + model.vertices.size() : v;
newtriangle.tindices[2] = t < 0 ? t + model.texcoords.size() : t;
model.triangles.add(newtriangle);
group.triangles.add(model.triangles.size() - 1);
}
} else {
/* v */
GLMtriangle triangle = new GLMtriangle();
v = Integer.valueOf(lineStrs[1]);
triangle.vindices[0] = v < 0 ? v + model.vertices.size() : v;
v = Integer.valueOf(lineStrs[2]);
triangle.vindices[1] = v < 0 ? v + model.vertices.size() : v;
v = Integer.valueOf(lineStrs[3]);
triangle.vindices[2] = v < 0 ? v + model.vertices.size() : v;
model.triangles.add(triangle);
group.triangles.add(model.triangles.size() - 1);
for (int i = 4; i < lineStrs.length; i++) {
GLMtriangle newtriangle = new GLMtriangle();
newtriangle.vindices[0] = model.triangles.get(model.triangles.size() - 1).vindices[0];
newtriangle.vindices[1] = model.triangles.get(model.triangles.size() - 1).vindices[2];
v = Integer.valueOf(lineStrs[i]);
newtriangle.vindices[2] = v < 0 ? v + model.vertices.size() : v;
model.triangles.add(newtriangle);
group.triangles.add(model.triangles.size() - 1);
}
}
continue;
}
}
return model;
}
/*
* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to a
* file.
*
* model - initialized GLMmodel structure filename - name of the file to
* write the Wavefront .OBJ format data to mode - a bitwise or of values
* describing what is written to the file GLM_NONE - render with only
* vertices GLM_FLAT - render with facet normals GLM_SMOOTH - render with
* vertex normals GLM_TEXTURE - render with texture coords GLM_COLOR -
* render with colors (color material) GLM_MATERIAL - render with materials
* GLM_COLOR and GLM_MATERIAL should not both be specified. GLM_FLAT and
* GLM_SMOOTH should not both be specified.
*/
public void glmWriteOBJ(GLMmodel model, String filename, int mode) throws Exception {
/* do a bit of warning */
if ((mode & GLM_FLAT) == GLM_FLAT && model.facetnorms.size() == 0) {
System.out.println("glmWriteOBJ() warning: flat normal output requested with no facet normals defined.\n");
mode &= ~GLM_FLAT;
}
if ((mode & GLM_SMOOTH) == GLM_SMOOTH && model.normals.size() == 0) {
System.out.println("glmWriteOBJ() warning: smooth normal output requested with no normals defined.\n");
mode &= ~GLM_SMOOTH;
}
if ((mode & GLM_TEXTURE) == GLM_TEXTURE && model.texcoords.size() == 0) {
System.out
.println("glmWriteOBJ() warning: texture coordinate output requested with no texture coordinates defined.\n");
mode &= ~GLM_TEXTURE;
}
if ((mode & GLM_FLAT) == GLM_FLAT && (mode & GLM_SMOOTH) == GLM_SMOOTH) {
System.out
.println("glmWriteOBJ() warning: flat normal output requested and smooth normal output requested (using smooth).\n");
mode &= ~GLM_FLAT;
}
if ((mode & GLM_COLOR) == GLM_COLOR && model.materials.size() == 0) {
System.out.println("glmWriteOBJ() warning: color output requested with no colors (materials) defined.\n");
mode &= ~GLM_COLOR;
}
if ((mode & GLM_MATERIAL) == GLM_MATERIAL && model.materials.size() == 0) {
System.out.println("glmWriteOBJ() warning: material output requested with no materials defined.\n");
mode &= ~GLM_MATERIAL;
}
if ((mode & GLM_COLOR) == GLM_COLOR && (mode & GLM_MATERIAL) == GLM_MATERIAL) {
System.out
.println("glmWriteOBJ() warning: color and material output requested outputting only materials.\n");
mode &= ~GLM_COLOR;
}
StringBuffer sb = new StringBuffer();
/* spit out a header */
sb.append("# \n");
sb.append("# Wavefront OBJ generated by GLM library\n");
sb.append("# \n");
sb.append("# GLM library\n");
sb.append("# Nate Robins\n");
sb.append("# http://www.pobox.com/~ndr\n");
sb.append("# \n");
if ((mode & GLM_MATERIAL) == GLM_MATERIAL && model.mtllibname != null) {
sb.append("\nmtllib " + model.mtllibname + "\n\n");
glmWriteMTL(model, filename, model.mtllibname);
}
/* spit out the vertices */
sb.append("\n");
sb.append("# " + model.vertices.size() + " vertices\n");
float[] vertice = new float[3];
for (int i = 1; i < model.vertices.size(); i++) {
vertice = model.vertices.get(i);
sb.append("v " + vertice[0] + " " + vertice[1] + " " + vertice[2] + "\n");
}
/* spit out the smooth/flat normals */
if ((mode & GLM_SMOOTH) == GLM_SMOOTH) {
sb.append("\n");
sb.append("# " + model.normals.size() + " normals\n");
float[] normal = new float[3];
for (int i = 1; i < model.normals.size(); i++) {
normal = model.normals.get(i);
sb.append("vn " + normal[0] + " " + normal[1] + " " + normal[2] + "\n");
}
} else if ((mode & GLM_FLAT) == GLM_FLAT) {
sb.append("\n");
sb.append("# " + model.facetnorms.size() + " normals\n");
float[] facetnorm = new float[3];
for (int i = 1; i < model.facetnorms.size(); i++) {
facetnorm = model.facetnorms.get(i);
sb.append("vn " + facetnorm[0] + " " + facetnorm[1] + " " + facetnorm[2] + "\n");
}
}
/* spit out the texture coordinates */
if ((mode & GLM_TEXTURE) == GLM_TEXTURE) {
sb.append("\n");
sb.append("# " + model.texcoords.size() + " texcoords\n");
float[] texcoord = new float[2];
for (int i = 1; i <= model.texcoords.size(); i++) {
texcoord = model.texcoords.get(i);
sb.append("vt " + texcoord[0] + " " + texcoord[1] + "\n");
}
}
sb.append("\n");
sb.append("# " + model.groups.size() + " groups\n");
sb.append("# " + model.triangles.size() + " faces (triangles)\n");
sb.append("\n");
for (GLMgroup group : model.groups) {
sb.append("g " + group.name + "\n");
if ((mode & GLM_MATERIAL) == GLM_MATERIAL)
sb.append("usemtl " + model.materials.get(group.material).name + "\n");
for (int i = 0; i < group.triangles.size(); i++) {
if ((mode & GLM_SMOOTH) == GLM_SMOOTH && (mode & GLM_TEXTURE) == GLM_TEXTURE) {
// f %d/%d/%d %d/%d/%d %d/%d/%d\n
sb.append("f " + model.triangles.get(group.triangles.get(i)).vindices[0]);
sb.append("/" + model.triangles.get(group.triangles.get(i)).tindices[0]);
sb.append("/" + model.triangles.get(group.triangles.get(i)).nindices[0]);
sb.append(" " + model.triangles.get(group.triangles.get(i)).vindices[1]);
sb.append("/" + model.triangles.get(group.triangles.get(i)).tindices[1]);
sb.append("/" + model.triangles.get(group.triangles.get(i)).nindices[1]);
sb.append(" " + model.triangles.get(group.triangles.get(i)).vindices[2]);
sb.append("/" + model.triangles.get(group.triangles.get(i)).tindices[2]);
sb.append("/" + model.triangles.get(group.triangles.get(i)).nindices[2] + "\n");
} else if ((mode & GLM_FLAT) == GLM_FLAT && (mode & GLM_TEXTURE) == GLM_TEXTURE) {
// f %d/%d %d/%d %d/%d\n
sb.append("f " + model.triangles.get(group.triangles.get(i)).vindices[0]);
sb.append("/" + model.triangles.get(group.triangles.get(i)).findex);
sb.append(" " + model.triangles.get(group.triangles.get(i)).vindices[1]);
sb.append("/" + model.triangles.get(group.triangles.get(i)).findex);
sb.append(" " + model.triangles.get(group.triangles.get(i)).vindices[2]);
sb.append("/" + model.triangles.get(group.triangles.get(i)).findex + "\n");
} else if ((mode & GLM_TEXTURE) == GLM_TEXTURE) {
// f %d/%d %d/%d %d/%d\n
sb.append("f " + model.triangles.get(group.triangles.get(i)).vindices[0]);
sb.append("/" + model.triangles.get(group.triangles.get(i)).tindices[0]);
sb.append(" " + model.triangles.get(group.triangles.get(i)).vindices[1]);
sb.append("/" + model.triangles.get(group.triangles.get(i)).tindices[1]);
sb.append(" " + model.triangles.get(group.triangles.get(i)).vindices[2]);
sb.append("/" + model.triangles.get(group.triangles.get(i)).tindices[2] + "\n");
} else if ((mode & GLM_SMOOTH) == GLM_SMOOTH) {
// f %d//%d %d//%d %d//%d\n
sb.append("f " + model.triangles.get(group.triangles.get(i)).vindices[0]);
sb.append("//" + model.triangles.get(group.triangles.get(i)).nindices[0]);
sb.append(" " + model.triangles.get(group.triangles.get(i)).vindices[1]);
sb.append("//" + model.triangles.get(group.triangles.get(i)).nindices[1]);
sb.append(" " + model.triangles.get(group.triangles.get(i)).vindices[2]);
sb.append("//" + model.triangles.get(group.triangles.get(i)).nindices[2] + "\n");
} else if ((mode & GLM_FLAT) == GLM_FLAT) {
// f %d//%d %d//%d %d//%d\n
sb.append("f " + model.triangles.get(group.triangles.get(i)).vindices[0]);
sb.append("//" + model.triangles.get(group.triangles.get(i)).findex);
sb.append(" " + model.triangles.get(group.triangles.get(i)).vindices[1]);
sb.append("//" + model.triangles.get(group.triangles.get(i)).findex);
sb.append(" " + model.triangles.get(group.triangles.get(i)).vindices[2]);
sb.append("//" + model.triangles.get(group.triangles.get(i)).findex);
} else {
// f %d %d %d\n
sb.append("f " + model.triangles.get(group.triangles.get(i)).vindices[0]);
sb.append(" " + model.triangles.get(group.triangles.get(i)).vindices[1]);
sb.append(" " + model.triangles.get(group.triangles.get(i)).vindices[2] + "\n");
}
}
sb.append("\n");
}
FileOutputStream fos = new FileOutputStream(filename);
fos.write(sb.toString().getBytes());
fos.flush();
fos.close();
}
/*
* glmDraw: Renders the model to the current OpenGL context using the mode
* specified.
*
* model - initialized GLMmodel structure mode - a bitwise OR of values
* describing what is to be rendered. GLM_NONE - render with only vertices
* GLM_FLAT - render with facet normals GLM_SMOOTH - render with vertex
* normals GLM_TEXTURE - render with texture coords GLM_COLOR - render with
* colors (color material) GLM_MATERIAL - render with materials GLM_COLOR
* and GLM_MATERIAL should not both be specified. GLM_FLAT and GLM_SMOOTH
* should not both be specified.
*/
public void glmDraw(GLMmodel model, int mode) {
int i;
GLMtriangle triangle;
GLMmaterial material = null;
/* do a bit of warning */
if ((mode & GLM_FLAT) == GLM_FLAT && model.facetnorms.size() == 0) {
System.out.println("glmDraw() warning: flat render mode requested with no facet normals defined.\n");
mode &= ~GLM_FLAT;
}
if ((mode & GLM_SMOOTH) == GLM_SMOOTH && model.normals.size() == 0) {
System.out.println("glmDraw() warning: smooth render mode requested with no normals defined.\n");
mode &= ~GLM_SMOOTH;
}
if ((mode & GLM_TEXTURE) == GLM_TEXTURE && model.texcoords.size() == 0) {
System.out
.println("glmDraw() warning: texture render mode requested with no texture coordinates defined.\n");
mode &= ~GLM_TEXTURE;
}
if ((mode & GLM_FLAT) == GLM_FLAT && (mode & GLM_SMOOTH) == GLM_SMOOTH) {
System.out
.println("glmDraw() warning: flat render mode requested and smooth render mode requested (using smooth).\n");
mode &= ~GLM_FLAT;
}
if ((mode & GLM_COLOR) == GLM_COLOR && model.materials.size() == 0) {
System.out.println("glmDraw() warning: color render mode requested with no materials defined.\n");
mode &= ~GLM_COLOR;
}
if ((mode & GLM_MATERIAL) == GLM_MATERIAL && model.materials.size() == mode) {
System.out.println("glmDraw() warning: material render mode requested with no materials defined.\n");
mode &= ~GLM_MATERIAL;
}
if ((mode & GLM_COLOR) == GLM_COLOR && (mode & GLM_MATERIAL) == GLM_MATERIAL) {
System.out
.println("glmDraw() warning: color and material render mode requested using only material mode.\n");
mode &= ~GLM_COLOR;
}
if ((mode & GLM_COLOR) == GLM_COLOR)
glEnable(GL_COLOR_MATERIAL);
else if ((mode & GLM_MATERIAL) == GLM_MATERIAL)
glDisable(GL_COLOR_MATERIAL);
/*
* perhaps this loop should be unrolled into material, color, flat,
* smooth, etc. loops? since most cpu's have good branch prediction
* schemes (and these branches will always go one way), probably
* wouldn't gain too much?
*/
for (GLMgroup group : model.groups) {
if ((mode & GLM_MATERIAL) == GLM_MATERIAL) {
material = model.materials.get(group.material);
glMaterial(GL_FRONT_AND_BACK, GL_AMBIENT, (FloatBuffer) (BufferUtils.createFloatBuffer(4).put(
material.ambient).flip()));
glMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE, (FloatBuffer) (BufferUtils.createFloatBuffer(4).put(
material.diffuse).flip()));
glMaterial(GL_FRONT_AND_BACK, GL_SPECULAR, (FloatBuffer) (BufferUtils.createFloatBuffer(4).put(
material.specular).flip()));
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material.shininess);
}
if ((mode & GLM_COLOR) == GLM_COLOR) {
glColor3f(material.diffuse[0], material.diffuse[1], material.diffuse[2]);
}
glBegin(GL_TRIANGLES);
for (i = 0; i < group.triangles.size(); i++) {
triangle = model.triangles.get(group.triangles.get(i));
float[] f;
if ((mode & GLM_FLAT) == GLM_FLAT) {
f = model.facetnorms.get(triangle.findex);
glNormal3f(f[0], f[1], f[2]);
}
if ((mode & GLM_SMOOTH) == GLM_SMOOTH) {
f = model.normals.get(triangle.nindices[0]);
glNormal3f(f[0], f[1], f[2]);
}
if ((mode & GLM_TEXTURE) == GLM_TEXTURE) {
f = model.texcoords.get(triangle.tindices[0]);
glTexCoord2f(f[0], f[1]);
}
f = model.vertices.get(triangle.vindices[0]);
glVertex3f(f[0], f[1], f[2]);
if ((mode & GLM_SMOOTH) == GLM_SMOOTH) {
f = model.normals.get(triangle.nindices[1]);
glNormal3f(f[0], f[1], f[2]);
}
if ((mode & GLM_TEXTURE) == GLM_TEXTURE) {
f = model.texcoords.get(triangle.tindices[1]);
glTexCoord2f(f[0], f[1]);
}
f = model.vertices.get(triangle.vindices[1]);
glVertex3f(f[0], f[1], f[2]);
if ((mode & GLM_SMOOTH) == GLM_SMOOTH) {
f = model.normals.get(triangle.nindices[2]);
glNormal3f(f[0], f[1], f[2]);
}
if ((mode & GLM_TEXTURE) == GLM_TEXTURE) {
f = model.texcoords.get(triangle.tindices[2]);
glTexCoord2f(f[0], f[1]);
}
f = model.vertices.get(triangle.vindices[2]);
glVertex3f(f[0], f[1], f[2]);
}
glEnd();
}
}
/*
* glmList: Generates and returns a display list for the model using the
* mode specified.
*
* model - initialized GLMmodel structure mode - a bitwise OR of values
* describing what is to be rendered. GLM_NONE - render with only vertices
* GLM_FLAT - render with facet normals GLM_SMOOTH - render with vertex
* normals GLM_TEXTURE - render with texture coords GLM_COLOR - render with
* colors (color material) GLM_MATERIAL - render with materials GLM_COLOR
* and GLM_MATERIAL should not both be specified. GLM_FLAT and GLM_SMOOTH
* should not both be specified.
*/
public int glmList(GLMmodel model, int mode) {
int list;
list = glGenLists(1);
glNewList(list, GL_COMPILE);
glmDraw(model, mode);
glEndList();
return list;
}
}