package javaforce.gl;
import java.util.*;
import javaforce.*;
import static javaforce.gl.GL.*;
/** GLScene is a primitive 3D framework.
* Holds all loaded 3D meshes and related resources.
*/
public class GLScene {
private static final boolean DEBUG = false;
private boolean needinittex = true;
ArrayList<GLModel> ml;
HashMap<String, GLTexture> tl; //texture list
HashMap<String, GLModel> mtl; //model templates list
private ArrayList<Integer> freeglidlist;
GLTexture blankTexture;
public GLScene() {
freeglidlist = new ArrayList<Integer>();
reset();
texturePath = "";
blankTexture = new GLTexture(0);
blankTexture.set(new int[] {-1},1,1); //white pixel
}
public boolean inited = false;
public String texturePath;
public int fragShader, vertexShader, program;
public int vpa; //attribs
public int tca[] = new int[2];
public int uUVMaps;
public int mpu, mmu, mvu; //uniform matrix'es (perspective, model, view)
//code
public void init(String vertex, String fragment) { //must give size of render window
glFrontFace(GL.GL_CCW); //3DS uses GL_CCW
glEnable(GL.GL_CULL_FACE); //don't draw back sides
glEnable(GL.GL_DEPTH_TEST);
glDepthFunc(GL.GL_LEQUAL);
glEnable(GL.GL_BLEND);
glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1);
glEnable(GL.GL_TEXTURE_2D);
glActiveTexture(GL.GL_TEXTURE0);
vertexShader = glCreateShader(GL.GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, new String[] {vertex}, null);
glCompileShader(vertexShader);
JFLog.log("vertex log=" + glGetShaderInfoLog(vertexShader));
fragShader = glCreateShader(GL.GL_FRAGMENT_SHADER);
glShaderSource(fragShader, 1, new String[] {fragment}, null);
glCompileShader(fragShader);
JFLog.log("fragment log=" + glGetShaderInfoLog(fragShader));
program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragShader);
glLinkProgram(program);
JFLog.log("program log=" + glGetProgramInfoLog(program));
glUseProgram(program);
vpa = glGetAttribLocation(program, "aVertexPosition");
glEnableVertexAttribArray(vpa);
tca[0] = glGetAttribLocation(program, "aTextureCoord1");
glEnableVertexAttribArray(tca[0]);
int uSampler1 = glGetUniformLocation(program, "uSampler1");
glUniform1i(uSampler1, 0);
tca[1] = glGetAttribLocation(program, "aTextureCoord2");
glEnableVertexAttribArray(tca[1]);
int uSampler2 = glGetUniformLocation(program, "uSampler2");
glUniform1i(uSampler2, 1);
mpu = glGetUniformLocation(program, "uPMatrix");
mmu = glGetUniformLocation(program, "uMMatrix");
mvu = glGetUniformLocation(program, "uVMatrix");
uUVMaps = glGetUniformLocation(program, "uUVMaps");
// JFLog.log("attribs=" + vpa + "," + tca[0] + "," + tca[1]);
// JFLog.log("uniforms=" + mpu + "," + mmu + "," + mvu + "," + uUVMaps + "," + uSampler1 + "," /*+ uSampler2*/);
initTextures();
inited = true;
}
public void reset() {
if (tl != null) releaseTextures();
ml = new ArrayList<GLModel>();
tl = new HashMap<String, GLTexture>();
mtl = new HashMap<String, GLModel>();
}
private void releaseTextures() {
Set keyset = tl.keySet();
Iterator iter = keyset.iterator();
String texidx;
GLTexture tex;
while (iter.hasNext()) {
texidx = (String)iter.next();
tex = tl.get(texidx);
if (tex.glid != -1) {
releaseTexture(tex.glid);
tex.glid = -1;
}
}
}
private void releaseTexture(int glid) {
freeglidlist.add(glid);
}
//load textures from disk to general-purpose memory
public boolean loadTextures() {
//scan thru object list and load them all
boolean ret = true;
GLObject obj;
GLModel mod;
int modCnt = ml.size();
for(int a=0;a<modCnt;a++) {
mod = ml.get(a);
int objCnt = mod.ol.size();
for(int b=0;b<objCnt;b++) {
obj = mod.ol.get(b);
int mapCnt = obj.maps.size();
for(int m=0;m<mapCnt;m++) {
GLUVMap map = obj.maps.get(m);
if (map.texloaded) continue;
if (loadTexture(mod.getTexture(map.textureIndex), map.idx)) {
map.texloaded = true;
} else {
ret = false;
}
}
}
}
return ret;
}
private boolean loadTexture(String fn, int idx) {
if (fn == null) return false;
GLTexture tex;
tex = tl.get(fn);
if (tex != null) {
tex.refcnt++;
return true;
}
needinittex = true;
tex = new GLTexture(idx);
tex.name = fn;
if (!tex.load(fn)) {
JFLog.log("Error:Failed to load texture:" + fn);
return false;
}
tex.refcnt = 1;
tl.put(fn, tex);
return true;
}
//directly load a texture
public boolean setTexture(String fn, int px[], int w, int h, int idx) {
GLTexture tex = tl.get(fn);
if (tex == null) {
tex = new GLTexture(idx);
tl.put(fn, tex);
} else {
tex.loaded = false;
}
tex.set(px, w, h);
needinittex = true;
return false;
}
//load textures into video memory (texture objects)
boolean initTextures() {
if (!needinittex) {
return true;
}
//setup blankTexture
if (blankTexture.glid == -1) initTexture(blankTexture);
//first uninit any that have been deleted
if (freeglidlist.size() > 0) uninitTextures();
//scan thru object list and load them all
Set keyset = tl.keySet();
Iterator iter = keyset.iterator();
String texidx;
while (iter.hasNext()) {
texidx = (String)iter.next();
if (!initTexture(tl.get(texidx))) return false;
}
needinittex = false;
return true;
}
private boolean initTexture(GLTexture tex) {
return tex.load();
}
private boolean uninitTextures() {
while (freeglidlist.size() > 0) {
uninitTexture(freeglidlist.get(0));
freeglidlist.remove(0);
}
return true;
}
private boolean uninitTexture(int glid) {
int id[] = new int[1];
id[0] = glid;
glDeleteTextures(1, id);
return true;
}
public void releaseUnusedTextures() {
Set keyset = tl.keySet();
Iterator iter = keyset.iterator();
String texidx;
while (iter.hasNext()) {
texidx = (String)iter.next();
if (tl.get(texidx).refcnt == 0) releaseTexture(tl.get(texidx).glid);
}
}
/** Release a cloned model @ index.
*/
public void releaseModel(int idx) {
GLModel mod;
GLObject obj;
mod = ml.get(idx);
int size = mod.ol.size();
for(int a=0;a<size;a++) {
obj = mod.ol.get(a);
for(int m=0;m<obj.maps.size();m++) {
GLUVMap map = obj.maps.get(m);
tl.get(mod.getTexture(map.textureIndex)).refcnt--;
}
}
ml.remove(idx);
}
public int modelCount() { return ml.size(); }
public boolean addModel(GLModel mod) { return addModel(mod, 0); } //places Model at start of list
public boolean addModel(GLModel mod, int idx) { if (mod == null) return false; ml.add(idx, mod); return true;} //place Models with transparent textures last
public int indexOfModel(GLModel mod) { return ml.indexOf(mod); }
public void removeModel(int idx) { ml.remove(idx); }
public void removeModel(GLModel mod) { ml.remove(mod); }
public void nextFrame(int objidx) { ml.get(objidx).nextFrame(); }
public void setFrame(int objidx, int frame) { ml.get(objidx).setFrame(frame); }
public void modelTranslate(int idx, float x, float y, float z) { ml.get(idx).translate(x,y,z); }
public void modelRotate(int idx, float angle, float x, float y, float z) { ml.get(idx).rotate(angle,x,y,z); }
public void modelScale(int idx, float x, float y, float z) { ml.get(idx).scale(x,y,z); }
/** Loads a .3DS file into the template array.
* Use addModel() to add a clone into the render scene.
*/
public GLModel load3DS(String fn) {
GLModel mod;
mod = mtl.get(fn);
if (mod != null) {
mod.refcnt++;
return mod;
}
GL_3DS loader = new GL_3DS();
mod = loader.load(fn);
if (mod == null) return null;
mtl.put(fn, mod);
mod.refcnt = 1;
mod = (GLModel)mod.clone();
return mod;
}
/** Loads a .blend file into the template array.
* Use addModel() to add a clone into the render scene.
*/
public GLModel loadBlend(String fn) {
GLModel mod;
mod = mtl.get(fn);
if (mod != null) {
mod.refcnt++;
return mod;
}
GL_BLEND loader = new GL_BLEND();
mod = loader.load(fn);
if (mod == null) return null;
mtl.put(fn, mod);
mod.refcnt = 1;
mod = (GLModel)mod.clone();
return mod;
}
/** Loads a .JF3D file into the template array.
* Use addModel() to add a clone into the render scene.
*/
public GLModel loadJF3D(String fn) {
GLModel mod;
mod = mtl.get(fn);
if (mod != null) {
mod.refcnt++;
return mod;
}
GL_JF3D loader = new GL_JF3D();
mod = loader.load(fn);
if (mod == null) return null;
mtl.put(fn, mod);
mod.refcnt = 1;
mod = (GLModel)mod.clone();
return mod;
}
/** Clones a pre-loaded model.
* Use addModel() to add into the render scene.
*/
public GLModel cloneModel(String fn) {
GLModel mod = mtl.get(fn);
if (mod == null) return null;
mod.refcnt++;
return (GLModel)mod.clone();
}
public void unloadModel(GLModel mod) {
mod.refcnt--;
}
//this will release all unused models
public void releaseModel() {
Set keyset = mtl.keySet();
Iterator iter = keyset.iterator();
String idx;
GLModel mod;
while (iter.hasNext()) {
idx = (String)iter.next();
mod = mtl.get(idx);
if (mod.refcnt == 0) {
mtl.remove(idx);
}
}
}
}