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))); + } +}