package com.nilunder.bdx;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import javax.vecmath.*;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.Texture.TextureWrap;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g3d.Environment;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.attributes.*;
import com.badlogic.gdx.graphics.g3d.utils.MeshPartBuilder;
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.utils.JsonReader;
import com.badlogic.gdx.utils.JsonValue;
import com.bulletphysics.collision.broadphase.BroadphaseInterface;
import com.bulletphysics.collision.broadphase.DbvtBroadphase;
import com.bulletphysics.collision.dispatch.CollisionDispatcher;
import com.bulletphysics.collision.dispatch.CollisionWorld;
import com.bulletphysics.collision.dispatch.DefaultCollisionConfiguration;
import com.bulletphysics.collision.narrowphase.PersistentManifold;
import com.bulletphysics.dynamics.DiscreteDynamicsWorld;
import com.bulletphysics.dynamics.RigidBody;
import com.bulletphysics.dynamics.constraintsolver.SequentialImpulseConstraintSolver;
import com.bulletphysics.linearmath.Transform;
import com.nilunder.bdx.gl.*;
import com.nilunder.bdx.gl.Mesh;
import com.nilunder.bdx.utils.*;
import com.nilunder.bdx.inputs.*;
import com.nilunder.bdx.components.*;
import com.nilunder.bdx.GameObject.ArrayListGameObject;
import com.nilunder.bdx.utils.Color;
public class Scene implements Named{
public static HashMap<String, Instantiator> instantiators;
public JsonValue json;
public String name;
public LinkedListNamed<GameObject> objects;
public LinkedListNamed<Light> lights;
public Camera camera;
public ArrayListNamed<Camera> cameras;
public HashMap<Model, Vector2f> modelToFrame;
public boolean visible;
private FileHandle scene;
public HashMap<String, Mesh> meshes;
public HashMap<String,Texture> textures;
public HashMap<String,Material> materials;
public Material defaultMaterial;
private Mesh defaultMesh;
public DiscreteDynamicsWorld world;
private ArrayList<GameObject> toBeAdded;
private ArrayList<GameObject> toBeRemoved;
private boolean requestedRestart;
public boolean paused;
private Instantiator instantiator;
public Viewport viewport;
public HashMap<String, GameObject> templates;
public ArrayList<ScreenShader> screenShaders;
public boolean renderPassthrough = true;
public RenderBuffer lastFrameBuffer;
public Environment environment;
static private ShapeRenderer shapeRenderer;
private ArrayList<ArrayList<Object>> drawCommands;
static public boolean clearColorDefaultSet;
private Color fogColor;
private float fogStart;
private float fogDepth;
private boolean fogOn;
private boolean valid;
private boolean requestedEnd;
public Scene(String name){
this(Gdx.files.internal("bdx/scenes/" + name + ".bdx"), instantiators.get(name));
}
public Scene(FileHandle scene, Instantiator instantiator){
this.scene = scene;
if (instantiator != null){
this.instantiator = instantiator;
}else{
this.instantiator = new Instantiator();
}
}
public Vector3f gravity(){
return world.getGravity(new Vector3f());
}
public void gravity(Vector3f gravity){
world.setGravity(gravity);
}
public String name(){
return name;
}
public static class BDXIntAttribute extends IntAttribute {
public final static String ShadelessAlias = "Shadeless";
public final static long Shadeless = register(ShadelessAlias);
public BDXIntAttribute(){
super(Shadeless, 0);
}
};
public static class BDXColorAttribute extends ColorAttribute {
public final static String TintAlias = "Tint";
public final static long Tint = register(TintAlias);
public final static String EmitAlias = "Emit";
public final static long Emit = register(EmitAlias);
static {
Mask = Mask | Tint | Emit;
}
private BDXColorAttribute(long type, float r, float g, float b){
super(type, r, g, b, 0);
}
}
public void init(){
requestedRestart = false;
requestedEnd = false;
paused = false;
visible = true;
if (shapeRenderer == null)
shapeRenderer = new ShapeRenderer();
drawCommands = new ArrayList<ArrayList<Object>>();
lastFrameBuffer = new RenderBuffer(null);
environment = new Environment();
environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0, 0, 0, 1));
environment.set(new PointLightsAttribute());
environment.set(new SpotLightsAttribute());
environment.set(new DirectionalLightsAttribute());
screenShaders = new ArrayList<ScreenShader>();
defaultMaterial = new Material("__BDX_DEFAULT");
defaultMaterial.set(new ColorAttribute(ColorAttribute.AmbientLight, 1, 1, 1, 1));
defaultMaterial.set(new ColorAttribute(ColorAttribute.Diffuse, 1, 1, 1, 1));
defaultMaterial.set(new BlendingAttribute());
defaultMaterial.set(new BDXColorAttribute(BDXColorAttribute.Tint, 0, 0, 0));
defaultMesh = new Mesh(new ModelBuilder().createBox(1.0f, 1.0f, 1.0f, defaultMaterial, Usage.Position | Usage.Normal | Usage.TextureCoordinates), this);
meshes = new HashMap<String, Mesh>();
textures = new HashMap<String,Texture>();
materials = new HashMap<String,Material>();
modelToFrame = new HashMap<>();
materials.put(defaultMaterial.id, defaultMaterial);
BroadphaseInterface broadphase = new DbvtBroadphase();
DefaultCollisionConfiguration collisionConfiguration = new DefaultCollisionConfiguration();
SequentialImpulseConstraintSolver solver = new SequentialImpulseConstraintSolver();
CollisionDispatcher dispatcher = new CollisionDispatcher(collisionConfiguration);
toBeAdded = new ArrayList<GameObject>();
toBeRemoved = new ArrayList<GameObject>();
objects = new LinkedListNamed<GameObject>();
lights = new LinkedListNamed<Light>();
templates = new HashMap<String, GameObject>();
json = new JsonReader().parse(scene);
name = json.get("name").asString();
world = new DiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);
world.setDebugDrawer(new Bullet.DebugDrawer(json.get("physviz").asBoolean()));
gravity(new Vector3f(0, 0, -json.get("gravity").asFloat()));
float[] ac = json.get("ambientColor").asFloatArray();
ambientLight(new Color(ac[0], ac[1], ac[2], 1));
if (!clearColorDefaultSet) {
float[] cc = json.get("clearColor").asFloatArray();
Bdx.display.clearColor.set(cc[0], cc[1], cc[2], 0);
clearColorDefaultSet = true;
}
if (json.get("framerateProfile").asBoolean()){
Bdx.profiler.init();
}
float[] fc = json.get("clearColor").asFloatArray();
fogColor = new Color(fc[0], fc[1], fc[2], 1);
fog(json.get("mistOn").asBoolean());
fogRange(json.get("mistStart").asFloat(), json.get("mistDepth").asFloat());
for (JsonValue mat : json.get("materials")){
String texName = mat.get("texture").asString();
boolean hasAlpha = mat.get("alpha_blend").asString().equals("ALPHA");
float opacity = hasAlpha ? mat.get("opacity").asFloat() : 1;
Material material = new Material(mat.name);
float[] c = mat.get("color").asFloatArray();
material.set(ColorAttribute.createDiffuse(c[0], c[1], c[2], opacity));
float[] s = mat.get("spec_color").asFloatArray();
material.set(ColorAttribute.createSpecular(s[0], s[1], s[2], 1));
material.set(FloatAttribute.createShininess(mat.get("shininess").asFloat()));
material.set(new BDXColorAttribute(BDXColorAttribute.Tint, 0, 0, 0));
IntAttribute shadeless = (IntAttribute) new BDXIntAttribute();
if (mat.get("shadeless").asBoolean())
shadeless.value = 1;
material.set(shadeless);
float emitStrength = mat.get("emit").asFloat();
material.set(new BDXColorAttribute(BDXColorAttribute.Emit, emitStrength, emitStrength, emitStrength));
if (mat.get("backface_culling").asBoolean())
material.set(new IntAttribute(IntAttribute.CullFace, GL20.GL_BACK));
else
material.set(new IntAttribute(IntAttribute.CullFace, GL20.GL_NONE));
if (texName != null){
Texture texture = textures.get(texName);
if (texture == null){
texture = new Texture(Gdx.files.internal("bdx/textures/" + texName));
textures.put(texName, texture);
}
texture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
material.texture(texture);
}
material.set(new DepthTestAttribute());
if (hasAlpha){
BlendingAttribute ba = new BlendingAttribute(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
ba.opacity = opacity;
material.set(ba);
material.set(FloatAttribute.createAlphaTest(0.01f)); // Discard pixels that fail this alpha test (sub-1% alpha)
material.backToFrontSorting(true); // Turn on back-to-front sorting for alpha-enabled objects by default
}else{
BlendingAttribute ba = new BlendingAttribute();
ba.blended = false;
material.set(ba);
}
materials.put(mat.name, material);
}
for (JsonValue model: json.get("models")){
meshes.put(model.name, new Mesh(createModel(model), this, model.name));
}
HashMap<String, JsonValue> fonts = new HashMap<>();
for (JsonValue fontj: json.get("fonts")){
String font = fontj.asString();
fonts.put(font, new JsonReader().parse(Gdx.files.internal("bdx/fonts/"+font+".fntx")));
}
FAnim.loadActions(json.get("actions"));
for (JsonValue gobj: json.get("objects")){
GameObject g = instantiator.newObject(gobj);
g.json = gobj;
g.name = gobj.name;
g.scene = this;
g.props = new HashMap<String, JsonValue>();
for (JsonValue prop : gobj.get("properties")){
g.props.put(prop.name, prop);
}
String meshName = gobj.get("mesh_name").asString();
if (meshName != null){
g.visibleNoChildren(gobj.get("visible").asBoolean());
g.mesh(meshName);
}else{
g.visibleNoChildren(false);
g.mesh(defaultMesh);
}
com.badlogic.gdx.graphics.Mesh mesh = g.modelInstance.model.meshes.first();
float[] trans = gobj.get("transform").asFloatArray();
JsonValue origin = json.get("origins").get(meshName);
JsonValue dimensions = json.get("dimensions").get(meshName);
g.origin = origin == null ? new Vector3f() : new Vector3f(origin.asFloatArray());
g.dimensionsNoScale = dimensions == null ? new Vector3f(1, 1, 1) : new Vector3f(dimensions.asFloatArray());
JsonValue physics = gobj.get("physics");
g.currBodyType = GameObject.BodyType.valueOf(physics.get("body_type").asString());
g.currBoundsType = GameObject.BoundsType.valueOf(physics.get("bounds_type").asString());
g.body = Bullet.makeBody(mesh, trans, g.origin, g.currBodyType, g.currBoundsType, physics);
g.body.setUserPointer(g);
g.scale(getGLMatrixScale(trans));
String type = gobj.get("type").asString();
if (type.equals("FONT")){
Text t = (Text)g;
t.font = fonts.get(gobj.get("font").asString());
t.text(gobj.get("text").asString());
t.capacity = t.text().length();
String align = gobj.get("alignment").asString();
if (align.equals("RIGHT"))
t.alignment(Text.Alignment.RIGHT);
else if (align.equals("CENTER"))
t.alignment(Text.Alignment.CENTER);
else
t.alignment(Text.Alignment.LEFT);
}else if (type.equals("LAMP")){
JsonValue settings = gobj.get("lamp");
Light l = (Light)g;
if (settings.getString("type").equals("SUN"))
l.type = Light.Type.SUN;
else if (settings.getString("type").equals("SPOT"))
l.type = Light.Type.SPOT;
else // POINT lamps; HEMI and AREA aren't supported, so they're turned into POINTs
l.type = Light.Type.POINT;
l.energy(settings.getFloat("energy"));
float[] c = settings.get("color").asFloatArray();
l.color(new Color(c[0], c[1], c[2], c[3]));
if (l.type.equals(Light.Type.SPOT)) {
l.spotSize(settings.getFloat("spot_size"));
}
}else if (type.equals("CAMERA")){
Camera c = (Camera)g;
float[] projection = gobj.get("camera").get("projection").asFloatArray();
Vector2f resolution = new Vector2f(json.get("resolution").asFloatArray());
if (gobj.get("camera").get("type").asString().equals("PERSP")){
c.initData(Camera.Type.PERSPECTIVE);
c.size(resolution);
c.resolution(resolution);
c.projection(new Matrix4f(projection));
c.fov(c.fov());
}else{
c.initData(Camera.Type.ORTHOGRAPHIC);
c.size(resolution);
c.resolution(resolution);
c.zoom(2 / projection[0]);
}
Matrix4 pm = new Matrix4(projection);
pm.inv();
Vector3 vec = new Vector3(0, 0, -1);
vec.prj(pm);
c.near(-vec.z);
vec.set(0, 0, 1);
vec.prj(pm);
c.far(-vec.z);
}
templates.put(g.name, g);
}
hookParentChild();
cameras = new ArrayListNamed<Camera>();
addInstances();
camera = (Camera) objects.get(json.get("cameras").asStringArray()[0]);
String frameType = json.get("frame_type").asString();
Viewport.Type viewportType;
if (frameType.equals("LETTERBOX")){
viewportType = Viewport.Type.LETTERBOX;
}else if (frameType.equals("EXTEND")){
viewportType = Viewport.Type.EXTEND;
}else{ // "SCALE"
viewportType = Viewport.Type.SCALE;
}
viewport = new Viewport(this, viewportType);
for (GameObject g : sortByPriority(new ArrayList<GameObject>(objects))){
initGameObject(g);
}
valid = true;
}
public void dispose(){
valid = false;
for (GameObject g : objects)
g.end();
lastFrameBuffer.dispose();
defaultMesh = null;
meshes = null;
for (Texture t : textures.values())
t.dispose();
for (ScreenShader s : screenShaders)
s.dispose();
for (Camera c : cameras) {
if (c.renderBuffer != null)
c.renderBuffer.dispose();
}
for (Material m : materials.values()) {
if (m.shader != null)
m.shader.dispose();
if (m.currentTexture != null)
m.currentTexture.dispose();
}
}
private void hookParentChild(){
for (GameObject g : templates.values()){
String parentName = g.json.get("parent").asString();
if (parentName != null){
g.parent(templates.get(parentName));
}
}
}
private ArrayList<GameObject> sortByPriority(ArrayList<GameObject> objects){
for (GameObject g : objects){
if (g.json.get("use_priority").asBoolean()){
Collections.swap(objects, 0, objects.indexOf(g));
break;
}
}
return objects;
}
private void addInstances(){
for (GameObject gobj : new ArrayList<GameObject>(templates.values())){
if (gobj.json.get("active").asBoolean() && gobj.parent() == null){
GameObject g = clone(gobj);
addToWorld(g);
}
}
for (GameObject g : toBeAdded){
objects.add(g);
if (g instanceof Light)
lights.add((Light) g);
}
toBeAdded.clear();
}
private GameObject cloneNoChildren(GameObject gobj){
GameObject g = instantiator.newObject(gobj.json);
g.json = gobj.json;
g.name = gobj.name;
g.visibleNoChildren(gobj.visible());
g.scene = this;
g.mesh(gobj.mesh());
g.body = Bullet.cloneBody(gobj.body);
g.currBodyType = gobj.currBodyType;
g.currBoundsType = gobj.currBoundsType;
g.origin = gobj.origin;
g.dimensionsNoScale = gobj.dimensionsNoScale;
g.body.setUserPointer(g);
g.scale(gobj.scale());
g.props = new HashMap<String, JsonValue>(gobj.props);
if (g instanceof Camera){
Camera c = (Camera)g;
Camera cobj = (Camera)gobj;
c.initData(cobj.type);
c.size(cobj.size());
c.resolution(cobj.resolution());
if (c.type == Camera.Type.PERSPECTIVE){
c.fov(cobj.fov());
}else{
c.zoom(cobj.zoom());
}
c.near(cobj.near());
c.far(cobj.far());
c.update();
cameras.add(c);
}else if (g instanceof Text){
Text t = (Text)g;
Text tt = (Text)gobj;
t.font = tt.font;
t.text(tt.text());
t.capacity = tt.capacity;
t.mesh(t.mesh().copy());
t.alignment(tt.alignment());
}else if (g instanceof Light){
Light l = (Light)g;
Light ll = (Light)gobj;
l.energy(ll.energy());
l.color(ll.color());
l.spotSize(ll.spotSize());
l.exponent(ll.exponent());
l.type = ll.type;
l.makeLightData();
l.updateLight();
l.on(true);
}
return g;
}
private GameObject clone(GameObject gobj){
String instance = gobj.json.get("instance").asString();
GameObject inst = gobj;
if (instance != null)
gobj = templates.get(instance);
GameObject g = cloneNoChildren(gobj);
for (GameObject c : gobj.children){
GameObject nc = clone(c);
nc.parent(g);
}
if (instance != null){
g.position(inst.position());
Matrix3f ori = inst.orientation();
ori.mul(g.orientation());
g.orientation(ori);
g.scale(inst.scale());
g.props.putAll(inst.props);
for (GameObject c : inst.children){
GameObject nc = clone(c);
nc.parent(g);
}
}
return g;
}
private void initGameObject(GameObject gobj){
if (!gobj.initialized) {
gobj.init();
gobj.initialized = true;
}
}
private void addToWorld(GameObject gobj){
if (gobj.currBodyType != GameObject.BodyType.NO_COLLISION){
world.addRigidBody(gobj.body, gobj.json.get("physics").get("group").asShort(), gobj.json.get("physics").get("mask").asShort());
if (gobj.currBodyType == GameObject.BodyType.STATIC || gobj.currBodyType == GameObject.BodyType.SENSOR)
gobj.deactivate();
if (gobj.parent() != null && gobj.parent().body.getCollisionShape().isCompound())
world.removeRigidBody(gobj.body);
}
toBeAdded.add(gobj);
for (GameObject g : gobj.children){
addToWorld(g);
}
}
public GameObject add(GameObject gobj){
GameObject p = clone(gobj);
addToWorld(p);
if (gobj.children.isEmpty()){
initGameObject(p);
}else{
ArrayList<GameObject> parentAndChildren = new ArrayList<GameObject>();
parentAndChildren.add(p);
parentAndChildren.addAll(p.childrenRecursive());
parentAndChildren = sortByPriority(parentAndChildren);
for (GameObject g : parentAndChildren){
initGameObject(g);
}
}
return p;
}
public GameObject addNoChildren(GameObject gobj){
GameObject g = cloneNoChildren(gobj);
addToWorld(g);
initGameObject(g);
return g;
}
public GameObject add(String name){
return add(templates.get(name));
}
public GameObject addNoChildren(String name){
return addNoChildren(templates.get(name));
}
public void remove(GameObject g){
toBeAdded.remove(g);
toBeRemoved.add(g);
}
public RayHit ray(Vector3f src, Vector3f vec, String... props){
return ray(src, vec, (short)~0, (short)~0, props);
}
public RayHit ray(Vector3f src, Vector3f vec, short group, short mask, String... props){
Vector3f to = new Vector3f(src);
to.add(vec);
CollisionWorld.ClosestRayResultCallback rrc = new CollisionWorld.ClosestRayResultCallback(src, to);
rrc.collisionFilterGroup = group;
rrc.collisionFilterMask = mask;
world.rayTest(src, to, rrc);
if (!rrc.hasHit())
return null;
RayHit rh = new RayHit();
rh.object = (GameObject) (rrc.collisionObject.getUserPointer());
rh.position = rrc.hitPointWorld;
rh.normal = rrc.hitNormalWorld.normalized();
for (String p : props){
if (!rh.object.props.containsKey(p))
return null;
}
return rh;
}
public ArrayList<RayHit> xray(Vector3f src, Vector3f vec, boolean includeAll, String... props){
return xray(src, vec, includeAll, (short)~0, (short)~0, props);
}
public ArrayList<RayHit> xray(Vector3f src, Vector3f vec, boolean includeAll, short group, short mask, String... props){
Vector3f startPos = new Vector3f(src);
Vector3f dist = new Vector3f(vec);
ArrayList<RayHit> hits = new ArrayList<RayHit>();
ArrayList<GameObject> hitObjects = new ArrayList<GameObject>();
boolean finished = false;
while (!finished){
RayHit ray = ray(startPos, dist, group, mask);
if (ray != null){
boolean skip = false;
for (String prop : props) {
if (!ray.object.props.containsKey(prop)) {
skip = true;
break;
}
}
if (!skip && (!hitObjects.contains(ray.object) || includeAll)) {
hits.add(ray);
hitObjects.add(ray.object);
}
float delta = ray.position.minus(startPos).length();
delta = Math.max(0.005f, delta);
Vector3f n = new Vector3f(vec);
n.length(delta);
startPos.add(n);
dist.sub(n);
}
else
finished = true;
}
return hits;
}
public ArrayList<RayHit> xray(Vector3f src, Vector3f vec, String... props) {
return xray(src, vec, false, props);
}
public Model createModel(JsonValue model) {
ModelBuilder builder = new ModelBuilder();
builder.begin();
short idx = 0;
for (JsonValue mat : model){
Material m = materials.get(mat.name);
if (mat.name.equals(defaultMaterial.id))
m = new Material(m);
MeshPartBuilder mpb = builder.part(model.name, GL20.GL_TRIANGLES,
Usage.Position | Usage.Normal | Usage.TextureCoordinates, m);
float verts[] = mat.asFloatArray();
mpb.vertex(verts);
int len = verts.length / Bdx.VERT_STRIDE;
try{
for (short i = 0; i < len; ++i){
mpb.index(idx);
idx += 1;
}
}catch (Error e){
throw new RuntimeException("MODEL ERROR: Models with more than 32767 vertices are not supported. " + model.name + " has " + Integer.toString(len) + " vertices.");
}
}
return builder.end();
}
public void restart(){
requestedRestart = true;
}
public void pause(){
paused = true;
}
public void play(){
paused = false;
}
private void detectCollisions(){
for (GameObject g : objects){
ArrayListGameObject hitLast = g.touchingObjectsLast;
g.touchingObjectsLast = g.touchingObjects;
g.touchingObjects = hitLast;
g.touchingObjects.clear();
g.contactManifolds.clear();
}
int numManifolds = world.getDispatcher().getNumManifolds();
for (int i = 0; i < numManifolds; ++i){
PersistentManifold mani = world.getDispatcher().getManifoldByIndexInternal(i);
if (mani.getNumContacts() > 0){
RigidBody a = (RigidBody)mani.getBody0();
RigidBody b = (RigidBody)mani.getBody1();
GameObject A = (GameObject)a.getUserPointer();
GameObject B = (GameObject)b.getUserPointer();
A.touchingObjects.add(B);
B.touchingObjects.add(A);
A.contactManifolds.add(mani);
B.contactManifolds.add(mani);
}
}
}
private void setGLMatrixScale(float[] m, Vector3f scale){
m[0] *= scale.x;
m[1] *= scale.x;
m[2] *= scale.x;
m[4] *= scale.y;
m[5] *= scale.y;
m[6] *= scale.y;
m[8] *= scale.z;
m[9] *= scale.z;
m[10] *= scale.z;
}
private Vector3f getGLMatrixScale(float[] m){
Vector3f s = new Vector3f();
s.x = m[0];
s.y = m[1];
s.z = m[2];
float x = s.length();
s.x = m[4];
s.y = m[5];
s.z = m[6];
float y = s.length();
s.x = m[8];
s.y = m[9];
s.z = m[10];
float z = s.length();
s.x = x; s.y = y; s.z = z;
return s;
}
private void updateVisuals(){
Transform trans = new Transform();
float[] mt = new float[16];
for (GameObject g : objects){
if (g.visible()){
g.body.getWorldTransform(trans);
trans.getOpenGLMatrix(mt);
setGLMatrixScale(mt, g.scale());
g.modelInstance.transform.set(mt);
}
}
}
private void runObjectLogic(){
if (requestedRestart){
for (GameObject g : objects){
g.endNoChildren();
}
dispose();
init();
}
Bdx.mouse.init(this);
for (Finger f : Bdx.fingers){
f.init(this);
}
for (GameObject g : objects){
if(!g.valid())
continue;
if (g instanceof Light)
((Light) g).updateLight();
for (Component c : g.components){
if (c.state != null) {
if (c.logicCounter >= 1) {
c.logicCounter -= 1;
c.state.main();
}
c.logicCounter += c.logicFrequency * Bdx.TICK_TIME;
}
}
if (g.logicCounter >= 1) {
g.logicCounter -= 1;
g.main();
}
g.logicCounter += g.logicFrequency * Bdx.TICK_TIME;
}
for (GameObject g : toBeAdded) {
objects.add(g);
if (g instanceof Light)
lights.add((Light) g);
}
toBeAdded.clear();
for (GameObject g : toBeRemoved) {
g.parent(null);
world.removeRigidBody(g.body);
objects.remove(g);
if (g instanceof Light)
lights.remove(g);
}
toBeRemoved.clear();
if (requestedEnd) {
valid = false;
dispose();
if (Bdx.scenes.contains(this))
Bdx.scenes.remove(this);
}
}
private void updateChildBodies(){
for (GameObject g : objects){
if (g.parent() == null && g.children.size() > 0 && g.body.isActive()){
g.updateChildTransforms();
}
}
}
public void ambientLight(Color color) {
ColorAttribute ca = (ColorAttribute) environment.get(ColorAttribute.AmbientLight);
ca.color.set(color);
}
public Color ambientLight(){
ColorAttribute ca = (ColorAttribute) environment.get(ColorAttribute.AmbientLight);
return new Color(ca.color);
}
public void update(){
if (!paused){
Bdx.profiler.start("__logic");
runObjectLogic();
Bdx.profiler.stop("__logic");
updateVisuals();
for (Camera cam : cameras) {
if (cam == camera || cam.renderToTexture) // Update camera if it's the main scene camera, or if it's rendering to texture
cam.update();
}
Bdx.profiler.stop("__scene");
try{
world.stepSimulation(Bdx.TICK_TIME * Bdx.physicsSpeed, 0);
}catch (NullPointerException e){
throw new RuntimeException("PHYSICS ERROR: Detected collision between Static objects set to Ghost, with Triangle Mesh bounds: Keep them seperated, or use different bounds.");
}
Bdx.profiler.stop("__physics");
updateChildBodies();
Bdx.profiler.stop("__scene");
detectCollisions();
Bdx.profiler.stop("__physics");
}
}
public void end(){
requestedEnd = true;
}
public String toString(){
return name + " <" + getClass().getName() + "> @" + Integer.toHexString(hashCode());
}
public void drawLine(Vector3f start, Vector3f end, Color color){
ArrayList<Object> commands = new ArrayList<Object>();
commands.add("drawLine");
commands.add(color);
commands.add(start);
commands.add(end);
drawCommands.add(commands);
}
public void drawPoint(Vector3f point, Color color){
ArrayList<Object> commands = new ArrayList<Object>();
commands.add("drawPoint");
commands.add(color);
commands.add(point);
drawCommands.add(commands);
}
public void executeDrawCommands(){
for (ArrayList<Object> commands : drawCommands) {
String func = (String) commands.get(0);
Color color = (Color) commands.get(1);
Vector3f start = (Vector3f) commands.get(2);
if (func.equals("drawLine")) {
Vector3f end = (Vector3f) commands.get(3);
shapeRenderer.setProjectionMatrix(camera.data.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
shapeRenderer.setColor(color);
shapeRenderer.line(start.x, start.y, start.z, end.x, end.y, end.z);
shapeRenderer.end();
}
else {
shapeRenderer.setProjectionMatrix(camera.data.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Point);
shapeRenderer.setColor(color);
shapeRenderer.point(start.x, start.y, start.z);
shapeRenderer.end();
}
}
drawCommands.clear();
}
public void fog(boolean fogOn){
this.fogOn = fogOn;
if (fogOn) {
if (environment.get(ColorAttribute.Fog) == null)
environment.set(new ColorAttribute(ColorAttribute.Fog, fogColor));
}
else {
if (environment.get(ColorAttribute.Fog) != null)
environment.remove(ColorAttribute.Fog);
}
}
public boolean fog(){
return fogOn;
}
public void fogColor(Color fogColor) {
this.fogColor.set(fogColor);
if (environment.get(ColorAttribute.Fog) != null) {
ColorAttribute ca = (ColorAttribute) environment.get(ColorAttribute.Fog);
ca.color.set(fogColor);
}
}
public Color fogColor(){
return new Color(fogColor);
}
public void fogRange(float fogStart, float fogDepth){
this.fogStart = fogStart;
this.fogDepth = fogDepth;
}
public void fogRange(Vector2f range) {
fogRange(range.x, range.y);
}
public Vector2f fogRange(){
return new Vector2f(fogStart, fogDepth);
}
public boolean valid(){
return valid;
}
}