/*
*EERT = EERT enhanced rendering technology
*
*Copyright (C) [2008] [Robert "BuRnEr" Schadek]
*This program is free software; you can redistribute it and/or modify it under
*the terms of the GNU General Public License as published by the Free Software
*Foundation; either version 3 of the License,
*or (at your option) any later version.
*This program is distributed in the hope that it will be useful, but WITHOUT
*ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
*FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*You should have received a copy of the GNU General Public License along with
*this program; if not, see <http://www.gnu.org/licenses/>.
*/
package Engine;
import Types.Geometrie.Obj;
import Types.Geometrie.ObjIns;
import Types.Geometrie.Vector;
import Util.Geometrie.VectorUtil;
import java.util.LinkedList;
import javax.media.opengl.GL;
public class EOcNode {
private EOcMaster root;
public EOcNode[] childs;
public ObjIns[] objs;
private boolean[] drawn;
private Vector middle;
private float radius;
private int depth;
private float bSize;
private float bHalf;
public EOcNode(EOcMaster root, ObjIns[] objs, Vector middle, float radius, float bSize, boolean[] drawn, int depth) {
this.root = root;
this.middle = middle;
this.depth = depth;
this.radius = radius;
this.drawn = drawn;
this.bSize = bSize;
this.bHalf = this.bSize / 2;
this.objs = checkAllObjects(objs);
//Octree Depth
if (this.depth < this.root.treeDepth) {
this.childs = makeChilds();
}
}
public void draw(GL gl) {
//If this node has no more child
//draw all objIns not yet drawn
if (this.childs == null) {
float dis;
//If the distance is 0.0
//the node is not within
//the frustun
if(this.root.engine.frame.octree)drawBox(gl);
if (0.0f == (dis = SphereInFrustum(this.middle.x, this.middle.y, this.middle.z, this.radius))) {
return;
} else {
this.root.engine.eInfo.drawnNodes++;
for (ObjIns obIns : this.objs) {
if (!this.root.drawn[obIns.objInsNumber]) {
dis = (float) Math.sqrt(Math.pow(this.root.cam.loc.x - obIns.origin.x, 2) +
Math.pow(this.root.cam.loc.y - obIns.origin.y, 2) +
Math.pow(this.root.cam.loc.z - obIns.origin.z, 2));
//below this the actually rendering take place
obIns.parent.render(obIns.objInsNumber, dis);
this.root.drawn[obIns.objInsNumber] = true;
} else {
continue;
}
}
}
} else {
//drawBox(gl);
for (EOcNode child : this.childs) {
child.draw(gl);
}
return;
}
}
/* public void drawLight(GL gl) {
//If this node has no more child
//draw all objIns not yet drawn
if (this.childs == null) {
if(sphereInSphere()) {
for (ObjIns obIns : this.objs) {
if (!this.root.drawn[obIns.objInsNumber]) {
float dis = VectorUtil.distance(obIns.origin, this.root.cam.loc);
obIns.parent.findFacesFacingLight(dis, obIns.objInsNumber);
obIns.parent.renderShadow(obIns.objInsNumber);
this.root.drawn[obIns.objInsNumber] = true;
} else {
continue;
}
}
} else {
return;
}
} else {
for (EOcNode child : this.childs) {
child.drawLight(gl);
}
return;
}
}
//this one tests if a sphere namely
//a objIns is in the viewSphere
private boolean sphereInSphere() {
float dis = Math.abs(VectorUtil.distance(this.root.cam.frustMiddle, this.middle));
if(dis - this.radius > this.root.cam.frustRadius) {
return false;
}
return true;
}*/
private float SphereInFrustum(float x, float y, float z, float radius) {
int p;
float d = 0.0f;
for (p = 0; p < 6; p++) {
d = this.root.frustum[p][0] * x + this.root.frustum[p][1] * y + this.root.frustum[p][2] * z + this.root.frustum[p][3];
if (d <= -radius) {
return 0;
}
}
return d + radius;
}
private ObjIns[] checkAllObjects(ObjIns[] objs) {
LinkedList<ObjIns> objects = new LinkedList<ObjIns>();
for (ObjIns obj : objs) {
if (checkForObj(obj)) {
objects.add(obj);
}
}
ObjIns[] ret = new ObjIns[objects.size()];
return ret = objects.toArray(ret);
}
private boolean checkForObj(ObjIns obj) {
//Cheated a bit
//Just check a sphear around the box against the sphear around the Obj
//the error-margin shouldn't be to big, but the check is much cheaper
//and easier to understand
float dis = (float) Math.sqrt((obj.origin.x - this.middle.x) * (obj.origin.x - this.middle.x) +
(obj.origin.y - this.middle.y) * (obj.origin.y - this.middle.y) +
(obj.origin.z - this.middle.z) * (obj.origin.z - this.middle.z));
if (dis - obj.boundSph < this.radius) {
return true;
} else {
return false;
}
}
private void drawBox(GL gl) {
gl.glPushMatrix();
gl.glTranslatef(this.middle.x, this.middle.y, this.middle.z);
gl.glColor3f(0.4f, 0.2f, 0.7f);
//Back
gl.glBegin(GL.GL_LINE_LOOP);
gl.glVertex3f(-this.radius, -this.radius, -this.radius);
gl.glVertex3f(this.radius, -this.radius, -this.radius);
gl.glVertex3f(this.radius, this.radius, -this.radius);
gl.glVertex3f(-this.radius, this.radius, -this.radius);
gl.glEnd();
//Front
gl.glBegin(GL.GL_LINE_LOOP);
gl.glVertex3f(-this.radius, -this.radius, this.radius);
gl.glVertex3f(this.radius, -this.radius, this.radius);
gl.glVertex3f(this.radius, this.radius, this.radius);
gl.glVertex3f(-this.radius, this.radius, this.radius);
gl.glEnd();
//Left
gl.glBegin(GL.GL_LINE_LOOP);
gl.glVertex3f(-this.radius, -this.radius, -this.radius);
gl.glVertex3f(-this.radius, -this.radius, this.radius);
gl.glVertex3f(-this.radius, this.radius, this.radius);
gl.glVertex3f(-this.radius, this.radius, -this.radius);
gl.glEnd();
//Right
gl.glBegin(GL.GL_LINE_LOOP);
gl.glVertex3f(this.radius, -this.radius, -this.radius);
gl.glVertex3f(this.radius, -this.radius, this.radius);
gl.glVertex3f(this.radius, this.radius, this.radius);
gl.glVertex3f(this.radius, this.radius, -this.radius);
gl.glEnd();
gl.glColor3f(1f,1f,1f);
gl.glPopMatrix();
}
private EOcNode[] makeChilds() {
LinkedList<EOcNode> tmpChilds = new LinkedList<EOcNode>();
//important needs to be created within this contidional execution
//otherwise the child test in draw does not work
EOcNode ch1 = new EOcNode(this.root, this.objs, new Vector(middle.x - this.bHalf,
middle.y - this.bHalf,
middle.z - this.bHalf), this.radius / 2, this.bHalf, this.drawn, depth + 1);
if (ch1.objs.length > 0) {
tmpChilds.add(ch1);
}
EOcNode ch2 = new EOcNode(this.root, this.objs, new Vector(middle.x - this.bHalf,
middle.y - this.bHalf,
middle.z + this.bHalf), this.radius / 2, this.bHalf, this.drawn, depth + 1);
if (ch2.objs.length > 0) {
tmpChilds.add(ch2);
}
EOcNode ch3 = new EOcNode(this.root, this.objs, new Vector(middle.x - this.bHalf,
middle.y + this.bHalf,
middle.z - this.bHalf), this.radius / 2, this.bHalf, this.drawn, depth + 1);
if (ch3.objs.length > 0) {
tmpChilds.add(ch3);
}
EOcNode ch4 = new EOcNode(this.root, this.objs, new Vector(middle.x - this.bHalf,
middle.y + this.bHalf,
middle.z + this.bHalf), this.radius / 2, this.bHalf, this.drawn, depth + 1);
if (ch4.objs.length > 0) {
tmpChilds.add(ch4);
}
EOcNode ch5 = new EOcNode(this.root, this.objs, new Vector(middle.x + this.bHalf,
middle.y - this.bHalf,
middle.z - this.bHalf), this.radius / 2, this.bHalf, this.drawn, depth + 1);
if (ch5.objs.length > 0) {
tmpChilds.add(ch5);
}
EOcNode ch6 = new EOcNode(this.root, this.objs, new Vector(middle.x + this.bHalf,
middle.y - this.bHalf,
middle.z + this.bHalf), this.radius / 2, this.bHalf, this.drawn, depth + 1);
if (ch6.objs.length > 0) {
tmpChilds.add(ch6);
}
EOcNode ch7 = new EOcNode(this.root, this.objs, new Vector(middle.x + this.bHalf,
middle.y + this.bHalf,
middle.z - this.bHalf), this.radius / 2, this.bHalf, this.drawn, depth + 1);
if (ch7.objs.length > 0) {
tmpChilds.add(ch7);
}
EOcNode ch8 = new EOcNode(this.root, this.objs, new Vector(middle.x + this.bHalf,
middle.y + this.bHalf,
middle.z + this.bHalf), this.radius / 2, this.bHalf, this.drawn, depth + 1);
if (ch8.objs.length > 0) {
tmpChilds.add(ch8);
}
if (tmpChilds.size() == 0) {
return null;
} else {
EOcNode[] retChilds = new EOcNode[tmpChilds.size()];
this.root.numNodes += retChilds.length;
return retChilds = tmpChilds.toArray(retChilds);
}
}
}