package javaforce.gl;
import java.util.*;
import javaforce.*;
import static javaforce.gl.GL.*;
/** <code>GLObject</code> consists of vertex points, and polygons (usually triangles).
* All polygons share the same orientation (rotation, translation, scale).
*/
public class GLObject implements Cloneable {
public JFArrayFloat vpl; //vertex position list
public JFArrayInt vil; //vertex index list
public int vpb = -1, vib = -1; //GL Buffers
public int type = GL.GL_TRIANGLES; //GL_TRIANGLES or GL_QUADS
public ArrayList<GLUVMap> maps = new ArrayList<GLUVMap>();
public boolean visible = true;
public boolean needCopyBuffers = true;
//animation data
public HashMap<Integer, GLTranslate> tl; //move list
public HashMap<Integer, GLRotate> rl; //rotation list
public HashMap<Integer, GLScale> sl; //scale list
public int frameIndex;
public GLMatrix m; //current rotation, translation, scale
public float color[]; //RGBA (default = 1.0f,1.0f,1.0f,1.0f)
public GLVertex org; //origin (default = 0.0f,0.0f,0.0f)
public String name;
public int parent; //a 3ds file field (not used)
public int maxframeCount;
public GLObject() {
frameIndex = 0;
vpl = new JFArrayFloat();
vil = new JFArrayInt();
tl = new HashMap<Integer, GLTranslate>();
rl = new HashMap<Integer, GLRotate>();
sl = new HashMap<Integer, GLScale>();
color = new float[4];
for(int a=0;a<4;a++) color[a] = 1.0f;
visible = true;
org = new GLVertex();
parent = -1;
maxframeCount = 0;
m = new GLMatrix();
}
public Object clone() {
GLObject cln = new GLObject();
cln.vpl = vpl;
cln.vil = vil;
cln.maps = maps;
cln.visible = visible;
cln.tl = tl;
cln.rl = rl;
cln.sl = sl;
cln.frameIndex = frameIndex;
cln.m = (GLMatrix)m.clone(); //super.clone() would use an assignment
cln.color = new float[4];
for(int a=0;a<4;a++) cln.color[a] = color[a];
cln.org = org;
cln.parent = parent;
cln.maxframeCount = maxframeCount;
cln.type = type;
return cln;
}
public void setVisible(boolean state) {visible = state;}
public void addRotate(float angle, float x, float y, float z, GLVertex org) {
GLMatrix tmp = new GLMatrix();
//rotates relative to org
tmp.setAA(angle, x, y, z); //set rotation
tmp.addTranslate(org.x, org.y, org.z); //set translation
m.mult4x4(tmp); //add it
//now undo translation
tmp.setIdentity3x3(); //remove rotation
tmp.reverseTranslate();
m.mult4x4(tmp);
}
public void addTranslate(float x, float y, float z) {
m.addTranslate(x,y,z);
}
public void addScale(float x, float y, float z) {
m.addScale(x,y,z);
}
public void setFrame(int idx) { //0=init state
GLRotate _r;
GLTranslate _t;
GLScale _s;
frameIndex = idx;
if (idx == 0) {
m.setIdentity();
return;
}
_t = tl.get(idx);
if (_t != null) {
addTranslate((_t.x - org.x),(_t.y - org.y),(_t.z - org.z));
}
_r = rl.get(idx);
if (_r != null) {
addRotate(_r.angle,_r.x,_r.y,_r.z,org);
}
_s = sl.get(idx);
if (_s != null) {
addScale(_s.x, _s.y, _s.z);
}
}
public void nextFrame() {
setFrame(frameIndex+1);
}
public int frameCount() {
return maxframeCount;
}
public void addVertex(float xyz[]) {
vpl.append(xyz);
}
public void addVertex(float xyz[], float uv[]) {
vpl.append(xyz);
maps.get(0).uvl.append(uv);
}
public void addVertex(float xyz[], float uv1[], float uv2[]) {
vpl.append(xyz);
maps.get(0).uvl.append(uv1);
maps.get(1).uvl.append(uv2);
}
public void addVertex(GLVertex v) {
vpl.append(v.x);
vpl.append(v.y);
vpl.append(v.z);
GLUVMap map = maps.get(0);
map.uvl.append(v.u);
map.uvl.append(v.v);
}
public int getVertexCount() {
return vpl.size() / 3;
}
public void addText(float uv[]) {
maps.get(0).addText(uv);
}
public void addText(float uv[], int map) {
maps.get(map).addText(uv);
}
public void addPoly(int pts[]) {
vil.append(pts);
}
public void copyBuffers() {
int ids[] = new int[1];
if (vpb == -1) {
glGenBuffers(1, ids);
vpb = ids[0];
}
glBindBuffer(GL.GL_ARRAY_BUFFER, vpb);
glBufferData(GL.GL_ARRAY_BUFFER, vpl.size() * 4, vpl.toArray(), GL.GL_STATIC_DRAW);
for(int a=0;a<maps.size();a++) {
maps.get(a).copyBuffers();
}
if (vib == -1) {
glGenBuffers(1, ids);
vib = ids[0];
}
glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, vib);
glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, vil.size() * 4, vil.toArray(), GL.GL_STREAM_DRAW);
needCopyBuffers = false;
}
public void bindBuffers(GLScene scene) {
glBindBuffer(GL.GL_ARRAY_BUFFER, vpb);
glVertexAttribPointer(scene.vpa, 3, GL.GL_FLOAT, GL.GL_FALSE, 0, 0);
for(int m=0;m<maps.size();m++) {
maps.get(m).bindBuffers(scene);
}
glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, vib);
}
public void render(GLScene scene) {
if (vpl.size() == 0 || vil.size() == 0) return; //crashes if empty ???
int uvcnt = maps.size();
glUniform1i(scene.uUVMaps, uvcnt);
GL.glEnableVertexAttribArray(scene.tca[0]);
if (uvcnt > 1) {
GL.glEnableVertexAttribArray(scene.tca[1]);
} else {
GL.glDisableVertexAttribArray(scene.tca[1]);
}
glDrawElements(type, vil.size(), GL.GL_UNSIGNED_INT, 0);
}
public GLUVMap createUVMap() {
GLUVMap map = new GLUVMap(maps.size());
maps.add(map);
return map;
}
public GLUVMap getUVMap(int idx) {
return maps.get(idx);
}
public GLUVMap getUVMap(String name) {
for(int a=0;a<maps.size();a++) {
GLUVMap map = maps.get(a);
if (map.name.equals(name)) return map;
}
return null;
}
public int getUVMaps() {
return maps.size();
}
public void print(GLModel model) {
System.out.println("Object:" + name);
//print vertex data
float vp[] = vpl.toArray();
for(int a=0;a<vp.length;) {
System.out.println(String.format("v[%d]=%6.3f,%6.3f,%6.3f", a/3, vp[a++], vp[a++], vp[a++]));
}
//print poly data
int vi[] = vil.toArray();
for(int a=0;a<vi.length;) {
switch (type) {
case GL.GL_TRIANGLES:
System.out.println(String.format("i[%d]=%d,%d,%d", a/3, vi[a++], vi[a++], vi[a++]));
break;
case GL.GL_QUADS:
System.out.println(String.format("i[%d]=%d,%d,%d,%d", a/4, vi[a++], vi[a++], vi[a++], vi[a++]));
break;
}
}
//print uv maps
for(int m=0;m<maps.size();m++) {
GLUVMap map = maps.get(m);
System.out.println("UVMap:" + map.name + ",texture=" + model.textures.get(map.textureIndex));
float uv[] = map.uvl.toArray();
for(int a=0;a<uv.length;) {
System.out.println(String.format("uv[%d]=%6.3f,%6.3f", a/2, uv[a++], uv[a++]));
}
}
}
}