/**
* Copyright (C) 2012 J.W.Marsden <jmarsden@plural.cc>
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package cc.plural.ecs.engine;
import cc.plural.ecs.component.geometry.GeometryComponent;
import cc.plural.ecs.component.render.RenderComponent;
import cc.plural.ecs.component.spatial.SpatialComponent;
import cc.plural.ecs.renderer.Renderer;
import cc.plural.math.Matrix3f;
import cc.plural.math.Transformation;
import java.util.ArrayList;
import java.util.List;
public class GameObject {
public final Engine engine;
public final int id;
public String name;
public GameObject parent;
public List<GameObject> children;
public List<Component> components;
public int renderPasses;
public boolean logMessages;
public SpatialComponent spatial;
public GeometryComponent geometry;
public RenderComponent render;
public boolean forceCull;
public GameObject(Engine engine, int id) {
this.engine = engine;
this.id = id;
this.parent = null;
this.children = new ArrayList<GameObject>();
this.components = new ArrayList<Component>();
this.spatial = null;
this.geometry = null;
this.render = null;
this.logMessages = false;
this.renderPasses = 1;
this.forceCull = false;
}
/**
* @return the id
*/
public int getId() {
return id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the renderPasses
*/
public int getRenderPasses() {
return renderPasses;
}
/**
* @param renderPasses the renderPasses to set
*/
public void setRenderPasses(int renderPasses) {
this.renderPasses = renderPasses;
}
public boolean hasParent() {
return parent != null;
}
/**
* @return the parent
*/
public GameObject getParent() {
return parent;
}
public void addChild(GameObject child) {
if (child.parent != null) {
parent.removeChild(child);
}
if (!children.contains(child)) {
children.add(child);
child.parent = this;
engine.markChildGameObject(child);
}
}
public void removeChild(GameObject child) {
if (!children.contains(child)) {
children.remove(child);
child.parent = null;
engine.unmarkChildGameObject(child);
}
}
public void registerComponent(Component component) {
if (component.gameObject != null) {
component.gameObject.deregisterComponent(component);
}
if (component instanceof GeometryComponent) {
geometry = (GeometryComponent) component;
if (render == null) {
registerComponent(new RenderComponent());
}
} else if (component instanceof SpatialComponent) {
spatial = (SpatialComponent) component;
}
if (!components.contains(component)) {
components.add(component);
}
component.gameObject = this;
}
public void deregisterComponent(Component component) {
if (component instanceof GeometryComponent) {
geometry = null;
if (render != null) {
deregisterComponent(render);
render = null;
}
} else if (component instanceof SpatialComponent) {
spatial = null;
}
if (!components.contains(component)) {
components.remove(component);
}
component.gameObject = null;
}
public Component getComponent(Class<?> clazz) {
for (int i = 0; i < components.size(); i++) {
Component component = components.get(i);
if (component.getClass().equals(clazz)) {
return component;
}
}
return null;
}
public Component[] getComponents() {
return this.components.toArray(new Component[this.components.size()]);
}
void init() {
if (components == null) {
return;
}
for (int i = 0; i < components.size(); i++) {
components.get(i).init();
}
}
void start() {
if (components == null) {
return;
}
for (int i = 0; i < components.size(); i++) {
components.get(i).start();
}
for (int i = 0; i < children.size(); i++) {
GameObject child = children.get(i);
child.start();
}
}
void update(float delta) {
if (components == null) {
return;
}
for (int i = 0; i < components.size(); i++) {
components.get(i).update(delta);
}
for (int i = 0; i < children.size(); i++) {
GameObject child = children.get(i);
child.update(delta);
}
}
void render(Renderer renderer) {
if (forceCull == true) {
return;
}
if (!renderer.cull(spatial)) {
if (hasContentToRender()) {
renderer.addToRenderQueue(this);
}
for (int i = 0; i < children.size(); i++) {
GameObject child = children.get(i);
child.render(renderer);
}
}
}
List<Component> findIntentTopicRecipients(int topic) {
List<Component> listenerList = new ArrayList<Component>();
for (int i = 0; i < components.size(); i++) {
Component component = components.get(i);
if (component.isListening() && component.listensToTopic(topic)) {
listenerList.add(component);
}
}
for (int i = 0; i < children.size(); i++) {
GameObject child = children.get(i);
List<Component> childListenerList = child.findIntentTopicRecipients(topic);
if (childListenerList != null && !childListenerList.isEmpty()) {
listenerList.addAll(childListenerList);
}
}
return listenerList;
}
/**
* @deprecated
*/
void sendIntent(ComponentIntent intent) {
for (int i = 0; i < components.size(); i++) {
Component component = components.get(i);
if (component.isListening() && component.listensToTopic(intent.getTopic())) {
component.recieveIntent(intent);
intent.addReceiver(component);
}
}
for (int i = 0; i < children.size(); i++) {
GameObject child = children.get(i);
child.sendIntent(intent);
}
if (logMessages && intent.wasReceived()) {
System.out.println("I:" + intent);
}
}
public boolean hasContentToRender() {
if (geometry != null) {
return true;
}
return false;
}
public void dumpComponents() {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < components.size(); i++) {
Component component = components.get(i);
builder.append('[').append(i).append("]\t").append(component.toString()).append(System.lineSeparator());
}
}
public void createGeometry() {
if (geometry == null) {
geometry = new GeometryComponent();
}
}
public void createSpatial() {
if (spatial == null) {
spatial = new SpatialComponent();
}
}
public void setPosition(float x, float y) {
if (spatial != null) {
spatial.setTranslation(x, y);
}
}
public void setPosition(float x, float y, float z) {
if (spatial != null) {
spatial.setTranslation(x, y, z);
}
}
public void setRotation(float r) {
if (spatial != null) {
}
}
public void setRotation(Matrix3f r) {
if (spatial != null) {
spatial.setRotation(r);
}
}
public void setScale(float s) {
if (spatial != null) {
spatial.setScale(s);
}
}
//
// public BoundingVolume getLocalBounds() {
// for(GameObject child : children) {
// BoundingVolume childBounds = child.getLocalBounds();
//
// }
//
// return null;
// }
//
// public BoundingVolume getWorldBounds() {
// return null;
// }
public Transformation getWorld() {
updateWorldTransforms();
return spatial.world;
}
public void updateWorldTransforms() {
if (parent == null) {
updateRootTransform();
// tranform updated
} else {
List<GameObject> updateStack = new ArrayList<GameObject>();
GameObject trace = this;
do {
updateStack.add(trace);
} while ((trace = trace.parent) != null);
int stackSize = updateStack.size();
if (stackSize > 0) {
updateStack.get(stackSize - 1).updateRootTransform();
}
if (stackSize > 1) {
for (int i = updateStack.size() - 2; i >= 0; i--) {
updateStack.get(i).updateChildWorldTransform();
// tranform updated
}
}
}
}
private void updateRootTransform() {
spatial.crossoverLocalToWorld();
}
private void updateChildWorldTransform() {
spatial.crossoverLocalToWorld();
spatial.combineWorldWithParent(parent.spatial);
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "GameObject [id=" + id + ", name=" + name + "]";
}
}