package com.thecrouchmode.graphics;
import static org.lwjgl.opengl.GL11.*;
//import static org.lwjgl.opengl.GL12.*;
//import static org.lwjgl.opengl.GL13.*;
//import static org.lwjgl.opengl.GL14.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
//import static org.lwjgl.opengl.GL21.*;
import static org.lwjgl.opengl.GL30.*;
import java.io.IOException;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.thecrouchmode.LWJGL.util.Buffers;
import com.thecrouchmode.LWJGL.util.ResourceReader;
import com.thecrouchmode.vector.Matrix4f;
import com.thecrouchmode.vector.Vector3f;
public class Model{
private final int dataBuffer;
private final int indexBuffer;
private final int size;
public final Matrix4f normalization;
public final Vector3f ambient = new Vector3f(0.3, 0.3, 0.3);
public final Vector3f diffuse = new Vector3f(0.7, 0.7, 0.7);
public final Vector3f specular = new Vector3f(0.5, 0.5, 0.5);
public final int shinyness = 100;
private static int elements = (3 + 3 +2); //3 pos, 3 normal, 2 uv
public Model(float[] data, int indices[], Matrix4f normalization){
this.dataBuffer = glGenBuffers();
this.indexBuffer = glGenBuffers();
size = indices.length;
this.normalization = normalization;
glBindBuffer(GL_ARRAY_BUFFER, this.dataBuffer);
glBufferData(GL_ARRAY_BUFFER, Buffers.createBuffer(data), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this.indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, Buffers.createBuffer(indices), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
public Model(String path, boolean smooth) throws IOException{
this.dataBuffer = glGenBuffers();
this.indexBuffer = glGenBuffers();
List<String> lines = ResourceReader.readLines(path);
//clear file of comments and empty lines
for(Iterator<String> i = lines.iterator(); i.hasNext();){
String line = i.next();
if(line.equals("") || line.charAt(0)=='#') i.remove();
}
//find no. points & faces
int points = Integer.parseInt(lines.get(1).split("\\s+")[0]);
int faces = Integer.parseInt(lines.get(1).split("\\s+")[1]);
float[] data = new float[points*3*2];
List<List<Vector3f>> normalLists = new ArrayList<>();
List<Vector3f> flatNormals = new ArrayList<>();
//from row two and no. points rows forward
List<Vector3f> vertices = new ArrayList<>();
Vector3f min = null;
Vector3f max = null;
for(int row = 2; row < points+2; row++){
String[] line = lines.get(row).split("\\s+");
normalLists.add(new ArrayList<Vector3f>());
Vector3f vertex = new Vector3f(
Float.parseFloat(line[0]),
Float.parseFloat(line[1]),
Float.parseFloat(line[2]));
vertices.add(vertex);
if(min == null) min = vertex;
if(max == null) max = vertex;
if(vertex.x > max.x) max = new Vector3f(vertex.x, max.y, max.z);
if(vertex.y > max.y) max = new Vector3f(max.x, vertex.y, max.z);
if(vertex.z > max.z) max = new Vector3f(max.x, max.y, vertex.z);
if(vertex.x < min.x) min = new Vector3f(vertex.x, min.y, min.z);
if(vertex.y < min.y) min = new Vector3f(min.x, vertex.y, min.z);
if(vertex.z < min.z) min = new Vector3f(min.x, min.y, vertex.z);
}
Vector3f lengths = max.subtract(min);
float maxLength = Math.max(Math.max(lengths.x, lengths.y), lengths.z);
Vector3f midPoint = Vector3f.sum(max, min).scale(-0.5);
normalization = Matrix4f.product(
Matrix4f.scale(1.0/maxLength),
Matrix4f.translation(midPoint));
List<Integer> indices = new ArrayList<>();
//indices start at row 2+points, every row's a face
for(int row = 2+points; row < faces+points+2; row++){
String[] line = lines.get(row).split("\\s+");
//calculate the normal
Vector3f v1 = vertices.get(Integer.parseInt(line[1]));
Vector3f v2 = vertices.get(Integer.parseInt(line[2]));
Vector3f v3 = vertices.get(Integer.parseInt(line[3]));
Vector3f normal = Vector3f.cross(
v2.subtract(v1).unit(),
v3.subtract(v1).unit()).unit();
//System.out.println("Normal: "+normal);
if(smooth) for(int i = 0; i < Integer.parseInt(line[0]); i++){
normalLists.get(Integer.parseInt(line[i+1])).add(normal);
}
//triangulate and add indices to index list.
for(int i = 0; i < Integer.parseInt(line[0])-2; i++){
indices.add(Integer.parseInt(line[1]));
indices.add(Integer.parseInt(line[i+2]));
indices.add(Integer.parseInt(line[i+3]));
if(!smooth){
flatNormals.add(normal);
flatNormals.add(normal);
flatNormals.add(normal);
}
}
}
//create buffer of indices here TODO
float[] dataBuffer;
int[] indexBuffer;
if(smooth){
dataBuffer = new float[vertices.size()*elements];
indexBuffer = new int[indices.size()];
for(int i = 0; i < indices.size(); i++){
indexBuffer[i] = indices.get(i);
}
for(int i = 0; i < vertices.size(); i++){
Vector3f vertex = vertices.get(i);
dataBuffer[i*elements] = vertex.x;
dataBuffer[i*elements+1] = vertex.y;
dataBuffer[i*elements+2] = vertex.z;
Vector3f normal = new Vector3f(0, 0, 0);
for(Vector3f normalTerm : normalLists.get(i)){
normal = normal.add(normalTerm);
}
normal = normal.scale(1.0/normalLists.get(i).size());
//normal = new Vector3f(1, 0, 0);
dataBuffer[i*elements+3] = normal.x;
dataBuffer[i*elements+4] = normal.y;
dataBuffer[i*elements+5] = normal.z;
dataBuffer[i*elements+6] = vertex.x;
dataBuffer[i*elements+7] = vertex.y;
}
}
else{
dataBuffer = new float[indices.size()*elements];
indexBuffer = new int[indices.size()];
for(int i = 0; i < indices.size(); i++){
indexBuffer[i] = i;
//Positions
Vector3f vertex = vertices.get(indices.get(i));
dataBuffer[i*elements] = vertex.x;
dataBuffer[i*elements+1] = vertex.y;
dataBuffer[i*elements+2] = vertex.z;
//Normals
Vector3f normal = flatNormals.get(i);
dataBuffer[i*elements+3] = normal.x;
dataBuffer[i*elements+4] = normal.y;
dataBuffer[i*elements+5] = normal.z;
//UVs
dataBuffer[i*elements+6] = vertex.x;
dataBuffer[i*elements+7] = vertex.y;
}
}
size = indices.size();
glBindBuffer(GL_ARRAY_BUFFER, this.dataBuffer);
glBufferData(GL_ARRAY_BUFFER, Buffers.createBuffer(dataBuffer), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this.indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, Buffers.createBuffer(indexBuffer), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
public Model(String path) throws IOException{
this(path, true);
}
public void draw(){
glBindBuffer(GL_ARRAY_BUFFER, dataBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glVertexAttribPointer(//create AttribPointer pod
0, //what array in shader access something something
3, //no. elements
GL_FLOAT, //type
false, //normalized
elements * 4, //size of whole vertex/stride
0); // start point
glVertexAttribPointer(//create AttribPointer normal
1, //what array in shader access something something
3, //no. elements
GL_FLOAT, //type
false, //normalized
elements * 4, //size of whole vertex/stride
3 * 4); // start point
glVertexAttribPointer(//create AttribPointer uv
2, //what array in shader access something something
2, //no. elements
GL_FLOAT, //type
false, //normalized
elements * 4, //size of whole vertex/stride
6 * 4); // start point
glDrawElements(GL_TRIANGLES, size, GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
}