diff --git a/.gitignore b/.gitignore
index ef485f9..465d184 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,8 @@
## Eclipse
#################
+target/
+
*.pydevproject
.project
.metadata
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..03d3dea
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,23 @@
+
+ 4.0.0
+ com.base
+ 3DGameEngine
+ jar
+ 1.0-SNAPSHOT
+ 3DGameEngine
+ http://maven.apache.org
+
+
+
+ org.lwjgl.lwjgl
+ lwjgl
+ 2.9.1
+
+
+ junit
+ junit
+ 3.8.1
+ test
+
+
+
diff --git a/src/main/java/com/base/engine/components/BaseLight.java b/src/main/java/com/base/engine/components/BaseLight.java
new file mode 100644
index 0000000..275c8b4
--- /dev/null
+++ b/src/main/java/com/base/engine/components/BaseLight.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.components;
+
+import com.base.engine.core.CoreEngine;
+import com.base.engine.rendering.RenderingEngine;
+import com.base.engine.core.Vector3f;
+import com.base.engine.rendering.Shader;
+
+public class BaseLight extends GameComponent
+{
+ private Vector3f color;
+ private float intensity;
+ private Shader shader;
+
+ public BaseLight(Vector3f color, float intensity)
+ {
+ this.color = color;
+ this.intensity = intensity;
+ }
+
+ @Override
+ public void addToEngine(CoreEngine engine)
+ {
+ engine.getRenderingEngine().addLight(this);
+ }
+
+ public void setShader(Shader shader)
+ {
+ this.shader = shader;
+ }
+
+ public Shader getShader()
+ {
+ return shader;
+ }
+
+ public Vector3f getColor()
+ {
+ return color;
+ }
+
+ public void setColor(Vector3f color)
+ {
+ this.color = color;
+ }
+
+ public float getIntensity()
+ {
+ return intensity;
+ }
+
+ public void setIntensity(float intensity)
+ {
+ this.intensity = intensity;
+ }
+}
diff --git a/src/main/java/com/base/engine/components/Camera.java b/src/main/java/com/base/engine/components/Camera.java
new file mode 100644
index 0000000..c9a5f8c
--- /dev/null
+++ b/src/main/java/com/base/engine/components/Camera.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.components;
+
+import com.base.engine.core.*;
+import com.base.engine.rendering.RenderingEngine;
+import com.base.engine.rendering.Window;
+
+public class Camera extends GameComponent
+{
+ private Matrix4f projection;
+
+ public Camera(float fov, float aspect, float zNear, float zFar)
+ {
+ this.projection = new Matrix4f().initPerspective(fov, aspect, zNear, zFar);
+ }
+
+ public Matrix4f getViewProjection()
+ {
+ Matrix4f cameraRotation = getTransform().getTransformedRot().conjugate().toRotationMatrix();
+ Vector3f cameraPos = getTransform().getTransformedPos().mul(-1);
+
+ Matrix4f cameraTranslation = new Matrix4f().initTranslation(cameraPos.getX(), cameraPos.getY(), cameraPos.getZ());
+
+ return projection.mul(cameraRotation.mul(cameraTranslation));
+ }
+
+ @Override
+ public void addToEngine(CoreEngine engine)
+ {
+ engine.getRenderingEngine().addCamera(this);
+ }
+}
diff --git a/src/main/java/com/base/engine/components/DirectionalLight.java b/src/main/java/com/base/engine/components/DirectionalLight.java
new file mode 100644
index 0000000..645942f
--- /dev/null
+++ b/src/main/java/com/base/engine/components/DirectionalLight.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.components;
+
+import com.base.engine.core.Vector3f;
+import com.base.engine.rendering.Shader;
+
+public class DirectionalLight extends BaseLight
+{
+ public DirectionalLight(Vector3f color, float intensity)
+ {
+ super(color, intensity);
+
+ setShader(new Shader("forward-directional"));
+ }
+
+ public Vector3f getDirection()
+ {
+ return getTransform().getTransformedRot().getForward();
+ }
+}
diff --git a/src/main/java/com/base/engine/components/FreeLook.java b/src/main/java/com/base/engine/components/FreeLook.java
new file mode 100644
index 0000000..4ec8e8d
--- /dev/null
+++ b/src/main/java/com/base/engine/components/FreeLook.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.components;
+
+import com.base.engine.core.Input;
+import com.base.engine.core.Vector2f;
+import com.base.engine.core.Vector3f;
+import com.base.engine.rendering.Window;
+
+public class FreeLook extends GameComponent
+{
+ private static final Vector3f yAxis = new Vector3f(0,1,0);
+
+ private boolean mouseLocked = false;
+ private float sensitivity;
+ private int unlockMouseKey;
+
+ public FreeLook(float sensitivity)
+ {
+ this(sensitivity, Input.KEY_ESCAPE);
+ }
+
+ public FreeLook(float sensitivity, int unlockMouseKey)
+ {
+ this.sensitivity = sensitivity;
+ this.unlockMouseKey = unlockMouseKey;
+ }
+
+ @Override
+ public void input(float delta)
+ {
+ Vector2f centerPosition = new Vector2f(Window.getWidth()/2, Window.getHeight()/2);
+
+ if(Input.getKey(unlockMouseKey))
+ {
+ Input.setCursor(true);
+ mouseLocked = false;
+ }
+ if(Input.getMouseDown(0))
+ {
+ Input.setMousePosition(centerPosition);
+ Input.setCursor(false);
+ mouseLocked = true;
+ }
+
+ if(mouseLocked)
+ {
+ Vector2f deltaPos = Input.getMousePosition().sub(centerPosition);
+
+ boolean rotY = deltaPos.getX() != 0;
+ boolean rotX = deltaPos.getY() != 0;
+
+ if(rotY)
+ getTransform().rotate(yAxis, (float) Math.toRadians(deltaPos.getX() * sensitivity));
+ if(rotX)
+ getTransform().rotate(getTransform().getRot().getRight(), (float) Math.toRadians(-deltaPos.getY() * sensitivity));
+
+ if(rotY || rotX)
+ Input.setMousePosition(centerPosition);
+ }
+ }
+}
diff --git a/src/main/java/com/base/engine/components/FreeMove.java b/src/main/java/com/base/engine/components/FreeMove.java
new file mode 100644
index 0000000..9f6c2f2
--- /dev/null
+++ b/src/main/java/com/base/engine/components/FreeMove.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.components;
+
+import com.base.engine.core.Input;
+import com.base.engine.core.Vector3f;
+
+public class FreeMove extends GameComponent
+{
+ private float speed;
+ private int forwardKey;
+ private int backKey;
+ private int leftKey;
+ private int rightKey;
+
+ public FreeMove(float speed)
+ {
+ this(speed, Input.KEY_W, Input.KEY_S, Input.KEY_A, Input.KEY_D);
+ }
+
+ public FreeMove(float speed, int forwardKey, int backKey, int leftKey, int rightKey)
+ {
+ this.speed = speed;
+ this.forwardKey = forwardKey;
+ this.backKey = backKey;
+ this.leftKey = leftKey;
+ this.rightKey = rightKey;
+ }
+
+ @Override
+ public void input(float delta)
+ {
+ float movAmt = speed * delta;
+
+ if(Input.getKey(forwardKey))
+ move(getTransform().getRot().getForward(), movAmt);
+ if(Input.getKey(backKey))
+ move(getTransform().getRot().getForward(), -movAmt);
+ if(Input.getKey(leftKey))
+ move(getTransform().getRot().getLeft(), movAmt);
+ if(Input.getKey(rightKey))
+ move(getTransform().getRot().getRight(), movAmt);
+ }
+
+ private void move(Vector3f dir, float amt)
+ {
+ getTransform().setPos(getTransform().getPos().add(dir.mul(amt)));
+ }
+}
diff --git a/src/main/java/com/base/engine/components/GameComponent.java b/src/main/java/com/base/engine/components/GameComponent.java
new file mode 100644
index 0000000..eac0aa2
--- /dev/null
+++ b/src/main/java/com/base/engine/components/GameComponent.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.components;
+
+import com.base.engine.core.CoreEngine;
+import com.base.engine.core.GameObject;
+import com.base.engine.rendering.RenderingEngine;
+import com.base.engine.core.Transform;
+import com.base.engine.rendering.Shader;
+
+public abstract class GameComponent
+{
+ private GameObject parent;
+
+ public void input(float delta) {}
+ public void update(float delta) {}
+ public void render(Shader shader, RenderingEngine renderingEngine) {}
+
+ public void setParent(GameObject parent)
+ {
+ this.parent = parent;
+ }
+
+ public Transform getTransform()
+ {
+ return parent.getTransform();
+ }
+
+ public void addToEngine(CoreEngine engine) {}
+}
+
diff --git a/src/main/java/com/base/engine/components/MeshRenderer.java b/src/main/java/com/base/engine/components/MeshRenderer.java
new file mode 100644
index 0000000..b7ed0de
--- /dev/null
+++ b/src/main/java/com/base/engine/components/MeshRenderer.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.components;
+
+import com.base.engine.core.Transform;
+import com.base.engine.rendering.Material;
+import com.base.engine.rendering.Mesh;
+import com.base.engine.rendering.RenderingEngine;
+import com.base.engine.rendering.Shader;
+
+public class MeshRenderer extends GameComponent
+{
+ private Mesh mesh;
+ private Material material;
+
+ public MeshRenderer(Mesh mesh, Material material)
+ {
+ this.mesh = mesh;
+ this.material = material;
+ }
+
+ @Override
+ public void render(Shader shader, RenderingEngine renderingEngine)
+ {
+ shader.bind();
+ shader.updateUniforms(getTransform(), material, renderingEngine);
+ mesh.draw();
+ }
+}
diff --git a/src/main/java/com/base/engine/components/PointLight.java b/src/main/java/com/base/engine/components/PointLight.java
new file mode 100644
index 0000000..5a58b29
--- /dev/null
+++ b/src/main/java/com/base/engine/components/PointLight.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.components;
+
+import com.base.engine.core.Vector3f;
+import com.base.engine.rendering.Attenuation;
+import com.base.engine.rendering.Shader;
+
+public class PointLight extends BaseLight
+{
+ private static final int COLOR_DEPTH = 256;
+
+ private Attenuation attenuation;
+ private float range;
+
+ public PointLight(Vector3f color, float intensity, Attenuation attenuation)
+ {
+ super(color, intensity);
+ this.attenuation = attenuation;
+
+ float a = attenuation.getExponent();
+ float b = attenuation.getLinear();
+ float c = attenuation.getConstant() - COLOR_DEPTH * getIntensity() * getColor().max();
+
+ this.range = (float)((-b + Math.sqrt(b * b - 4 * a * c))/(2 * a));
+
+ setShader(new Shader("forward-point"));
+ }
+
+ public float getRange()
+ {
+ return range;
+ }
+
+ public void setRange(float range)
+ {
+ this.range = range;
+ }
+
+ public Attenuation getAttenuation()
+ {
+ return attenuation;
+ }
+}
diff --git a/src/main/java/com/base/engine/components/SpotLight.java b/src/main/java/com/base/engine/components/SpotLight.java
new file mode 100644
index 0000000..d5f5276
--- /dev/null
+++ b/src/main/java/com/base/engine/components/SpotLight.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.components;
+
+import com.base.engine.core.Vector3f;
+import com.base.engine.rendering.Attenuation;
+import com.base.engine.rendering.Shader;
+
+public class SpotLight extends PointLight
+{
+ private float cutoff;
+
+ public SpotLight(Vector3f color, float intensity, Attenuation attenuation, float cutoff)
+ {
+ super(color, intensity, attenuation);
+ this.cutoff = cutoff;
+
+ setShader(new Shader("forward-spot"));
+ }
+
+ public Vector3f getDirection()
+ {
+ return getTransform().getTransformedRot().getForward();
+ }
+
+ public float getCutoff()
+ {
+ return cutoff;
+ }
+ public void setCutoff(float cutoff)
+ {
+ this.cutoff = cutoff;
+ }
+}
diff --git a/src/main/java/com/base/engine/core/CoreEngine.java b/src/main/java/com/base/engine/core/CoreEngine.java
new file mode 100644
index 0000000..b26e817
--- /dev/null
+++ b/src/main/java/com/base/engine/core/CoreEngine.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.core;
+
+import com.base.engine.components.GameComponent;
+import com.base.engine.rendering.RenderingEngine;
+import com.base.engine.rendering.Window;
+
+public class CoreEngine
+{
+ private boolean isRunning;
+ private Game game;
+ private RenderingEngine renderingEngine;
+ private int width;
+ private int height;
+ private double frameTime;
+
+ public CoreEngine(int width, int height, double framerate, Game game)
+ {
+ this.isRunning = false;
+ this.game = game;
+ this.width = width;
+ this.height = height;
+ this.frameTime = 1.0/framerate;
+ game.setEngine(this);
+ }
+
+ public void createWindow(String title)
+ {
+ Window.createWindow(width, height, title);
+ this.renderingEngine = new RenderingEngine();
+ }
+
+ public void start()
+ {
+ if(isRunning)
+ return;
+
+ run();
+ }
+
+ public void stop()
+ {
+ if(!isRunning)
+ return;
+
+ isRunning = false;
+ }
+
+ private void run()
+ {
+ isRunning = true;
+
+ int frames = 0;
+ long frameCounter = 0;
+
+ game.init();
+
+ double lastTime = Time.getTime();
+ double unprocessedTime = 0;
+
+ while(isRunning)
+ {
+ boolean render = false;
+
+ double startTime = Time.getTime();
+ double passedTime = startTime - lastTime;
+ lastTime = startTime;
+
+ unprocessedTime += passedTime;
+ frameCounter += passedTime;
+
+ while(unprocessedTime > frameTime)
+ {
+ render = true;
+
+ unprocessedTime -= frameTime;
+
+ if(Window.isCloseRequested())
+ stop();
+
+ game.input((float)frameTime);
+ Input.update();
+
+ game.update((float)frameTime);
+
+ if(frameCounter >= 1.0)
+ {
+ System.out.println(frames);
+ frames = 0;
+ frameCounter = 0;
+ }
+ }
+ if(render)
+ {
+ game.render(renderingEngine);
+ Window.render();
+ frames++;
+ }
+ else
+ {
+ try
+ {
+ Thread.sleep(1);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ cleanUp();
+ }
+
+ private void cleanUp()
+ {
+ Window.dispose();
+ }
+
+ public RenderingEngine getRenderingEngine() {
+ return renderingEngine;
+ }
+}
diff --git a/src/main/java/com/base/engine/core/Game.java b/src/main/java/com/base/engine/core/Game.java
new file mode 100644
index 0000000..49ec4b7
--- /dev/null
+++ b/src/main/java/com/base/engine/core/Game.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.core;
+
+import com.base.engine.rendering.RenderingEngine;
+
+public abstract class Game
+{
+ private GameObject root;
+
+ public void init() {}
+
+ public void input(float delta)
+ {
+ getRootObject().inputAll(delta);
+ }
+
+ public void update(float delta)
+ {
+ getRootObject().updateAll(delta);
+ }
+
+ public void render(RenderingEngine renderingEngine)
+ {
+ renderingEngine.render(getRootObject());
+ }
+
+ public void addObject(GameObject object)
+ {
+ getRootObject().addChild(object);
+ }
+
+ private GameObject getRootObject()
+ {
+ if(root == null)
+ root = new GameObject();
+
+ return root;
+ }
+
+ public void setEngine(CoreEngine engine) { getRootObject().setEngine(engine); }
+}
diff --git a/src/main/java/com/base/engine/core/GameObject.java b/src/main/java/com/base/engine/core/GameObject.java
new file mode 100644
index 0000000..3bd5ac5
--- /dev/null
+++ b/src/main/java/com/base/engine/core/GameObject.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.core;
+
+import com.base.engine.components.GameComponent;
+import com.base.engine.rendering.RenderingEngine;
+import com.base.engine.rendering.Shader;
+
+import java.util.ArrayList;
+
+public class GameObject
+{
+ private ArrayList children;
+ private ArrayList components;
+ private Transform transform;
+ private CoreEngine engine;
+
+ public GameObject()
+ {
+ children = new ArrayList();
+ components = new ArrayList();
+ transform = new Transform();
+ engine = null;
+ }
+
+ public void addChild(GameObject child)
+ {
+ children.add(child);
+ child.setEngine(engine);
+ child.getTransform().setParent(transform);
+ }
+
+ public GameObject addComponent(GameComponent component)
+ {
+ components.add(component);
+ component.setParent(this);
+
+ return this;
+ }
+
+ public void inputAll(float delta)
+ {
+ input(delta);
+
+ for(GameObject child : children)
+ child.inputAll(delta);
+ }
+
+ public void updateAll(float delta)
+ {
+ update(delta);
+
+ for(GameObject child : children)
+ child.updateAll(delta);
+ }
+
+ public void renderAll(Shader shader, RenderingEngine renderingEngine)
+ {
+ render(shader, renderingEngine);
+
+ for(GameObject child : children)
+ child.renderAll(shader, renderingEngine);
+ }
+
+ public void input(float delta)
+ {
+ transform.update();
+
+ for(GameComponent component : components)
+ component.input(delta);
+ }
+
+ public void update(float delta)
+ {
+ for(GameComponent component : components)
+ component.update(delta);
+ }
+
+ public void render(Shader shader, RenderingEngine renderingEngine)
+ {
+ for(GameComponent component : components)
+ component.render(shader, renderingEngine);
+ }
+
+ public ArrayList getAllAttached()
+ {
+ ArrayList result = new ArrayList();
+
+ for(GameObject child : children)
+ result.addAll(child.getAllAttached());
+
+ result.add(this);
+ return result;
+ }
+
+ public Transform getTransform()
+ {
+ return transform;
+ }
+
+ public void setEngine(CoreEngine engine)
+ {
+ if(this.engine != engine)
+ {
+ this.engine = engine;
+
+ for(GameComponent component : components)
+ component.addToEngine(engine);
+
+ for(GameObject child : children)
+ child.setEngine(engine);
+ }
+ }
+}
diff --git a/src/main/java/com/base/engine/core/Input.java b/src/main/java/com/base/engine/core/Input.java
new file mode 100644
index 0000000..0545527
--- /dev/null
+++ b/src/main/java/com/base/engine/core/Input.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.core;
+
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+
+public class Input
+{
+ public static final int NUM_KEYCODES = 256;
+ public static final int NUM_MOUSEBUTTONS = 5;
+
+ //All these constants come from LWJGL's Keyboard class
+ public static final int KEY_NONE = 0x00;
+ public static final int KEY_ESCAPE = 0x01;
+ public static final int KEY_1 = 0x02;
+ public static final int KEY_2 = 0x03;
+ public static final int KEY_3 = 0x04;
+ public static final int KEY_4 = 0x05;
+ public static final int KEY_5 = 0x06;
+ public static final int KEY_6 = 0x07;
+ public static final int KEY_7 = 0x08;
+ public static final int KEY_8 = 0x09;
+ public static final int KEY_9 = 0x0A;
+ public static final int KEY_0 = 0x0B;
+ public static final int KEY_MINUS = 0x0C; /* - on main keyboard */
+ public static final int KEY_EQUALS = 0x0D;
+ public static final int KEY_BACK = 0x0E; /* backspace */
+ public static final int KEY_TAB = 0x0F;
+ public static final int KEY_Q = 0x10;
+ public static final int KEY_W = 0x11;
+ public static final int KEY_E = 0x12;
+ public static final int KEY_R = 0x13;
+ public static final int KEY_T = 0x14;
+ public static final int KEY_Y = 0x15;
+ public static final int KEY_U = 0x16;
+ public static final int KEY_I = 0x17;
+ public static final int KEY_O = 0x18;
+ public static final int KEY_P = 0x19;
+ public static final int KEY_LBRACKET = 0x1A;
+ public static final int KEY_RBRACKET = 0x1B;
+ public static final int KEY_RETURN = 0x1C; /* Enter on main keyboard */
+ public static final int KEY_LCONTROL = 0x1D;
+ public static final int KEY_A = 0x1E;
+ public static final int KEY_S = 0x1F;
+ public static final int KEY_D = 0x20;
+ public static final int KEY_F = 0x21;
+ public static final int KEY_G = 0x22;
+ public static final int KEY_H = 0x23;
+ public static final int KEY_J = 0x24;
+ public static final int KEY_K = 0x25;
+ public static final int KEY_L = 0x26;
+ public static final int KEY_SEMICOLON = 0x27;
+ public static final int KEY_APOSTROPHE = 0x28;
+ public static final int KEY_GRAVE = 0x29; /* accent grave */
+ public static final int KEY_LSHIFT = 0x2A;
+ public static final int KEY_BACKSLASH = 0x2B;
+ public static final int KEY_Z = 0x2C;
+ public static final int KEY_X = 0x2D;
+ public static final int KEY_C = 0x2E;
+ public static final int KEY_V = 0x2F;
+ public static final int KEY_B = 0x30;
+ public static final int KEY_N = 0x31;
+ public static final int KEY_M = 0x32;
+ public static final int KEY_COMMA = 0x33;
+ public static final int KEY_PERIOD = 0x34; /* . on main keyboard */
+ public static final int KEY_SLASH = 0x35; /* / on main keyboard */
+ public static final int KEY_RSHIFT = 0x36;
+ public static final int KEY_MULTIPLY = 0x37; /* * on numeric keypad */
+ public static final int KEY_LMENU = 0x38; /* left Alt */
+ public static final int KEY_LALT = KEY_LMENU; /* left Alt */
+ public static final int KEY_SPACE = 0x39;
+ public static final int KEY_CAPITAL = 0x3A;
+ public static final int KEY_F1 = 0x3B;
+ public static final int KEY_F2 = 0x3C;
+ public static final int KEY_F3 = 0x3D;
+ public static final int KEY_F4 = 0x3E;
+ public static final int KEY_F5 = 0x3F;
+ public static final int KEY_F6 = 0x40;
+ public static final int KEY_F7 = 0x41;
+ public static final int KEY_F8 = 0x42;
+ public static final int KEY_F9 = 0x43;
+ public static final int KEY_F10 = 0x44;
+ public static final int KEY_NUMLOCK = 0x45;
+ public static final int KEY_SCROLL = 0x46; /* Scroll Lock */
+ public static final int KEY_NUMPAD7 = 0x47;
+ public static final int KEY_NUMPAD8 = 0x48;
+ public static final int KEY_NUMPAD9 = 0x49;
+ public static final int KEY_SUBTRACT = 0x4A; /* - on numeric keypad */
+ public static final int KEY_NUMPAD4 = 0x4B;
+ public static final int KEY_NUMPAD5 = 0x4C;
+ public static final int KEY_NUMPAD6 = 0x4D;
+ public static final int KEY_ADD = 0x4E; /* + on numeric keypad */
+ public static final int KEY_NUMPAD1 = 0x4F;
+ public static final int KEY_NUMPAD2 = 0x50;
+ public static final int KEY_NUMPAD3 = 0x51;
+ public static final int KEY_NUMPAD0 = 0x52;
+ public static final int KEY_DECIMAL = 0x53; /* . on numeric keypad */
+ public static final int KEY_F11 = 0x57;
+ public static final int KEY_F12 = 0x58;
+ public static final int KEY_F13 = 0x64; /* (NEC PC98) */
+ public static final int KEY_F14 = 0x65; /* (NEC PC98) */
+ public static final int KEY_F15 = 0x66; /* (NEC PC98) */
+ public static final int KEY_KANA = 0x70; /* (Japanese keyboard) */
+ public static final int KEY_CONVERT = 0x79; /* (Japanese keyboard) */
+ public static final int KEY_NOCONVERT = 0x7B; /* (Japanese keyboard) */
+ public static final int KEY_YEN = 0x7D; /* (Japanese keyboard) */
+ public static final int KEY_NUMPADEQUALS = 0x8D; /* = on numeric keypad (NEC PC98) */
+ public static final int KEY_CIRCUMFLEX = 0x90; /* (Japanese keyboard) */
+ public static final int KEY_AT = 0x91; /* (NEC PC98) */
+ public static final int KEY_COLON = 0x92; /* (NEC PC98) */
+ public static final int KEY_UNDERLINE = 0x93; /* (NEC PC98) */
+ public static final int KEY_KANJI = 0x94; /* (Japanese keyboard) */
+ public static final int KEY_STOP = 0x95; /* (NEC PC98) */
+ public static final int KEY_AX = 0x96; /* (Japan AX) */
+ public static final int KEY_UNLABELED = 0x97; /* (J3100) */
+ public static final int KEY_NUMPADENTER = 0x9C; /* Enter on numeric keypad */
+ public static final int KEY_RCONTROL = 0x9D;
+ public static final int KEY_NUMPADCOMMA = 0xB3; /* , on numeric keypad (NEC PC98) */
+ public static final int KEY_DIVIDE = 0xB5; /* / on numeric keypad */
+ public static final int KEY_SYSRQ = 0xB7;
+ public static final int KEY_RMENU = 0xB8; /* right Alt */
+ public static final int KEY_RALT = KEY_RMENU; /* right Alt */
+ public static final int KEY_PAUSE = 0xC5; /* Pause */
+ public static final int KEY_HOME = 0xC7; /* Home on arrow keypad */
+ public static final int KEY_UP = 0xC8; /* UpArrow on arrow keypad */
+ public static final int KEY_PRIOR = 0xC9; /* PgUp on arrow keypad */
+ public static final int KEY_LEFT = 0xCB; /* LeftArrow on arrow keypad */
+ public static final int KEY_RIGHT = 0xCD; /* RightArrow on arrow keypad */
+ public static final int KEY_END = 0xCF; /* End on arrow keypad */
+ public static final int KEY_DOWN = 0xD0; /* DownArrow on arrow keypad */
+ public static final int KEY_NEXT = 0xD1; /* PgDn on arrow keypad */
+ public static final int KEY_INSERT = 0xD2; /* Insert on arrow keypad */
+ public static final int KEY_DELETE = 0xD3; /* Delete on arrow keypad */
+ public static final int KEY_LMETA = 0xDB; /* Left Windows/Option key */
+ public static final int KEY_LWIN = KEY_LMETA; /* Left Windows key */
+ public static final int KEY_RMETA = 0xDC; /* Right Windows/Option key */
+ public static final int KEY_RWIN = KEY_RMETA; /* Right Windows key */
+ public static final int KEY_APPS = 0xDD; /* AppMenu key */
+ public static final int KEY_POWER = 0xDE;
+ public static final int KEY_SLEEP = 0xDF;
+
+ private static boolean[] lastKeys = new boolean[NUM_KEYCODES];
+ private static boolean[] lastMouse = new boolean[NUM_MOUSEBUTTONS];
+
+ public static void update()
+ {
+ for(int i = 0; i < NUM_KEYCODES; i++)
+ lastKeys[i] = getKey(i);
+
+ for(int i = 0; i < NUM_MOUSEBUTTONS; i++)
+ lastMouse[i] = getMouse(i);
+ }
+
+ public static boolean getKey(int keyCode)
+ {
+ return Keyboard.isKeyDown(keyCode);
+ }
+
+ public static boolean getKeyDown(int keyCode)
+ {
+ return getKey(keyCode) && !lastKeys[keyCode];
+ }
+
+ public static boolean getKeyUp(int keyCode)
+ {
+ return !getKey(keyCode) && lastKeys[keyCode];
+ }
+
+ public static boolean getMouse(int mouseButton)
+ {
+ return Mouse.isButtonDown(mouseButton);
+ }
+
+ public static boolean getMouseDown(int mouseButton)
+ {
+ return getMouse(mouseButton) && !lastMouse[mouseButton];
+ }
+
+ public static boolean getMouseUp(int mouseButton)
+ {
+ return !getMouse(mouseButton) && lastMouse[mouseButton];
+ }
+
+ public static Vector2f getMousePosition()
+ {
+ return new Vector2f(Mouse.getX(), Mouse.getY());
+ }
+
+ public static void setMousePosition(Vector2f pos)
+ {
+ Mouse.setCursorPosition((int)pos.getX(), (int)pos.getY());
+ }
+
+ public static void setCursor(boolean enabled)
+ {
+ Mouse.setGrabbed(!enabled);
+ }
+}
diff --git a/src/main/java/com/base/engine/core/Matrix4f.java b/src/main/java/com/base/engine/core/Matrix4f.java
new file mode 100644
index 0000000..035adb4
--- /dev/null
+++ b/src/main/java/com/base/engine/core/Matrix4f.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.core;
+
+public class Matrix4f
+{
+ private float[][] m;
+
+ public Matrix4f()
+ {
+ m = new float[4][4];
+ }
+
+ public Matrix4f initIdentity()
+ {
+ m[0][0] = 1; m[0][1] = 0; m[0][2] = 0; m[0][3] = 0;
+ m[1][0] = 0; m[1][1] = 1; m[1][2] = 0; m[1][3] = 0;
+ m[2][0] = 0; m[2][1] = 0; m[2][2] = 1; m[2][3] = 0;
+ m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1;
+
+ return this;
+ }
+
+ public Matrix4f initTranslation(float x, float y, float z)
+ {
+ m[0][0] = 1; m[0][1] = 0; m[0][2] = 0; m[0][3] = x;
+ m[1][0] = 0; m[1][1] = 1; m[1][2] = 0; m[1][3] = y;
+ m[2][0] = 0; m[2][1] = 0; m[2][2] = 1; m[2][3] = z;
+ m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1;
+
+ return this;
+ }
+
+ public Matrix4f initRotation(float x, float y, float z)
+ {
+ Matrix4f rx = new Matrix4f();
+ Matrix4f ry = new Matrix4f();
+ Matrix4f rz = new Matrix4f();
+
+ x = (float)Math.toRadians(x);
+ y = (float)Math.toRadians(y);
+ z = (float)Math.toRadians(z);
+
+ rz.m[0][0] = (float)Math.cos(z);rz.m[0][1] = -(float)Math.sin(z);rz.m[0][2] = 0; rz.m[0][3] = 0;
+ rz.m[1][0] = (float)Math.sin(z);rz.m[1][1] = (float)Math.cos(z);rz.m[1][2] = 0; rz.m[1][3] = 0;
+ rz.m[2][0] = 0; rz.m[2][1] = 0; rz.m[2][2] = 1; rz.m[2][3] = 0;
+ rz.m[3][0] = 0; rz.m[3][1] = 0; rz.m[3][2] = 0; rz.m[3][3] = 1;
+
+ rx.m[0][0] = 1; rx.m[0][1] = 0; rx.m[0][2] = 0; rx.m[0][3] = 0;
+ rx.m[1][0] = 0; rx.m[1][1] = (float)Math.cos(x);rx.m[1][2] = -(float)Math.sin(x);rx.m[1][3] = 0;
+ rx.m[2][0] = 0; rx.m[2][1] = (float)Math.sin(x);rx.m[2][2] = (float)Math.cos(x);rx.m[2][3] = 0;
+ rx.m[3][0] = 0; rx.m[3][1] = 0; rx.m[3][2] = 0; rx.m[3][3] = 1;
+
+ ry.m[0][0] = (float)Math.cos(y);ry.m[0][1] = 0; ry.m[0][2] = -(float)Math.sin(y);ry.m[0][3] = 0;
+ ry.m[1][0] = 0; ry.m[1][1] = 1; ry.m[1][2] = 0; ry.m[1][3] = 0;
+ ry.m[2][0] = (float)Math.sin(y);ry.m[2][1] = 0; ry.m[2][2] = (float)Math.cos(y);ry.m[2][3] = 0;
+ ry.m[3][0] = 0; ry.m[3][1] = 0; ry.m[3][2] = 0; ry.m[3][3] = 1;
+
+ m = rz.mul(ry.mul(rx)).getM();
+
+ return this;
+ }
+
+ public Matrix4f initScale(float x, float y, float z)
+ {
+ m[0][0] = x; m[0][1] = 0; m[0][2] = 0; m[0][3] = 0;
+ m[1][0] = 0; m[1][1] = y; m[1][2] = 0; m[1][3] = 0;
+ m[2][0] = 0; m[2][1] = 0; m[2][2] = z; m[2][3] = 0;
+ m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1;
+
+ return this;
+ }
+
+ public Matrix4f initPerspective(float fov, float aspectRatio, float zNear, float zFar)
+ {
+ float tanHalfFOV = (float)Math.tan(fov / 2);
+ float zRange = zNear - zFar;
+
+ m[0][0] = 1.0f / (tanHalfFOV * aspectRatio); m[0][1] = 0; m[0][2] = 0; m[0][3] = 0;
+ m[1][0] = 0; m[1][1] = 1.0f / tanHalfFOV; m[1][2] = 0; m[1][3] = 0;
+ m[2][0] = 0; m[2][1] = 0; m[2][2] = (-zNear -zFar)/zRange; m[2][3] = 2 * zFar * zNear / zRange;
+ m[3][0] = 0; m[3][1] = 0; m[3][2] = 1; m[3][3] = 0;
+
+
+ return this;
+ }
+
+ public Matrix4f initOrthographic(float left, float right, float bottom, float top, float near, float far)
+ {
+ float width = right - left;
+ float height = top - bottom;
+ float depth = far - near;
+
+ m[0][0] = 2/width;m[0][1] = 0; m[0][2] = 0; m[0][3] = -(right + left)/width;
+ m[1][0] = 0; m[1][1] = 2/height;m[1][2] = 0; m[1][3] = -(top + bottom)/height;
+ m[2][0] = 0; m[2][1] = 0; m[2][2] = -2/depth;m[2][3] = -(far + near)/depth;
+ m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1;
+
+ return this;
+ }
+
+ public Matrix4f initRotation(Vector3f forward, Vector3f up)
+ {
+ Vector3f f = forward.normalized();
+
+ Vector3f r = up.normalized();
+ r = r.cross(f);
+
+ Vector3f u = f.cross(r);
+
+ return initRotation(f, u, r);
+ }
+
+ public Matrix4f initRotation(Vector3f forward, Vector3f up, Vector3f right)
+ {
+ Vector3f f = forward;
+ Vector3f r = right;
+ Vector3f u = up;
+
+ m[0][0] = r.getX(); m[0][1] = r.getY(); m[0][2] = r.getZ(); m[0][3] = 0;
+ m[1][0] = u.getX(); m[1][1] = u.getY(); m[1][2] = u.getZ(); m[1][3] = 0;
+ m[2][0] = f.getX(); m[2][1] = f.getY(); m[2][2] = f.getZ(); m[2][3] = 0;
+ m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1;
+
+ return this;
+ }
+
+ public Vector3f transform(Vector3f r)
+ {
+ return new Vector3f(m[0][0] * r.getX() + m[0][1] * r.getY() + m[0][2] * r.getZ() + m[0][3],
+ m[1][0] * r.getX() + m[1][1] * r.getY() + m[1][2] * r.getZ() + m[1][3],
+ m[2][0] * r.getX() + m[2][1] * r.getY() + m[2][2] * r.getZ() + m[2][3]);
+ }
+
+ public Matrix4f mul(Matrix4f r)
+ {
+ Matrix4f res = new Matrix4f();
+
+ for(int i = 0; i < 4; i++)
+ {
+ for(int j = 0; j < 4; j++)
+ {
+ res.set(i, j, m[i][0] * r.get(0, j) +
+ m[i][1] * r.get(1, j) +
+ m[i][2] * r.get(2, j) +
+ m[i][3] * r.get(3, j));
+ }
+ }
+
+ return res;
+ }
+
+ public float[][] getM()
+ {
+ float[][] res = new float[4][4];
+
+ for(int i = 0; i < 4; i++)
+ for(int j = 0; j < 4; j++)
+ res[i][j] = m[i][j];
+
+ return res;
+ }
+
+ public float get(int x, int y)
+ {
+ return m[x][y];
+ }
+
+ public void setM(float[][] m)
+ {
+ this.m = m;
+ }
+
+ public void set(int x, int y, float value)
+ {
+ m[x][y] = value;
+ }
+}
diff --git a/src/main/java/com/base/engine/core/Quaternion.java b/src/main/java/com/base/engine/core/Quaternion.java
new file mode 100644
index 0000000..dd10f4a
--- /dev/null
+++ b/src/main/java/com/base/engine/core/Quaternion.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.core;
+
+public class Quaternion
+{
+ private float x;
+ private float y;
+ private float z;
+ private float w;
+
+ public Quaternion(float x, float y, float z, float w)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ public Quaternion(Vector3f axis, float angle)
+ {
+ float sinHalfAngle = (float)Math.sin(angle / 2);
+ float cosHalfAngle = (float)Math.cos(angle / 2);
+
+ this.x = axis.getX() * sinHalfAngle;
+ this.y = axis.getY() * sinHalfAngle;
+ this.z = axis.getZ() * sinHalfAngle;
+ this.w = cosHalfAngle;
+ }
+
+ public float length()
+ {
+ return (float)Math.sqrt(x * x + y * y + z * z + w * w);
+ }
+
+ public Quaternion normalized()
+ {
+ float length = length();
+
+ return new Quaternion(x / length, y / length, z / length, w / length);
+ }
+
+ public Quaternion conjugate()
+ {
+ return new Quaternion(-x, -y, -z, w);
+ }
+
+ public Quaternion mul(float r)
+ {
+ return new Quaternion(x * r, y * r, z * r, w * r);
+ }
+
+ public Quaternion mul(Quaternion r)
+ {
+ float w_ = w * r.getW() - x * r.getX() - y * r.getY() - z * r.getZ();
+ float x_ = x * r.getW() + w * r.getX() + y * r.getZ() - z * r.getY();
+ float y_ = y * r.getW() + w * r.getY() + z * r.getX() - x * r.getZ();
+ float z_ = z * r.getW() + w * r.getZ() + x * r.getY() - y * r.getX();
+
+ return new Quaternion(x_, y_, z_, w_);
+ }
+
+ public Quaternion mul(Vector3f r)
+ {
+ float w_ = -x * r.getX() - y * r.getY() - z * r.getZ();
+ float x_ = w * r.getX() + y * r.getZ() - z * r.getY();
+ float y_ = w * r.getY() + z * r.getX() - x * r.getZ();
+ float z_ = w * r.getZ() + x * r.getY() - y * r.getX();
+
+ return new Quaternion(x_, y_, z_, w_);
+ }
+
+ public Quaternion sub(Quaternion r)
+ {
+ return new Quaternion(x - r.getX(), y - r.getY(), z - r.getZ(), w - r.getW());
+ }
+
+ public Quaternion add(Quaternion r)
+ {
+ return new Quaternion(x + r.getX(), y + r.getY(), z + r.getZ(), w + r.getW());
+ }
+
+ public Matrix4f toRotationMatrix()
+ {
+ Vector3f forward = new Vector3f(2.0f * (x*z - w*y), 2.0f * (y*z + w*x), 1.0f - 2.0f * (x*x + y*y));
+ Vector3f up = new Vector3f(2.0f * (x*y + w*z), 1.0f - 2.0f * (x*x + z*z), 2.0f * (y*z - w*x));
+ Vector3f right = new Vector3f(1.0f - 2.0f * (y*y + z*z), 2.0f * (x*y - w*z), 2.0f * (x*z + w*y));
+
+ return new Matrix4f().initRotation(forward, up, right);
+ }
+
+ public float dot(Quaternion r)
+ {
+ return x * r.getX() + y * r.getY() + z * r.getZ() + w * r.getW();
+ }
+
+ public Quaternion nlerp(Quaternion dest, float lerpFactor, boolean shortest)
+ {
+ Quaternion correctedDest = dest;
+
+ if(shortest && this.dot(dest) < 0)
+ correctedDest = new Quaternion(-dest.getX(), -dest.getY(), -dest.getZ(), -dest.getW());
+
+ return correctedDest.sub(this).mul(lerpFactor).add(this).normalized();
+ }
+
+ public Quaternion slerp(Quaternion dest, float lerpFactor, boolean shortest)
+ {
+ final float EPSILON = 1e3f;
+
+ float cos = this.dot(dest);
+ Quaternion correctedDest = dest;
+
+ if(shortest && cos < 0)
+ {
+ cos = -cos;
+ correctedDest = new Quaternion(-dest.getX(), -dest.getY(), -dest.getZ(), -dest.getW());
+ }
+
+ if(Math.abs(cos) >= 1 - EPSILON)
+ return nlerp(correctedDest, lerpFactor, false);
+
+ float sin = (float)Math.sqrt(1.0f - cos * cos);
+ float angle = (float)Math.atan2(sin, cos);
+ float invSin = 1.0f/sin;
+
+ float srcFactor = (float)Math.sin((1.0f - lerpFactor) * angle) * invSin;
+ float destFactor = (float)Math.sin((lerpFactor) * angle) * invSin;
+
+ return this.mul(srcFactor).add(correctedDest.mul(destFactor));
+ }
+
+ //From Ken Shoemake's "Quaternion Calculus and Fast Animation" article
+ public Quaternion(Matrix4f rot)
+ {
+ float trace = rot.get(0, 0) + rot.get(1, 1) + rot.get(2, 2);
+
+ if(trace > 0)
+ {
+ float s = 0.5f / (float)Math.sqrt(trace+ 1.0f);
+ w = 0.25f / s;
+ x = (rot.get(1, 2) - rot.get(2, 1)) * s;
+ y = (rot.get(2, 0) - rot.get(0, 2)) * s;
+ z = (rot.get(0, 1) - rot.get(1, 0)) * s;
+ }
+ else
+ {
+ if(rot.get(0, 0) > rot.get(1, 1) && rot.get(0, 0) > rot.get(2, 2))
+ {
+ float s = 2.0f * (float)Math.sqrt(1.0f + rot.get(0, 0) - rot.get(1, 1) - rot.get(2, 2));
+ w = (rot.get(1, 2) - rot.get(2, 1)) / s;
+ x = 0.25f * s;
+ y = (rot.get(1, 0) + rot.get(0, 1)) / s;
+ z = (rot.get(2, 0) + rot.get(0, 2)) / s;
+ }
+ else if(rot.get(1, 1) > rot.get(2, 2))
+ {
+ float s = 2.0f * (float)Math.sqrt(1.0f + rot.get(1, 1) - rot.get(0, 0) - rot.get(2, 2));
+ w = (rot.get(2, 0) - rot.get(0, 2)) / s;
+ x = (rot.get(1, 0) + rot.get(0, 1)) / s;
+ y = 0.25f * s;
+ z = (rot.get(2, 1) + rot.get(1, 2)) / s;
+ }
+ else
+ {
+ float s = 2.0f * (float)Math.sqrt(1.0f + rot.get(2, 2) - rot.get(0, 0) - rot.get(1, 1));
+ w = (rot.get(0, 1) - rot.get(1, 0) ) / s;
+ x = (rot.get(2, 0) + rot.get(0, 2) ) / s;
+ y = (rot.get(1, 2) + rot.get(2, 1) ) / s;
+ z = 0.25f * s;
+ }
+ }
+
+ float length = (float)Math.sqrt(x*x + y*y + z*z +w*w);
+ x /= length;
+ y /= length;
+ z /= length;
+ w /= length;
+ }
+
+ public Vector3f getForward()
+ {
+ return new Vector3f(0,0,1).rotate(this);
+ }
+
+ public Vector3f getBack()
+ {
+ return new Vector3f(0,0,-1).rotate(this);
+ }
+
+ public Vector3f getUp()
+ {
+ return new Vector3f(0,1,0).rotate(this);
+ }
+
+ public Vector3f getDown()
+ {
+ return new Vector3f(0,-1,0).rotate(this);
+ }
+
+ public Vector3f getRight()
+ {
+ return new Vector3f(1,0,0).rotate(this);
+ }
+
+ public Vector3f getLeft()
+ {
+ return new Vector3f(-1,0,0).rotate(this);
+ }
+
+ public Quaternion set(float x, float y, float z, float w) { this.x = x; this.y = y; this.z = z; this.w = w; return this; }
+ public Quaternion set(Quaternion r) { set(r.getX(), r.getY(), r.getZ(), r.getW()); return this; }
+
+ public float getX()
+ {
+ return x;
+ }
+
+ public void setX(float x)
+ {
+ this.x = x;
+ }
+
+ public float getY()
+ {
+ return y;
+ }
+
+ public void setY(float y)
+ {
+ this.y = y;
+ }
+
+ public float getZ()
+ {
+ return z;
+ }
+
+ public void setZ(float z)
+ {
+ this.z = z;
+ }
+
+ public float getW()
+ {
+ return w;
+ }
+
+ public void setW(float w)
+ {
+ this.w = w;
+ }
+
+ public boolean equals(Quaternion r)
+ {
+ return x == r.getX() && y == r.getY() && z == r.getZ() && w == r.getW();
+ }
+}
diff --git a/src/main/java/com/base/engine/core/Time.java b/src/main/java/com/base/engine/core/Time.java
new file mode 100644
index 0000000..c2cdd41
--- /dev/null
+++ b/src/main/java/com/base/engine/core/Time.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.core;
+
+public class Time
+{
+ private static final long SECOND = 1000000000L;
+
+ public static double getTime()
+ {
+ return (double)System.nanoTime()/(double)SECOND;
+ }
+}
diff --git a/src/main/java/com/base/engine/core/Transform.java b/src/main/java/com/base/engine/core/Transform.java
new file mode 100644
index 0000000..3f8e427
--- /dev/null
+++ b/src/main/java/com/base/engine/core/Transform.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.core;
+
+public class Transform
+{
+ private Transform parent;
+ private Matrix4f parentMatrix;
+
+ private Vector3f pos;
+ private Quaternion rot;
+ private Vector3f scale;
+
+ private Vector3f oldPos;
+ private Quaternion oldRot;
+ private Vector3f oldScale;
+
+ public Transform()
+ {
+ pos = new Vector3f(0,0,0);
+ rot = new Quaternion(0,0,0,1);
+ scale = new Vector3f(1,1,1);
+
+ parentMatrix = new Matrix4f().initIdentity();
+ }
+
+ public void update()
+ {
+ if(oldPos != null)
+ {
+ oldPos.set(pos);
+ oldRot.set(rot);
+ oldScale.set(scale);
+ }
+ else
+ {
+ oldPos = new Vector3f(0,0,0).set(pos).add(1.0f);
+ oldRot = new Quaternion(0,0,0,0).set(rot).mul(0.5f);
+ oldScale = new Vector3f(0,0,0).set(scale).add(1.0f);
+ }
+ }
+
+ public void rotate(Vector3f axis, float angle)
+ {
+ rot = new Quaternion(axis, angle).mul(rot).normalized();
+ }
+
+ public void lookAt(Vector3f point, Vector3f up)
+ {
+ rot = getLookAtRotation(point, up);
+ }
+
+ public Quaternion getLookAtRotation(Vector3f point, Vector3f up)
+ {
+ return new Quaternion(new Matrix4f().initRotation(point.sub(pos).normalized(), up));
+ }
+
+ public boolean hasChanged()
+ {
+ if(parent != null && parent.hasChanged())
+ return true;
+
+ if(!pos.equals(oldPos))
+ return true;
+
+ if(!rot.equals(oldRot))
+ return true;
+
+ if(!scale.equals(oldScale))
+ return true;
+
+ return false;
+ }
+
+ public Matrix4f getTransformation()
+ {
+ Matrix4f translationMatrix = new Matrix4f().initTranslation(pos.getX(), pos.getY(), pos.getZ());
+ Matrix4f rotationMatrix = rot.toRotationMatrix();
+ Matrix4f scaleMatrix = new Matrix4f().initScale(scale.getX(), scale.getY(), scale.getZ());
+
+ return getParentMatrix().mul(translationMatrix.mul(rotationMatrix.mul(scaleMatrix)));
+ }
+
+ private Matrix4f getParentMatrix()
+ {
+ if(parent != null && parent.hasChanged())
+ parentMatrix = parent.getTransformation();
+
+ return parentMatrix;
+ }
+
+ public void setParent(Transform parent)
+ {
+ this.parent = parent;
+ }
+
+ public Vector3f getTransformedPos()
+ {
+ return getParentMatrix().transform(pos);
+ }
+
+ public Quaternion getTransformedRot()
+ {
+ Quaternion parentRotation = new Quaternion(0,0,0,1);
+
+ if(parent != null)
+ parentRotation = parent.getTransformedRot();
+
+ return parentRotation.mul(rot);
+ }
+
+ public Vector3f getPos()
+ {
+ return pos;
+ }
+
+ public void setPos(Vector3f pos)
+ {
+ this.pos = pos;
+ }
+
+ public Quaternion getRot()
+ {
+ return rot;
+ }
+
+ public void setRot(Quaternion rotation)
+ {
+ this.rot = rotation;
+ }
+
+ public Vector3f getScale()
+ {
+ return scale;
+ }
+
+ public void setScale(Vector3f scale)
+ {
+ this.scale = scale;
+ }
+}
diff --git a/src/main/java/com/base/engine/core/Util.java b/src/main/java/com/base/engine/core/Util.java
new file mode 100644
index 0000000..57e4a6a
--- /dev/null
+++ b/src/main/java/com/base/engine/core/Util.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.core;
+
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.util.ArrayList;
+
+import com.base.engine.rendering.Vertex;
+import org.lwjgl.BufferUtils;
+
+public class Util
+{
+ public static FloatBuffer createFloatBuffer(int size)
+ {
+ return BufferUtils.createFloatBuffer(size);
+ }
+
+ public static IntBuffer createIntBuffer(int size)
+ {
+ return BufferUtils.createIntBuffer(size);
+ }
+
+ public static ByteBuffer createByteBuffer(int size)
+ {
+ return BufferUtils.createByteBuffer(size);
+ }
+
+ public static IntBuffer createFlippedBuffer(int... values)
+ {
+ IntBuffer buffer = createIntBuffer(values.length);
+ buffer.put(values);
+ buffer.flip();
+
+ return buffer;
+ }
+
+ public static FloatBuffer createFlippedBuffer(Vertex[] vertices)
+ {
+ FloatBuffer buffer = createFloatBuffer(vertices.length * Vertex.SIZE);
+
+ for(int i = 0; i < vertices.length; i++)
+ {
+ buffer.put(vertices[i].getPos().getX());
+ buffer.put(vertices[i].getPos().getY());
+ buffer.put(vertices[i].getPos().getZ());
+ buffer.put(vertices[i].getTexCoord().getX());
+ buffer.put(vertices[i].getTexCoord().getY());
+ buffer.put(vertices[i].getNormal().getX());
+ buffer.put(vertices[i].getNormal().getY());
+ buffer.put(vertices[i].getNormal().getZ());
+ buffer.put(vertices[i].getTangent().getX());
+ buffer.put(vertices[i].getTangent().getY());
+ buffer.put(vertices[i].getTangent().getZ());
+ }
+
+ buffer.flip();
+
+ return buffer;
+ }
+
+ public static FloatBuffer createFlippedBuffer(Matrix4f value)
+ {
+ FloatBuffer buffer = createFloatBuffer(4 * 4);
+
+ for(int i = 0; i < 4; i++)
+ for(int j = 0; j < 4; j++)
+ buffer.put(value.get(i, j));
+
+ buffer.flip();
+
+ return buffer;
+ }
+
+ public static String[] removeEmptyStrings(String[] data)
+ {
+ ArrayList result = new ArrayList();
+
+ for(int i = 0; i < data.length; i++)
+ if(!data[i].equals(""))
+ result.add(data[i]);
+
+ String[] res = new String[result.size()];
+ result.toArray(res);
+
+ return res;
+ }
+
+ public static int[] toIntArray(Integer[] data)
+ {
+ int[] result = new int[data.length];
+
+ for(int i = 0; i < data.length; i++)
+ result[i] = data[i].intValue();
+
+ return result;
+ }
+}
diff --git a/src/main/java/com/base/engine/core/Vector2f.java b/src/main/java/com/base/engine/core/Vector2f.java
new file mode 100644
index 0000000..07ddbe7
--- /dev/null
+++ b/src/main/java/com/base/engine/core/Vector2f.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.core;
+
+public class Vector2f
+{
+ private float x;
+ private float y;
+
+ public Vector2f(float x, float y)
+ {
+ this.x = x;
+ this.y = y;
+ }
+
+ public float length()
+ {
+ return (float)Math.sqrt(x * x + y * y);
+ }
+
+ public float max()
+ {
+ return Math.max(x, y);
+ }
+
+ public float dot(Vector2f r)
+ {
+ return x * r.getX() + y * r.getY();
+ }
+
+ public Vector2f normalized()
+ {
+ float length = length();
+
+ return new Vector2f(x / length, y / length);
+ }
+
+ public float cross(Vector2f r)
+ {
+ return x * r.getY() - y * r.getX();
+ }
+
+ public Vector2f lerp(Vector2f dest, float lerpFactor)
+ {
+ return dest.sub(this).mul(lerpFactor).add(this);
+ }
+
+ public Vector2f rotate(float angle)
+ {
+ double rad = Math.toRadians(angle);
+ double cos = Math.cos(rad);
+ double sin = Math.sin(rad);
+
+ return new Vector2f((float)(x * cos - y * sin),(float)(x * sin + y * cos));
+ }
+
+ public Vector2f add(Vector2f r)
+ {
+ return new Vector2f(x + r.getX(), y + r.getY());
+ }
+
+ public Vector2f add(float r)
+ {
+ return new Vector2f(x + r, y + r);
+ }
+
+ public Vector2f sub(Vector2f r)
+ {
+ return new Vector2f(x - r.getX(), y - r.getY());
+ }
+
+ public Vector2f sub(float r)
+ {
+ return new Vector2f(x - r, y - r);
+ }
+
+ public Vector2f mul(Vector2f r)
+ {
+ return new Vector2f(x * r.getX(), y * r.getY());
+ }
+
+ public Vector2f mul(float r)
+ {
+ return new Vector2f(x * r, y * r);
+ }
+
+ public Vector2f div(Vector2f r)
+ {
+ return new Vector2f(x / r.getX(), y / r.getY());
+ }
+
+ public Vector2f div(float r)
+ {
+ return new Vector2f(x / r, y / r);
+ }
+
+ public Vector2f abs()
+ {
+ return new Vector2f(Math.abs(x), Math.abs(y));
+ }
+
+ public String toString()
+ {
+ return "(" + x + " " + y + ")";
+ }
+
+ public Vector2f set(float x, float y) { this.x = x; this.y = y; return this; }
+ public Vector2f set(Vector2f r) { set(r.getX(), r.getY()); return this; }
+
+ public float getX()
+ {
+ return x;
+ }
+
+ public void setX(float x)
+ {
+ this.x = x;
+ }
+
+ public float getY()
+ {
+ return y;
+ }
+
+ public void setY(float y)
+ {
+ this.y = y;
+ }
+
+ public boolean equals(Vector2f r)
+ {
+ return x == r.getX() && y == r.getY();
+ }
+}
diff --git a/src/main/java/com/base/engine/core/Vector3f.java b/src/main/java/com/base/engine/core/Vector3f.java
new file mode 100644
index 0000000..391aaa8
--- /dev/null
+++ b/src/main/java/com/base/engine/core/Vector3f.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.core;
+
+public class Vector3f
+{
+ private float x;
+ private float y;
+ private float z;
+
+ public Vector3f(float x, float y, float z)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ public float length()
+ {
+ return (float)Math.sqrt(x * x + y * y + z * z);
+ }
+
+ public float max()
+ {
+ return Math.max(x, Math.max(y, z));
+ }
+
+ public float dot(Vector3f r)
+ {
+ return x * r.getX() + y * r.getY() + z * r.getZ();
+ }
+
+ public Vector3f cross(Vector3f r)
+ {
+ float x_ = y * r.getZ() - z * r.getY();
+ float y_ = z * r.getX() - x * r.getZ();
+ float z_ = x * r.getY() - y * r.getX();
+
+ return new Vector3f(x_, y_, z_);
+ }
+
+ public Vector3f normalized()
+ {
+ float length = length();
+
+ return new Vector3f(x / length, y / length, z / length);
+ }
+
+ public Vector3f rotate(Vector3f axis, float angle)
+ {
+ float sinAngle = (float)Math.sin(-angle);
+ float cosAngle = (float)Math.cos(-angle);
+
+ return this.cross(axis.mul(sinAngle)).add( //Rotation on local X
+ (this.mul(cosAngle)).add( //Rotation on local Z
+ axis.mul(this.dot(axis.mul(1 - cosAngle))))); //Rotation on local Y
+ }
+
+ public Vector3f rotate(Quaternion rotation)
+ {
+ Quaternion conjugate = rotation.conjugate();
+
+ Quaternion w = rotation.mul(this).mul(conjugate);
+
+ return new Vector3f(w.getX(), w.getY(), w.getZ());
+ }
+
+ public Vector3f lerp(Vector3f dest, float lerpFactor)
+ {
+ return dest.sub(this).mul(lerpFactor).add(this);
+ }
+
+ public Vector3f add(Vector3f r)
+ {
+ return new Vector3f(x + r.getX(), y + r.getY(), z + r.getZ());
+ }
+
+ public Vector3f add(float r)
+ {
+ return new Vector3f(x + r, y + r, z + r);
+ }
+
+ public Vector3f sub(Vector3f r)
+ {
+ return new Vector3f(x - r.getX(), y - r.getY(), z - r.getZ());
+ }
+
+ public Vector3f sub(float r)
+ {
+ return new Vector3f(x - r, y - r, z - r);
+ }
+
+ public Vector3f mul(Vector3f r)
+ {
+ return new Vector3f(x * r.getX(), y * r.getY(), z * r.getZ());
+ }
+
+ public Vector3f mul(float r)
+ {
+ return new Vector3f(x * r, y * r, z * r);
+ }
+
+ public Vector3f div(Vector3f r)
+ {
+ return new Vector3f(x / r.getX(), y / r.getY(), z / r.getZ());
+ }
+
+ public Vector3f div(float r)
+ {
+ return new Vector3f(x / r, y / r, z / r);
+ }
+
+ public Vector3f abs()
+ {
+ return new Vector3f(Math.abs(x), Math.abs(y), Math.abs(z));
+ }
+
+ public String toString()
+ {
+ return "(" + x + " " + y + " " + z + ")";
+ }
+
+ public Vector2f getXY() { return new Vector2f(x, y); }
+ public Vector2f getYZ() { return new Vector2f(y, z); }
+ public Vector2f getZX() { return new Vector2f(z, x); }
+
+ public Vector2f getYX() { return new Vector2f(y, x); }
+ public Vector2f getZY() { return new Vector2f(z, y); }
+ public Vector2f getXZ() { return new Vector2f(x, z); }
+
+ public Vector3f set(float x, float y, float z) { this.x = x; this.y = y; this.z = z; return this; }
+ public Vector3f set(Vector3f r) { set(r.getX(), r.getY(), r.getZ()); return this; }
+
+ public float getX()
+ {
+ return x;
+ }
+
+ public void setX(float x)
+ {
+ this.x = x;
+ }
+
+ public float getY()
+ {
+ return y;
+ }
+
+ public void setY(float y)
+ {
+ this.y = y;
+ }
+
+ public float getZ()
+ {
+ return z;
+ }
+
+ public void setZ(float z)
+ {
+ this.z = z;
+ }
+
+ public boolean equals(Vector3f r)
+ {
+ return x == r.getX() && y == r.getY() && z == r.getZ();
+ }
+}
diff --git a/src/main/java/com/base/engine/rendering/Attenuation.java b/src/main/java/com/base/engine/rendering/Attenuation.java
new file mode 100644
index 0000000..e8a2b39
--- /dev/null
+++ b/src/main/java/com/base/engine/rendering/Attenuation.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.rendering;
+
+import com.base.engine.core.Vector3f;
+
+public class Attenuation extends Vector3f
+{
+ public Attenuation(float constant, float linear, float exponent) {
+ super(constant, linear, exponent);
+ }
+
+ public float getConstant()
+ {
+ return getX();
+ }
+
+ public float getLinear()
+ {
+ return getY();
+ }
+
+ public float getExponent()
+ {
+ return getZ();
+ }
+}
diff --git a/src/main/java/com/base/engine/rendering/Material.java b/src/main/java/com/base/engine/rendering/Material.java
new file mode 100644
index 0000000..d8687cb
--- /dev/null
+++ b/src/main/java/com/base/engine/rendering/Material.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.rendering;
+
+import com.base.engine.rendering.resourceManagement.MappedValues;
+
+import java.util.HashMap;
+
+public class Material extends MappedValues
+{
+ private HashMap textureHashMap;
+
+ public Material()
+ {
+ super();
+ textureHashMap = new HashMap();
+ textureHashMap.put("normalMap", new Texture("default_normal.jpg"));
+ }
+
+ public void addTexture(String name, Texture texture) { textureHashMap.put(name, texture); }
+
+ public Texture getTexture(String name)
+ {
+ Texture result = textureHashMap.get(name);
+ if(result != null)
+ return result;
+
+ return new Texture("test.png");
+ }
+}
diff --git a/src/main/java/com/base/engine/rendering/Mesh.java b/src/main/java/com/base/engine/rendering/Mesh.java
new file mode 100644
index 0000000..b4559fa
--- /dev/null
+++ b/src/main/java/com/base/engine/rendering/Mesh.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.rendering;
+
+import com.base.engine.core.Util;
+import com.base.engine.core.Vector3f;
+import com.base.engine.rendering.meshLoading.IndexedModel;
+import com.base.engine.rendering.meshLoading.OBJModel;
+import com.base.engine.rendering.resourceManagement.MeshResource;
+import com.base.engine.rendering.Vertex;
+import org.lwjgl.opengl.GL15;
+
+import static org.lwjgl.opengl.GL11.*;
+import static org.lwjgl.opengl.GL15.*;
+import static org.lwjgl.opengl.GL20.*;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class Mesh
+{
+ private static HashMap loadedModels = new HashMap();
+ private MeshResource resource;
+ private String fileName;
+
+ public Mesh(String fileName)
+ {
+ this.fileName = fileName;
+ MeshResource oldResource = loadedModels.get(fileName);
+
+ if(oldResource != null)
+ {
+ resource = oldResource;
+ resource.addReference();
+ }
+ else
+ {
+ loadMesh(fileName);
+ loadedModels.put(fileName, resource);
+ }
+ }
+
+ public Mesh(Vertex[] vertices, int[] indices)
+ {
+ this(vertices, indices, false);
+ }
+
+ public Mesh(Vertex[] vertices, int[] indices, boolean calcNormals)
+ {
+ fileName = "";
+ addVertices(vertices, indices, calcNormals);
+ }
+
+ @Override
+ protected void finalize()
+ {
+ if(resource.removeReference() && !fileName.isEmpty())
+ {
+ loadedModels.remove(fileName);
+ }
+ }
+
+ private void addVertices(Vertex[] vertices, int[] indices, boolean calcNormals)
+ {
+ if(calcNormals)
+ {
+ calcNormals(vertices, indices);
+ }
+
+ resource = new MeshResource(indices.length);
+
+ glBindBuffer(GL_ARRAY_BUFFER, resource.getVbo());
+ GL15.glBufferData(GL_ARRAY_BUFFER, Util.createFlippedBuffer(vertices), GL_STATIC_DRAW);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, resource.getIbo());
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, Util.createFlippedBuffer(indices), GL_STATIC_DRAW);
+ }
+
+ public void draw()
+ {
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(1);
+ glEnableVertexAttribArray(2);
+ glEnableVertexAttribArray(3);
+
+ glBindBuffer(GL_ARRAY_BUFFER, resource.getVbo());
+ glVertexAttribPointer(0, 3, GL_FLOAT, false, Vertex.SIZE * 4, 0);
+ glVertexAttribPointer(1, 2, GL_FLOAT, false, Vertex.SIZE * 4, 12);
+ glVertexAttribPointer(2, 3, GL_FLOAT, false, Vertex.SIZE * 4, 20);
+ glVertexAttribPointer(3, 3, GL_FLOAT, false, Vertex.SIZE * 4, 32);
+ glVertexAttribPointer(3, 3, GL_FLOAT, false, Vertex.SIZE * 4, 44);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, resource.getIbo());
+ glDrawElements(GL_TRIANGLES, resource.getSize(), GL_UNSIGNED_INT, 0);
+
+ glDisableVertexAttribArray(0);
+ glDisableVertexAttribArray(1);
+ glDisableVertexAttribArray(2);
+ glDisableVertexAttribArray(3);
+ }
+
+ private void calcNormals(Vertex[] vertices, int[] indices)
+ {
+ for(int i = 0; i < indices.length; i += 3)
+ {
+ int i0 = indices[i];
+ int i1 = indices[i + 1];
+ int i2 = indices[i + 2];
+
+ Vector3f v1 = vertices[i1].getPos().sub(vertices[i0].getPos());
+ Vector3f v2 = vertices[i2].getPos().sub(vertices[i0].getPos());
+
+ Vector3f normal = v1.cross(v2).normalized();
+
+ vertices[i0].setNormal(vertices[i0].getNormal().add(normal));
+ vertices[i1].setNormal(vertices[i1].getNormal().add(normal));
+ vertices[i2].setNormal(vertices[i2].getNormal().add(normal));
+ }
+
+ for(int i = 0; i < vertices.length; i++)
+ vertices[i].setNormal(vertices[i].getNormal().normalized());
+ }
+
+ private Mesh loadMesh(String fileName)
+ {
+ String[] splitArray = fileName.split("\\.");
+ String ext = splitArray[splitArray.length - 1];
+
+ if(!ext.equals("obj"))
+ {
+ System.err.println("Error: '" + ext + "' file format not supported for mesh data.");
+ new Exception().printStackTrace();
+ System.exit(1);
+ }
+
+ OBJModel test = new OBJModel("./res/models/" + fileName);
+ IndexedModel model = test.toIndexedModel();
+ model.calcNormals();
+
+ ArrayList vertices = new ArrayList();
+
+ for(int i = 0; i < model.getPositions().size(); i++)
+ {
+ vertices.add(new Vertex(model.getPositions().get(i),
+ model.getTexCoords().get(i),
+ model.getNormals().get(i),
+ model.getTangents().get(i)));
+ }
+
+ Vertex[] vertexData = new Vertex[vertices.size()];
+ vertices.toArray(vertexData);
+
+ Integer[] indexData = new Integer[model.getIndices().size()];
+ model.getIndices().toArray(indexData);
+
+ addVertices(vertexData, Util.toIntArray(indexData), false);
+
+ return this;
+ }
+}
diff --git a/src/main/java/com/base/engine/rendering/RenderingEngine.java b/src/main/java/com/base/engine/rendering/RenderingEngine.java
new file mode 100644
index 0000000..8db1bd9
--- /dev/null
+++ b/src/main/java/com/base/engine/rendering/RenderingEngine.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.rendering;
+
+import com.base.engine.components.BaseLight;
+import com.base.engine.components.Camera;
+import com.base.engine.core.GameObject;
+import com.base.engine.core.Transform;
+import com.base.engine.core.Vector3f;
+import com.base.engine.rendering.resourceManagement.MappedValues;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import static org.lwjgl.opengl.GL11.*;
+import static org.lwjgl.opengl.GL11.GL_VERSION;
+import static org.lwjgl.opengl.GL32.GL_DEPTH_CLAMP;
+
+public class RenderingEngine extends MappedValues
+{
+ private HashMap samplerMap;
+ private ArrayList lights;
+ private BaseLight activeLight;
+
+ private Shader forwardAmbient;
+ private Camera mainCamera;
+
+ public RenderingEngine()
+ {
+ super();
+ lights = new ArrayList();
+ samplerMap = new HashMap();
+ samplerMap.put("diffuse", 0);
+ samplerMap.put("normalMap", 1);
+
+ addVector3f("ambient", new Vector3f(0.1f, 0.1f, 0.1f));
+
+ forwardAmbient = new Shader("forward-ambient");
+
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+ glFrontFace(GL_CW);
+ glCullFace(GL_BACK);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_DEPTH_TEST);
+
+ glEnable(GL_DEPTH_CLAMP);
+
+ glEnable(GL_TEXTURE_2D);
+ }
+
+ public void updateUniformStruct(Transform transform, Material material, Shader shader, String uniformName, String uniformType)
+ {
+ throw new IllegalArgumentException(uniformType + " is not a supported type in RenderingEngine");
+ }
+
+ public void render(GameObject object)
+ {
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ object.renderAll(forwardAmbient, this);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE);
+ glDepthMask(false);
+ glDepthFunc(GL_EQUAL);
+
+ for(BaseLight light : lights)
+ {
+ activeLight = light;
+ object.renderAll(light.getShader(), this);
+ }
+
+ glDepthFunc(GL_LESS);
+ glDepthMask(true);
+ glDisable(GL_BLEND);
+ }
+
+ public static String getOpenGLVersion()
+ {
+ return glGetString(GL_VERSION);
+ }
+
+ public void addLight(BaseLight light)
+ {
+ lights.add(light);
+ }
+
+ public void addCamera(Camera camera)
+ {
+ mainCamera = camera;
+ }
+
+ public int getSamplerSlot(String samplerName)
+ {
+ return samplerMap.get(samplerName);
+ }
+
+ public BaseLight getActiveLight()
+ {
+ return activeLight;
+ }
+
+ public Camera getMainCamera()
+ {
+ return mainCamera;
+ }
+
+ public void setMainCamera(Camera mainCamera)
+ {
+ this.mainCamera = mainCamera;
+ }
+}
diff --git a/src/main/java/com/base/engine/rendering/Shader.java b/src/main/java/com/base/engine/rendering/Shader.java
new file mode 100644
index 0000000..c985c2f
--- /dev/null
+++ b/src/main/java/com/base/engine/rendering/Shader.java
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.rendering;
+
+import com.base.engine.components.BaseLight;
+import com.base.engine.components.DirectionalLight;
+import com.base.engine.components.PointLight;
+import com.base.engine.components.SpotLight;
+import com.base.engine.core.*;
+import com.base.engine.rendering.resourceManagement.ShaderResource;
+import com.base.engine.rendering.resourceManagement.TextureResource;
+
+import javax.naming.NameNotFoundException;
+
+import static org.lwjgl.opengl.GL20.*;
+import static org.lwjgl.opengl.GL20.glGetUniformLocation;
+import static org.lwjgl.opengl.GL32.*;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class Shader
+{
+ private static HashMap loadedShaders = new HashMap();
+
+ private ShaderResource resource;
+ private String fileName;
+
+ public Shader(String fileName)
+ {
+ this.fileName = fileName;
+
+ ShaderResource oldResource = loadedShaders.get(fileName);
+
+ if(oldResource != null)
+ {
+ resource = oldResource;
+ resource.addReference();
+ }
+ else
+ {
+ resource = new ShaderResource();
+
+ String vertexShaderText = loadShader(fileName + ".vs");
+ String fragmentShaderText = loadShader(fileName + ".fs");
+
+ addVertexShader(vertexShaderText);
+ addFragmentShader(fragmentShaderText);
+
+ addAllAttributes(vertexShaderText);
+
+ compileShader();
+
+ addAllUniforms(vertexShaderText);
+ addAllUniforms(fragmentShaderText);
+ }
+ }
+
+ public void bind()
+ {
+ glUseProgram(resource.getProgram());
+ }
+
+ public void updateUniforms(Transform transform, Material material, RenderingEngine renderingEngine)
+ {
+ Matrix4f worldMatrix = transform.getTransformation();
+ Matrix4f MVPMatrix = renderingEngine.getMainCamera().getViewProjection().mul(worldMatrix);
+
+ for(int i = 0; i < resource.getUniformNames().size(); i++)
+ {
+ String uniformName = resource.getUniformNames().get(i);
+ String uniformType = resource.getUniformTypes().get(i);
+
+ if(uniformType.equals("sampler2D"))
+ {
+ int samplerSlot = renderingEngine.getSamplerSlot(uniformName);
+ material.getTexture(uniformName).bind(samplerSlot);
+ setUniformi(uniformName, samplerSlot);
+ }
+ else if(uniformName.startsWith("T_"))
+ {
+ if(uniformName.equals("T_MVP"))
+ setUniform(uniformName, MVPMatrix);
+ else if(uniformName.equals("T_model"))
+ setUniform(uniformName, worldMatrix);
+ else
+ throw new IllegalArgumentException(uniformName + " is not a valid component of Transform");
+ }
+ else if(uniformName.startsWith("R_"))
+ {
+ String unprefixedUniformName = uniformName.substring(2);
+ if(uniformType.equals("vec3"))
+ setUniform(uniformName, renderingEngine.getVector3f(unprefixedUniformName));
+ else if(uniformType.equals("float"))
+ setUniformf(uniformName, renderingEngine.getFloat(unprefixedUniformName));
+ else if(uniformType.equals("DirectionalLight"))
+ setUniformDirectionalLight(uniformName, (DirectionalLight)renderingEngine.getActiveLight());
+ else if(uniformType.equals("PointLight"))
+ setUniformPointLight(uniformName, (PointLight)renderingEngine.getActiveLight());
+ else if(uniformType.equals("SpotLight"))
+ setUniformSpotLight(uniformName, (SpotLight)renderingEngine.getActiveLight());
+ else
+ renderingEngine.updateUniformStruct(transform, material, this, uniformName, uniformType);
+ }
+ else if(uniformName.startsWith("C_"))
+ {
+ if(uniformName.equals("C_eyePos"))
+ setUniform(uniformName, renderingEngine.getMainCamera().getTransform().getTransformedPos());
+ else
+ throw new IllegalArgumentException(uniformName + " is not a valid component of Camera");
+ }
+ else
+ {
+ if(uniformType.equals("vec3"))
+ setUniform(uniformName, material.getVector3f(uniformName));
+ else if(uniformType.equals("float"))
+ setUniformf(uniformName, material.getFloat(uniformName));
+ else
+ throw new IllegalArgumentException(uniformType + " is not a supported type in Material");
+ }
+ }
+ }
+
+ private void addAllAttributes(String shaderText)
+ {
+ final String ATTRIBUTE_KEYWORD = "attribute";
+ int attributeStartLocation = shaderText.indexOf(ATTRIBUTE_KEYWORD);
+ int attribNumber = 0;
+ while(attributeStartLocation != -1)
+ {
+ if(!(attributeStartLocation != 0
+ && (Character.isWhitespace(shaderText.charAt(attributeStartLocation - 1)) || shaderText.charAt(attributeStartLocation - 1) == ';')
+ && Character.isWhitespace(shaderText.charAt(attributeStartLocation + ATTRIBUTE_KEYWORD.length())))) {
+ attributeStartLocation = shaderText.indexOf(ATTRIBUTE_KEYWORD, attributeStartLocation + ATTRIBUTE_KEYWORD.length());
+ continue;
+
+ }
+
+ int begin = attributeStartLocation + ATTRIBUTE_KEYWORD.length() + 1;
+ int end = shaderText.indexOf(";", begin);
+
+ String attributeLine = shaderText.substring(begin, end).trim();
+ String attributeName = attributeLine.substring(attributeLine.indexOf(' ') + 1, attributeLine.length()).trim();
+
+ setAttribLocation(attributeName, attribNumber);
+ attribNumber++;
+
+ attributeStartLocation = shaderText.indexOf(ATTRIBUTE_KEYWORD, attributeStartLocation + ATTRIBUTE_KEYWORD.length());
+ }
+ }
+
+ private class GLSLStruct
+ {
+ public String name;
+ public String type;
+ }
+
+ private HashMap> findUniformStructs(String shaderText)
+ {
+ HashMap> result = new HashMap>();
+
+ final String STRUCT_KEYWORD = "struct";
+ int structStartLocation = shaderText.indexOf(STRUCT_KEYWORD);
+ while(structStartLocation != -1)
+ {
+ if(!(structStartLocation != 0
+ && (Character.isWhitespace(shaderText.charAt(structStartLocation - 1)) || shaderText.charAt(structStartLocation - 1) == ';')
+ && Character.isWhitespace(shaderText.charAt(structStartLocation + STRUCT_KEYWORD.length())))) {
+ structStartLocation = shaderText.indexOf(STRUCT_KEYWORD, structStartLocation + STRUCT_KEYWORD.length());
+ continue;
+ }
+
+ int nameBegin = structStartLocation + STRUCT_KEYWORD.length() + 1;
+ int braceBegin = shaderText.indexOf("{", nameBegin);
+ int braceEnd = shaderText.indexOf("}", braceBegin);
+
+ String structName = shaderText.substring(nameBegin, braceBegin).trim();
+ ArrayList glslStructs = new ArrayList();
+
+ int componentSemicolonPos = shaderText.indexOf(";", braceBegin);
+ while(componentSemicolonPos != -1 && componentSemicolonPos < braceEnd)
+ {
+ int componentNameEnd = componentSemicolonPos + 1;
+
+ while(Character.isWhitespace(shaderText.charAt(componentNameEnd - 1)) || shaderText.charAt(componentNameEnd - 1) == ';')
+ componentNameEnd--;
+
+ int componentNameStart = componentSemicolonPos;
+
+ while(!Character.isWhitespace(shaderText.charAt(componentNameStart - 1)))
+ componentNameStart--;
+
+ int componentTypeEnd = componentNameStart;
+
+ while(Character.isWhitespace(shaderText.charAt(componentTypeEnd - 1)))
+ componentTypeEnd--;
+
+ int componentTypeStart = componentTypeEnd;
+
+ while(!Character.isWhitespace(shaderText.charAt(componentTypeStart - 1)))
+ componentTypeStart--;
+
+ String componentName = shaderText.substring(componentNameStart, componentNameEnd);
+ String componentType = shaderText.substring(componentTypeStart, componentTypeEnd);
+
+ GLSLStruct glslStruct = new GLSLStruct();
+ glslStruct.name = componentName;
+ glslStruct.type = componentType;
+
+ glslStructs.add(glslStruct);
+
+ componentSemicolonPos = shaderText.indexOf(";", componentSemicolonPos + 1);
+ }
+
+ result.put(structName, glslStructs);
+
+ structStartLocation = shaderText.indexOf(STRUCT_KEYWORD, structStartLocation + STRUCT_KEYWORD.length());
+ }
+
+ return result;
+ }
+
+ private void addAllUniforms(String shaderText)
+ {
+ HashMap> structs = findUniformStructs(shaderText);
+
+ final String UNIFORM_KEYWORD = "uniform";
+ int uniformStartLocation = shaderText.indexOf(UNIFORM_KEYWORD);
+ while(uniformStartLocation != -1)
+ {
+ if(!(uniformStartLocation != 0
+ && (Character.isWhitespace(shaderText.charAt(uniformStartLocation - 1)) || shaderText.charAt(uniformStartLocation - 1) == ';')
+ && Character.isWhitespace(shaderText.charAt(uniformStartLocation + UNIFORM_KEYWORD.length())))) {
+ uniformStartLocation = shaderText.indexOf(UNIFORM_KEYWORD, uniformStartLocation + UNIFORM_KEYWORD.length());
+ continue;
+ }
+
+ int begin = uniformStartLocation + UNIFORM_KEYWORD.length() + 1;
+ int end = shaderText.indexOf(";", begin);
+
+ String uniformLine = shaderText.substring(begin, end).trim();
+
+ int whiteSpacePos = uniformLine.indexOf(' ');
+ String uniformName = uniformLine.substring(whiteSpacePos + 1, uniformLine.length()).trim();
+ String uniformType = uniformLine.substring(0, whiteSpacePos).trim();
+
+ resource.getUniformNames().add(uniformName);
+ resource.getUniformTypes().add(uniformType);
+ addUniform(uniformName, uniformType, structs);
+
+ uniformStartLocation = shaderText.indexOf(UNIFORM_KEYWORD, uniformStartLocation + UNIFORM_KEYWORD.length());
+ }
+ }
+
+ private void addUniform(String uniformName, String uniformType, HashMap> structs)
+ {
+ boolean addThis = true;
+ ArrayList structComponents = structs.get(uniformType);
+
+ if(structComponents != null)
+ {
+ addThis = false;
+ for(GLSLStruct struct : structComponents)
+ {
+ addUniform(uniformName + "." + struct.name, struct.type, structs);
+ }
+ }
+
+ if(!addThis)
+ return;
+
+ int uniformLocation = glGetUniformLocation(resource.getProgram(), uniformName);
+
+ if(uniformLocation == 0xFFFFFFFF)
+ {
+ System.err.println("Error: Could not find uniform: " + uniformName);
+ new Exception().printStackTrace();
+ System.exit(1);
+ }
+
+ resource.getUniforms().put(uniformName, uniformLocation);
+ }
+
+ private void addVertexShader(String text)
+ {
+ addProgram(text, GL_VERTEX_SHADER);
+ }
+
+ private void addGeometryShader(String text)
+ {
+ addProgram(text, GL_GEOMETRY_SHADER);
+ }
+
+ private void addFragmentShader(String text)
+ {
+ addProgram(text, GL_FRAGMENT_SHADER);
+ }
+
+ private void setAttribLocation(String attributeName, int location)
+ {
+ glBindAttribLocation(resource.getProgram(), location, attributeName);
+ }
+
+ private void compileShader()
+ {
+ glLinkProgram(resource.getProgram());
+
+ if(glGetProgrami(resource.getProgram(), GL_LINK_STATUS) == 0)
+ {
+ System.err.println(glGetProgramInfoLog(resource.getProgram(), 1024));
+ System.exit(1);
+ }
+
+ glValidateProgram(resource.getProgram());
+
+ if(glGetProgrami(resource.getProgram(), GL_VALIDATE_STATUS) == 0)
+ {
+ System.err.println(glGetProgramInfoLog(resource.getProgram(), 1024));
+ System.exit(1);
+ }
+ }
+
+ private void addProgram(String text, int type)
+ {
+ int shader = glCreateShader(type);
+
+ if(shader == 0)
+ {
+ System.err.println("Shader creation failed: Could not find valid memory location when adding shader");
+ System.exit(1);
+ }
+
+ glShaderSource(shader, text);
+ glCompileShader(shader);
+
+ if(glGetShaderi(shader, GL_COMPILE_STATUS) == 0)
+ {
+ System.err.println(glGetShaderInfoLog(shader, 1024));
+ System.exit(1);
+ }
+
+ glAttachShader(resource.getProgram(), shader);
+ }
+
+ private static String loadShader(String fileName)
+ {
+ StringBuilder shaderSource = new StringBuilder();
+ BufferedReader shaderReader = null;
+ final String INCLUDE_DIRECTIVE = "#include";
+
+ try
+ {
+ shaderReader = new BufferedReader(new FileReader("./res/shaders/" + fileName));
+ String line;
+
+ while((line = shaderReader.readLine()) != null)
+ {
+ if(line.startsWith(INCLUDE_DIRECTIVE))
+ {
+ shaderSource.append(loadShader(line.substring(INCLUDE_DIRECTIVE.length() + 2, line.length() - 1)));
+ }
+ else
+ shaderSource.append(line).append("\n");
+ }
+
+ shaderReader.close();
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+
+ return shaderSource.toString();
+ }
+
+ public void setUniformi(String uniformName, int value)
+ {
+ glUniform1i(resource.getUniforms().get(uniformName), value);
+ }
+
+ public void setUniformf(String uniformName, float value)
+ {
+ glUniform1f(resource.getUniforms().get(uniformName), value);
+ }
+
+ public void setUniform(String uniformName, Vector3f value)
+ {
+ glUniform3f(resource.getUniforms().get(uniformName), value.getX(), value.getY(), value.getZ());
+ }
+
+ public void setUniform(String uniformName, Matrix4f value)
+ {
+ glUniformMatrix4(resource.getUniforms().get(uniformName), true, Util.createFlippedBuffer(value));
+ }
+
+ public void setUniformBaseLight(String uniformName, BaseLight baseLight)
+ {
+ setUniform(uniformName + ".color", baseLight.getColor());
+ setUniformf(uniformName + ".intensity", baseLight.getIntensity());
+ }
+
+ public void setUniformDirectionalLight(String uniformName, DirectionalLight directionalLight)
+ {
+ setUniformBaseLight(uniformName + ".base", directionalLight);
+ setUniform(uniformName + ".direction", directionalLight.getDirection());
+ }
+
+ public void setUniformPointLight(String uniformName, PointLight pointLight)
+ {
+ setUniformBaseLight(uniformName + ".base", pointLight);
+ setUniformf(uniformName + ".atten.constant", pointLight.getAttenuation().getConstant());
+ setUniformf(uniformName + ".atten.linear", pointLight.getAttenuation().getLinear());
+ setUniformf(uniformName + ".atten.exponent", pointLight.getAttenuation().getExponent());
+ setUniform(uniformName + ".position", pointLight.getTransform().getTransformedPos());
+ setUniformf(uniformName + ".range", pointLight.getRange());
+ }
+
+ public void setUniformSpotLight(String uniformName, SpotLight spotLight)
+ {
+ setUniformPointLight(uniformName + ".pointLight", spotLight);
+ setUniform(uniformName + ".direction", spotLight.getDirection());
+ setUniformf(uniformName + ".cutoff", spotLight.getCutoff());
+ }
+}
diff --git a/src/main/java/com/base/engine/rendering/Texture.java b/src/main/java/com/base/engine/rendering/Texture.java
new file mode 100644
index 0000000..80fc37e
--- /dev/null
+++ b/src/main/java/com/base/engine/rendering/Texture.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.rendering;
+
+import static org.lwjgl.opengl.GL11.*;
+import static org.lwjgl.opengl.GL13.*;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+
+import com.base.engine.core.*;
+import com.base.engine.rendering.resourceManagement.TextureResource;
+
+import javax.imageio.ImageIO;
+
+public class Texture
+{
+ private static HashMap loadedTextures = new HashMap();
+ private TextureResource resource;
+ private String fileName;
+
+ public Texture(String fileName)
+ {
+ this.fileName = fileName;
+ TextureResource oldResource = loadedTextures.get(fileName);
+
+ if(oldResource != null)
+ {
+ resource = oldResource;
+ resource.addReference();
+ }
+ else
+ {
+ resource = loadTexture(fileName);
+ loadedTextures.put(fileName, resource);
+ }
+ }
+
+ @Override
+ protected void finalize()
+ {
+ if(resource.removeReference() && !fileName.isEmpty())
+ {
+ loadedTextures.remove(fileName);
+ }
+ }
+
+ public void bind()
+ {
+ bind(0);
+ }
+
+ public void bind(int samplerSlot)
+ {
+ assert(samplerSlot >= 0 && samplerSlot <= 31);
+ glActiveTexture(GL_TEXTURE0 + samplerSlot);
+ glBindTexture(GL_TEXTURE_2D, resource.getId());
+ }
+
+ public int getID()
+ {
+ return resource.getId();
+ }
+
+ private static TextureResource loadTexture(String fileName)
+ {
+ try
+ {
+ BufferedImage image = ImageIO.read(new File("./res/textures/" + fileName));
+ int[] pixels = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth());
+
+ ByteBuffer buffer = Util.createByteBuffer(image.getHeight() * image.getWidth() * 4);
+ boolean hasAlpha = image.getColorModel().hasAlpha();
+
+ for(int y = 0; y < image.getHeight(); y++)
+ {
+ for(int x = 0; x < image.getWidth(); x++)
+ {
+ int pixel = pixels[y * image.getWidth() + x];
+
+ buffer.put((byte)((pixel >> 16) & 0xFF));
+ buffer.put((byte)((pixel >> 8) & 0xFF));
+ buffer.put((byte)((pixel) & 0xFF));
+ if(hasAlpha)
+ buffer.put((byte)((pixel >> 24) & 0xFF));
+ else
+ buffer.put((byte)(0xFF));
+ }
+ }
+
+ buffer.flip();
+
+ TextureResource resource = new TextureResource();
+ glBindTexture(GL_TEXTURE_2D, resource.getId());
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+ return resource;
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ return null;
+ }
+}
diff --git a/src/main/java/com/base/engine/rendering/Vertex.java b/src/main/java/com/base/engine/rendering/Vertex.java
new file mode 100644
index 0000000..c17acd2
--- /dev/null
+++ b/src/main/java/com/base/engine/rendering/Vertex.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.rendering;
+
+import com.base.engine.core.Vector2f;
+import com.base.engine.core.Vector3f;
+
+public class Vertex
+{
+ public static final int SIZE = 11;
+
+ private Vector3f pos;
+ private Vector2f texCoord;
+ private Vector3f normal;
+ private Vector3f tangent;
+
+ public Vertex(Vector3f pos)
+ {
+ this(pos, new Vector2f(0,0));
+ }
+
+ public Vertex(Vector3f pos, Vector2f texCoord)
+ {
+ this(pos, texCoord, new Vector3f(0,0,0));
+ }
+
+ public Vertex(Vector3f pos, Vector2f texCoord, Vector3f normal)
+ {
+ this(pos, texCoord, normal, new Vector3f(0,0,0));
+ }
+
+ public Vertex(Vector3f pos, Vector2f texCoord, Vector3f normal, Vector3f tangent)
+ {
+ this.pos = pos;
+ this.texCoord = texCoord;
+ this.normal = normal;
+ this.tangent = tangent;
+ }
+
+ public Vector3f getTangent() {
+ return tangent;
+ }
+
+ public void setTangent(Vector3f tangent) {
+ this.tangent = tangent;
+ }
+
+ public Vector3f getPos()
+ {
+ return pos;
+ }
+
+ public void setPos(Vector3f pos)
+ {
+ this.pos = pos;
+ }
+
+ public Vector2f getTexCoord()
+ {
+ return texCoord;
+ }
+
+ public void setTexCoord(Vector2f texCoord)
+ {
+ this.texCoord = texCoord;
+ }
+
+ public Vector3f getNormal()
+ {
+ return normal;
+ }
+
+ public void setNormal(Vector3f normal)
+ {
+ this.normal = normal;
+ }
+}
diff --git a/src/main/java/com/base/engine/rendering/Window.java b/src/main/java/com/base/engine/rendering/Window.java
new file mode 100644
index 0000000..44f9c14
--- /dev/null
+++ b/src/main/java/com/base/engine/rendering/Window.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.rendering;
+
+import com.base.engine.core.Vector2f;
+import org.lwjgl.LWJGLException;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.Display;
+import org.lwjgl.opengl.DisplayMode;
+
+public class Window
+{
+ public static void createWindow(int width, int height, String title)
+ {
+ Display.setTitle(title);
+ try
+ {
+ Display.setDisplayMode(new DisplayMode(width, height));
+ Display.create();
+ Keyboard.create();
+ Mouse.create();
+ }
+ catch (LWJGLException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public static void render()
+ {
+ Display.update();
+ }
+
+ public static void dispose()
+ {
+ Display.destroy();
+ Keyboard.destroy();
+ Mouse.destroy();
+ }
+
+ public static boolean isCloseRequested()
+ {
+ return Display.isCloseRequested();
+ }
+
+ public static int getWidth()
+ {
+ return Display.getDisplayMode().getWidth();
+ }
+
+ public static int getHeight()
+ {
+ return Display.getDisplayMode().getHeight();
+ }
+
+ public static String getTitle()
+ {
+ return Display.getTitle();
+ }
+
+ public Vector2f getCenter()
+ {
+ return new Vector2f(getWidth()/2, getHeight()/2);
+ }
+}
diff --git a/src/main/java/com/base/engine/rendering/meshLoading/IndexedModel.java b/src/main/java/com/base/engine/rendering/meshLoading/IndexedModel.java
new file mode 100644
index 0000000..8035eb0
--- /dev/null
+++ b/src/main/java/com/base/engine/rendering/meshLoading/IndexedModel.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.rendering.meshLoading;
+
+import com.base.engine.core.Vector2f;
+import com.base.engine.core.Vector3f;
+import com.base.engine.rendering.Vertex;
+
+import java.util.ArrayList;
+
+public class IndexedModel
+{
+ private ArrayList positions;
+ private ArrayList texCoords;
+ private ArrayList normals;
+ private ArrayList tangents;
+ private ArrayList indices;
+
+ public IndexedModel()
+ {
+ positions = new ArrayList();
+ texCoords = new ArrayList();
+ normals = new ArrayList();
+ tangents = new ArrayList();
+ indices = new ArrayList();
+ }
+
+ public void calcNormals()
+ {
+ for(int i = 0; i < indices.size(); i += 3)
+ {
+ int i0 = indices.get(i);
+ int i1 = indices.get(i + 1);
+ int i2 = indices.get(i + 2);
+
+ Vector3f v1 = positions.get(i1).sub(positions.get(i0));
+ Vector3f v2 = positions.get(i2).sub(positions.get(i0));
+
+ Vector3f normal = v1.cross(v2).normalized();
+
+ normals.get(i0).set(normals.get(i0).add(normal));
+ normals.get(i1).set(normals.get(i1).add(normal));
+ normals.get(i2).set(normals.get(i2).add(normal));
+ }
+
+ for(int i = 0; i < normals.size(); i++)
+ normals.get(i).set(normals.get(i).normalized());
+ }
+
+ public void calcTangents()
+ {
+ for(int i = 0; i < indices.size(); i += 3)
+ {
+ int i0 = indices.get(i);
+ int i1 = indices.get(i + 1);
+ int i2 = indices.get(i + 2);
+
+ Vector3f edge1 = positions.get(i1).sub(positions.get(i0));
+ Vector3f edge2 = positions.get(i2).sub(positions.get(i0));
+
+ float deltaU1 = texCoords.get(i1).getX() - texCoords.get(i0).getX();
+ float deltaV1 = texCoords.get(i1).getY() - texCoords.get(i0).getY();
+ float deltaU2 = texCoords.get(i2).getX() - texCoords.get(i0).getX();
+ float deltaV2 = texCoords.get(i2).getY() - texCoords.get(i0).getY();
+
+ float dividend = (deltaU1*deltaV2 - deltaU2*deltaV1);
+ //TODO: The first 1.0f may need to be changed to 0.0f here.
+ float f = dividend == 0 ? 1.0f : 1.0f/dividend;
+
+ Vector3f tangent = new Vector3f(0,0,0);
+ tangent.setX(f * (deltaV2 * edge1.getX() - deltaV1 * edge2.getX()));
+ tangent.setY(f * (deltaV2 * edge1.getY() - deltaV1 * edge2.getY()));
+ tangent.setZ(f * (deltaV2 * edge1.getZ() - deltaV1 * edge2.getZ()));
+
+ tangents.get(i0).set(tangents.get(i0).add(tangent));
+ tangents.get(i1).set(tangents.get(i1).add(tangent));
+ tangents.get(i2).set(tangents.get(i2).add(tangent));
+ }
+
+ for(int i = 0; i < tangents.size(); i++)
+ tangents.get(i).set(tangents.get(i).normalized());
+ }
+
+ public ArrayList getPositions() { return positions; }
+ public ArrayList getTexCoords() { return texCoords; }
+ public ArrayList getNormals() { return normals; }
+ public ArrayList getTangents() { return tangents; }
+ public ArrayList getIndices() { return indices; }
+}
diff --git a/src/main/java/com/base/engine/rendering/meshLoading/OBJIndex.java b/src/main/java/com/base/engine/rendering/meshLoading/OBJIndex.java
new file mode 100644
index 0000000..06beac4
--- /dev/null
+++ b/src/main/java/com/base/engine/rendering/meshLoading/OBJIndex.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.rendering.meshLoading;
+
+public class OBJIndex
+{
+ public int vertexIndex;
+ public int texCoordIndex;
+ public int normalIndex;
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ OBJIndex index = (OBJIndex)obj;
+
+ return vertexIndex == index.vertexIndex
+ && texCoordIndex == index.texCoordIndex
+ && normalIndex == index.normalIndex;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int BASE = 17;
+ final int MULTIPLIER = 31;
+
+ int result = BASE;
+
+ result = MULTIPLIER * result + vertexIndex;
+ result = MULTIPLIER * result + texCoordIndex;
+ result = MULTIPLIER * result + normalIndex;
+
+ return result;
+ }
+}
diff --git a/src/main/java/com/base/engine/rendering/meshLoading/OBJModel.java b/src/main/java/com/base/engine/rendering/meshLoading/OBJModel.java
new file mode 100644
index 0000000..cf0cd60
--- /dev/null
+++ b/src/main/java/com/base/engine/rendering/meshLoading/OBJModel.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.rendering.meshLoading;
+
+import com.base.engine.core.Util;
+import com.base.engine.core.Vector2f;
+import com.base.engine.core.Vector3f;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class OBJModel
+{
+ private ArrayList positions;
+ private ArrayList texCoords;
+ private ArrayList normals;
+ private ArrayList indices;
+ private boolean hasTexCoords;
+ private boolean hasNormals;
+
+ public OBJModel(String fileName)
+ {
+ positions = new ArrayList();
+ texCoords = new ArrayList();
+ normals = new ArrayList();
+ indices = new ArrayList();
+ hasTexCoords = false;
+ hasNormals = false;
+
+ BufferedReader meshReader = null;
+
+ try
+ {
+ meshReader = new BufferedReader(new FileReader(fileName));
+ String line;
+
+ while((line = meshReader.readLine()) != null)
+ {
+ String[] tokens = line.split(" ");
+ tokens = Util.removeEmptyStrings(tokens);
+
+ if(tokens.length == 0 || tokens[0].equals("#"))
+ continue;
+ else if(tokens[0].equals("v"))
+ {
+ positions.add(new Vector3f(Float.valueOf(tokens[1]),
+ Float.valueOf(tokens[2]),
+ Float.valueOf(tokens[3])));
+ }
+ else if(tokens[0].equals("vt"))
+ {
+ texCoords.add(new Vector2f(Float.valueOf(tokens[1]),
+ Float.valueOf(tokens[2])));
+ }
+ else if(tokens[0].equals("vn"))
+ {
+ normals.add(new Vector3f(Float.valueOf(tokens[1]),
+ Float.valueOf(tokens[2]),
+ Float.valueOf(tokens[3])));
+ }
+ else if(tokens[0].equals("f"))
+ {
+ for(int i = 0; i < tokens.length - 3; i++)
+ {
+ indices.add(parseOBJIndex(tokens[1]));
+ indices.add(parseOBJIndex(tokens[2 + i]));
+ indices.add(parseOBJIndex(tokens[3 + i]));
+ }
+ }
+ }
+
+ meshReader.close();
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ public IndexedModel toIndexedModel()
+ {
+ IndexedModel result = new IndexedModel();
+ IndexedModel normalModel = new IndexedModel();
+ HashMap resultIndexMap = new HashMap();
+ HashMap normalIndexMap = new HashMap();
+ HashMap indexMap = new HashMap();
+
+ for(int i = 0; i < indices.size(); i++)
+ {
+ OBJIndex currentIndex = indices.get(i);
+
+ Vector3f currentPosition = positions.get(currentIndex.vertexIndex);
+ Vector2f currentTexCoord;
+ Vector3f currentNormal;
+
+ if(hasTexCoords)
+ currentTexCoord = texCoords.get(currentIndex.texCoordIndex);
+ else
+ currentTexCoord = new Vector2f(0,0);
+
+ if(hasNormals)
+ currentNormal = normals.get(currentIndex.normalIndex);
+ else
+ currentNormal = new Vector3f(0,0,0);
+
+ Integer modelVertexIndex = resultIndexMap.get(currentIndex);
+
+ if(modelVertexIndex == null)
+ {
+ modelVertexIndex = result.getPositions().size();
+ resultIndexMap.put(currentIndex, modelVertexIndex);
+
+ result.getPositions().add(currentPosition);
+ result.getTexCoords().add(currentTexCoord);
+ if(hasNormals)
+ result.getNormals().add(currentNormal);
+ result.getTangents().add(new Vector3f(0,0,0));
+ }
+
+ Integer normalModelIndex = normalIndexMap.get(currentIndex.vertexIndex);
+
+ if(normalModelIndex == null)
+ {
+ normalModelIndex = normalModel.getPositions().size();
+ normalIndexMap.put(currentIndex.vertexIndex, normalModelIndex);
+
+ normalModel.getPositions().add(currentPosition);
+ normalModel.getTexCoords().add(currentTexCoord);
+ normalModel.getNormals().add(currentNormal);
+ normalModel.getTangents().add(new Vector3f(0,0,0));
+ }
+
+ result.getIndices().add(modelVertexIndex);
+ normalModel.getIndices().add(normalModelIndex);
+ indexMap.put(modelVertexIndex, normalModelIndex);
+ }
+
+ if(!hasNormals)
+ {
+ normalModel.calcNormals();
+
+ for(int i = 0; i < result.getPositions().size(); i++)
+ result.getNormals().add(normalModel.getNormals().get(indexMap.get(i)));
+ }
+
+ normalModel.calcTangents();
+
+ for(int i = 0; i < result.getPositions().size(); i++)
+ result.getTangents().add(normalModel.getTangents().get(indexMap.get(i)));
+
+ return result;
+ }
+
+ private OBJIndex parseOBJIndex(String token)
+ {
+ String[] values = token.split("/");
+
+ OBJIndex result = new OBJIndex();
+ result.vertexIndex = Integer.parseInt(values[0]) - 1;
+
+ if(values.length > 1)
+ {
+ hasTexCoords = true;
+ result.texCoordIndex = Integer.parseInt(values[1]) - 1;
+
+ if(values.length > 2)
+ {
+ hasNormals = true;
+ result.normalIndex = Integer.parseInt(values[2]) - 1;
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/src/main/java/com/base/engine/rendering/resourceManagement/MappedValues.java b/src/main/java/com/base/engine/rendering/resourceManagement/MappedValues.java
new file mode 100644
index 0000000..970f3f2
--- /dev/null
+++ b/src/main/java/com/base/engine/rendering/resourceManagement/MappedValues.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.rendering.resourceManagement;
+
+import com.base.engine.core.Vector3f;
+
+import java.util.HashMap;
+
+public abstract class MappedValues
+{
+ private HashMap vector3fHashMap;
+ private HashMap floatHashMap;
+
+ public MappedValues()
+ {
+ vector3fHashMap = new HashMap();
+ floatHashMap = new HashMap();
+ }
+
+ public void addVector3f(String name, Vector3f vector3f) { vector3fHashMap.put(name, vector3f); }
+ public void addFloat(String name, float floatValue) { floatHashMap.put(name, floatValue); }
+
+ public Vector3f getVector3f(String name)
+ {
+ Vector3f result = vector3fHashMap.get(name);
+ if(result != null)
+ return result;
+
+ return new Vector3f(0,0,0);
+ }
+
+ public float getFloat(String name)
+ {
+ Float result = floatHashMap.get(name);
+ if(result != null)
+ return result;
+
+ return 0;
+ }
+}
diff --git a/src/main/java/com/base/engine/rendering/resourceManagement/MeshResource.java b/src/main/java/com/base/engine/rendering/resourceManagement/MeshResource.java
new file mode 100644
index 0000000..47db5b5
--- /dev/null
+++ b/src/main/java/com/base/engine/rendering/resourceManagement/MeshResource.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.rendering.resourceManagement;
+
+import static org.lwjgl.opengl.GL15.*;
+
+public class MeshResource
+{
+ private int vbo;
+ private int ibo;
+ private int size;
+ private int refCount;
+
+ public MeshResource(int size)
+ {
+ vbo = glGenBuffers();
+ ibo = glGenBuffers();
+ this.size = size;
+ this.refCount = 1;
+ }
+
+ @Override
+ protected void finalize()
+ {
+ glDeleteBuffers(vbo);
+ glDeleteBuffers(ibo);
+ }
+
+ public void addReference()
+ {
+ refCount++;
+ }
+
+ public boolean removeReference()
+ {
+ refCount--;
+ return refCount == 0;
+ }
+
+ public int getVbo() {
+ return vbo;
+ }
+
+ public int getIbo() {
+ return ibo;
+ }
+
+ public int getSize() {
+ return size;
+ }
+}
diff --git a/src/main/java/com/base/engine/rendering/resourceManagement/ShaderResource.java b/src/main/java/com/base/engine/rendering/resourceManagement/ShaderResource.java
new file mode 100644
index 0000000..82c9365
--- /dev/null
+++ b/src/main/java/com/base/engine/rendering/resourceManagement/ShaderResource.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.rendering.resourceManagement;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import static org.lwjgl.opengl.GL15.glDeleteBuffers;
+import static org.lwjgl.opengl.GL20.glCreateProgram;
+
+public class ShaderResource
+{
+ private int program;
+ private HashMap uniforms;
+ private ArrayList uniformNames;
+ private ArrayList uniformTypes;
+ private int refCount;
+
+ public ShaderResource()
+ {
+ this.program = glCreateProgram();
+ this.refCount = 1;
+
+ if(program == 0)
+ {
+ System.err.println("Shader creation failed: Could not find valid memory location in constructor");
+ System.exit(1);
+ }
+
+ uniforms = new HashMap();
+ uniformNames = new ArrayList();
+ uniformTypes = new ArrayList();
+ }
+
+ @Override
+ protected void finalize()
+ {
+ glDeleteBuffers(program);
+ }
+
+ public void addReference()
+ {
+ refCount++;
+ }
+
+ public boolean removeReference()
+ {
+ refCount--;
+ return refCount == 0;
+ }
+
+ public int getProgram() { return program; }
+
+ public HashMap getUniforms() {
+ return uniforms;
+ }
+
+ public ArrayList getUniformNames() {
+ return uniformNames;
+ }
+
+ public ArrayList getUniformTypes() {
+ return uniformTypes;
+ }
+}
diff --git a/src/main/java/com/base/engine/rendering/resourceManagement/TextureResource.java b/src/main/java/com/base/engine/rendering/resourceManagement/TextureResource.java
new file mode 100644
index 0000000..5b2c523
--- /dev/null
+++ b/src/main/java/com/base/engine/rendering/resourceManagement/TextureResource.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.engine.rendering.resourceManagement;
+
+import static org.lwjgl.opengl.GL11.glGenTextures;
+import static org.lwjgl.opengl.GL15.glDeleteBuffers;
+
+public class TextureResource
+{
+ private int id;
+ private int refCount;
+
+ public TextureResource()
+ {
+ this.id = glGenTextures();
+ this.refCount = 1;
+ }
+
+ @Override
+ protected void finalize()
+ {
+ glDeleteBuffers(id);
+ }
+
+ public void addReference()
+ {
+ refCount++;
+ }
+
+ public boolean removeReference()
+ {
+ refCount--;
+ return refCount == 0;
+ }
+
+ public int getId() { return id; }
+}
diff --git a/src/main/java/com/base/game/LookAtComponent.java b/src/main/java/com/base/game/LookAtComponent.java
new file mode 100644
index 0000000..48f9c20
--- /dev/null
+++ b/src/main/java/com/base/game/LookAtComponent.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.game;
+
+import com.base.engine.components.GameComponent;
+import com.base.engine.core.*;
+import com.base.engine.rendering.RenderingEngine;
+import com.base.engine.rendering.Shader;
+
+public class LookAtComponent extends GameComponent
+{
+ RenderingEngine renderingEngine;
+
+ @Override
+ public void update(float delta)
+ {
+ if(renderingEngine != null)
+ {
+ Quaternion newRot = getTransform().getLookAtRotation(renderingEngine.getMainCamera().getTransform().getTransformedPos(),
+ new Vector3f(0,1,0));
+ //getTransform().getRot().getUp());
+
+ getTransform().setRot(getTransform().getRot().nlerp(newRot, delta * 5.0f, true));
+ //getTransform().setRot(getTransform().getRot().slerp(newRot, delta * 5.0f, true));
+ }
+ }
+
+ @Override
+ public void render(Shader shader, RenderingEngine renderingEngine)
+ {
+ this.renderingEngine = renderingEngine;
+ }
+}
diff --git a/src/main/java/com/base/game/Main.java b/src/main/java/com/base/game/Main.java
new file mode 100644
index 0000000..bd83003
--- /dev/null
+++ b/src/main/java/com/base/game/Main.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.game;
+
+import com.base.engine.core.CoreEngine;
+
+public class Main
+{
+ public static void main(String[] args)
+ {
+ CoreEngine engine = new CoreEngine(800, 600, 60, new TestGame());
+ engine.createWindow("3D Game Engine");
+ engine.start();
+ }
+}
diff --git a/src/main/java/com/base/game/TestGame.java b/src/main/java/com/base/game/TestGame.java
new file mode 100644
index 0000000..811ebd0
--- /dev/null
+++ b/src/main/java/com/base/game/TestGame.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2014 Benny Bobaganoosh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.base.game;
+
+import com.base.engine.components.*;
+import com.base.engine.core.*;
+import com.base.engine.rendering.*;
+
+public class TestGame extends Game
+{
+ public void init()
+ {
+ Mesh mesh = new Mesh("plane3.obj");
+ Material material = new Material();//new Texture("test.png"), new Vector3f(1,1,1), 1, 8);
+ material.addTexture("diffuse", new Texture("bricks.jpg"));
+ material.addTexture("normalMap", new Texture("bricks_normal.jpg"));
+ material.addFloat("specularIntensity", 1);
+ material.addFloat("specularPower", 8);
+
+ Material material2 = new Material();//new Texture("test.png"), new Vector3f(1,1,1), 1, 8);
+ material2.addTexture("diffuse", new Texture("bricks2.jpg"));
+ material2.addTexture("normalMap", new Texture("bricks2_normal.jpg"));
+ material2.addFloat("specularIntensity", 1);
+ material2.addFloat("specularPower", 8);
+
+ Mesh tempMesh = new Mesh("monkey3.obj");
+
+ MeshRenderer meshRenderer = new MeshRenderer(mesh, material);
+
+ GameObject planeObject = new GameObject();
+ planeObject.addComponent(meshRenderer);
+ planeObject.getTransform().getPos().set(0, -1, 5);
+
+ GameObject directionalLightObject = new GameObject();
+ DirectionalLight directionalLight = new DirectionalLight(new Vector3f(0,0,1), 0.4f);
+
+ directionalLightObject.addComponent(directionalLight);
+
+ GameObject pointLightObject = new GameObject();
+ pointLightObject.addComponent(new PointLight(new Vector3f(0,1,0), 0.4f, new Attenuation(0,0,1)));
+
+ SpotLight spotLight = new SpotLight(new Vector3f(0,1,1), 0.4f,
+ new Attenuation(0,0,0.1f), 0.7f);
+
+ GameObject spotLightObject = new GameObject();
+ spotLightObject.addComponent(spotLight);
+
+ spotLightObject.getTransform().getPos().set(5, 0, 5);
+ spotLightObject.getTransform().setRot(new Quaternion(new Vector3f(0,1,0), (float)Math.toRadians(90.0f)));
+
+ addObject(planeObject);
+ addObject(directionalLightObject);
+ addObject(pointLightObject);
+ addObject(spotLightObject);
+
+ GameObject testMesh3 = new GameObject().addComponent(new LookAtComponent()).addComponent(new MeshRenderer(tempMesh, material));
+
+ addObject(
+ //addObject(
+ new GameObject().addComponent(new FreeLook(0.5f)).addComponent(new FreeMove(10.0f)).addComponent(new Camera((float) Math.toRadians(70.0f), (float) Window.getWidth() / (float) Window.getHeight(), 0.01f, 1000.0f)));
+
+ addObject(testMesh3);
+
+ testMesh3.getTransform().getPos().set(5,5,5);
+ testMesh3.getTransform().setRot(new Quaternion(new Vector3f(0,1,0), (float)Math.toRadians(-70.0f)));
+
+ addObject(new GameObject().addComponent(new MeshRenderer(new Mesh("monkey3.obj"), material2)));
+
+ directionalLight.getTransform().setRot(new Quaternion(new Vector3f(1, 0, 0), (float) Math.toRadians(-45)));
+ }
+}