package tk.amberide.engine.gl.model;
import tk.amberide.engine.gl.model.obj.Mesh;
import tk.amberide.engine.gl.Buffers;
import tk.amberide.engine.gl.TextureLoader;
import java.io.File;
import java.util.ArrayList;
import tk.amberide.engine.gl.model.obj.Face;
import tk.amberide.engine.gl.model.obj.Group;
import tk.amberide.engine.gl.model.obj.Material;
import tk.amberide.engine.gl.model.obj.WavefrontObject;
import java.io.IOException;
import java.util.List;
import java.util.WeakHashMap;
import javax.imageio.ImageIO;
import static org.lwjgl.opengl.GL11.*;
import org.lwjgl.util.vector.Vector3f;
public class ModelScene {
protected final WeakHashMap<Material, Integer> textureCache = new WeakHashMap<Material, Integer>();
protected float sx = 1, sy = 1, sz = 1;
public ModelScene(File file) throws IOException {
this(file, 1, 1, 1);
}
public ModelScene(File file, float s) throws IOException {
this(file, s, s, s);
}
public ModelScene(File file, float sx, float sy, float sz) throws IOException {
this(new WavefrontObject(file), sx, sy, sz);
}
public ModelScene(WavefrontObject obj, float s) throws IOException {
this(obj, s, s, s);
}
public ModelScene(WavefrontObject obj) throws IOException {
this(obj, 1, 1, 1);
}
public ModelScene(WavefrontObject obj, float sx, float sy, float sz) throws IOException {
this.sx = sx;
this.sy = sy;
this.sz = sz;
displayListId = glGenLists(1);
model = obj;
ArrayList<Group> groups = model.getGroups();
for (int gi = 0;
gi < groups.size();
gi++) {
Group g = groups.get(gi);
Material gm = g.getMaterial();
Mesh mesh = new Mesh();
mesh.setName(g.getName());
mesh.setMaterial(gm);
String texName = gm.getTextureName();
if (texName != null && texName.length() > 0) {
gm.setTexture(ImageIO.read(new File(obj.getObjectFile().getParentFile(), texName)));
}
for (int fi = 0; fi < g.getFaces().size(); fi++) {
mesh.addFace(g.getFaces().get(fi));
}
for (int vi = 0; vi < model.getVertices().size(); vi++) {
Vector3f v = (Vector3f) model.getVertices().get(vi);
vertices.add(new float[]{v.getX(), v.getY(), v.getZ()});
}
for (int vi = 0; vi < model.getNormals().size(); vi++) {
Vector3f v = (Vector3f) model.getNormals().get(vi);
normals.add(new float[]{v.getX(), v.getY(), v.getZ()});
}
for (int vi = 0; vi < model.getTextures().size(); vi++) {
Vector3f tc = (Vector3f) model.getTextures().get(vi);
textures.add(new float[]{tc.x, tc.y, tc.z});
}
addMesh(mesh);
}
}
public void addMesh(Mesh mesh) {
meshes.add(mesh);
}
public void draw() {
// If the list is compiled and everything is ok, render
if (displayListId > 0 && listCompiled) {
glCallList(displayListId);
return;
}
if (displayListId > 0 && !listCompiled) {
glNewList(displayListId, GL_COMPILE);
}
for (int i = 0; i < meshes.size(); i++) {
Mesh m = meshes.get(i);
Material mat = m.getMaterial();
int texId;
if (textureCache.containsKey(mat)) {
texId = textureCache.get(mat);
} else {
textureCache.put(mat, texId = TextureLoader.getTexture(mat.getTexture()).getID());
}
// If current material has texture, bind it
if (texId > 0) {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texId);
} else {
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
}
Vector3f ka = mat.getKa();
glMaterial(GL_FRONT_AND_BACK, GL_AMBIENT, Buffers.asFlippedFloatBuffer(new float[]{ka.x, ka.y, ka.z, 1.0f}));
Vector3f kd = mat.getKd();
glMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE, Buffers.asFlippedFloatBuffer(new float[]{kd.x, kd.y, kd.z, 1.0f}));
Vector3f ks = mat.getKs();
if (ks != null) {
glMaterial(GL_FRONT_AND_BACK, GL_SPECULAR, Buffers.asFlippedFloatBuffer(new float[]{ks.x, ks.y, ks.z, 1.0f}));
}
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, mat.getShininess());
//glEnable( GL_COLOR_MATERIAL );
// render triangles.. this is too basic. should be optimized
glBegin(GL_TRIANGLES);
//if( m._material._texId > 0 )
//glColor4f( 1, 1, 1, 1 );
//else
glColor4f(kd.x, kd.y, kd.z, 1.0f);
List<Face> faces = m.getFaces();
for (int fi = 0; fi < faces.size(); fi++) {
Face f = faces.get(fi);
glNormal3f(normals.get(f.normIndices[0])[0], normals.get(f.normIndices[0])[1], normals.get(f.normIndices[0])[2]);
if (texId > 0) {
glTexCoord2f(textures.get(f.texIndices[0])[0], textures.get(f.texIndices[0])[1]);
}
glVertex3f(vertices.get(f.vertIndices[0])[0] * sx, vertices.get(f.vertIndices[0])[1] * sy, vertices.get(f.vertIndices[0])[2] * sz);
glNormal3f(normals.get(f.normIndices[1])[0], normals.get(f.normIndices[1])[1], normals.get(f.normIndices[1])[2]);
if (texId > 0) {
glTexCoord2f(textures.get(f.texIndices[1])[0], textures.get(f.texIndices[1])[1]);
}
glVertex3f(vertices.get(f.vertIndices[1])[0] * sx, vertices.get(f.vertIndices[1])[1] * sy, vertices.get(f.vertIndices[1])[2] * sz);
glNormal3f(normals.get(f.normIndices[2])[0], normals.get(f.normIndices[2])[1], normals.get(f.normIndices[2])[2]);
if (texId > 0) {
glTexCoord2f(textures.get(f.texIndices[2])[0], textures.get(f.texIndices[2])[1]);
}
glVertex3f(vertices.get(f.vertIndices[2])[0] * sx, vertices.get(f.vertIndices[2])[1] * sy, vertices.get(f.vertIndices[2])[2] * sz);
}
glEnd();
}
if (displayListId > 0 && !listCompiled) {
glEndList();
listCompiled = true;
}
}
int displayListId;
boolean listCompiled;
ArrayList<float[]> vertices = new ArrayList<float[]>();
ArrayList<float[]> normals = new ArrayList<float[]>();
ArrayList<float[]> textures = new ArrayList<float[]>();
ArrayList<Mesh> meshes = new ArrayList<Mesh>();
private WavefrontObject model;
}