diff --git a/shaders/cubemap.fs.glsl b/shaders/cubemap.fs.glsl new file mode 100644 index 0000000..ffcf6c3 --- /dev/null +++ b/shaders/cubemap.fs.glsl @@ -0,0 +1,12 @@ +#version 330 + +in vec3 texCoord; + +out vec4 outputColor; + +uniform samplerCube cubemap; + +void main() +{ + outputColor = texture(cubemap, texCoord); +} diff --git a/shaders/cubemap.vs.glsl b/shaders/cubemap.vs.glsl new file mode 100644 index 0000000..5b14f79 --- /dev/null +++ b/shaders/cubemap.vs.glsl @@ -0,0 +1,14 @@ +#version 330 + +layout(location = 0) in vec3 position; +layout(location = 1) in vec3 texturePos; + +out vec3 texCoord; + +uniform mat4 CameraMatrix; +uniform mat4 ModelMatrix; + +void main() { + gl_Position = CameraMatrix * ModelMatrix * vec4(position, 1.0); + texCoord = vec3(texturePos.x, -texturePos.y, texturePos.z); +} diff --git a/shaders/object.fs.glsl b/shaders/object.fs.glsl new file mode 100644 index 0000000..26a6c4f --- /dev/null +++ b/shaders/object.fs.glsl @@ -0,0 +1,63 @@ +#version 400 +struct LightSource { + //int type; so far only point lights supported + int enabled; + vec3 position; +}; +struct Material { + vec3 ambient; + vec3 diffuse; + vec3 specular; + int shininess; +}; + + + +in vec2 fragTexCoord; +in vec3 fragNormal; +in vec3 fragPos; + +out vec4 outputColor; + +uniform mat4 ModelMatrix; +uniform sampler2D textureSampler; +uniform Material material; +uniform vec3 EyePos; + +const int MaxLigths = 10; +uniform LightSource lights[MaxLigths]; + + + + +void main() +{ + //calculate normal in world coordinates + mat3 normalMatrix = transpose(inverse(mat3(ModelMatrix))); + vec3 normal = normalize(normalMatrix * fragNormal); + vec3 eyeDir = normalize(EyePos - fragPos); + + for(int i = 0; i < MaxLigths; ++i) { + //calculate the vector from this pixels surface to the light source + vec3 lightDir = lights[i].position - fragPos; + + float attenuation = 1.0 / length(lightDir); + lightDir = normalize(lightDir); + + + //Diffuse + float diffuseIntensity = max(0.0, dot(normal, lightDir)); + vec3 diffuseLight = attenuation * material.diffuse * diffuseIntensity; + + //Specular + vec3 reflection = 2 * dot(lightDir, normal) * normal - lightDir; + float specularIntensity = max(0.0, dot(reflection, eyeDir)); + specularIntensity = pow(specularIntensity, material.shininess); + + vec3 specularLight = attenuation * specularIntensity * material.specular; + + + vec4 color = texture(textureSampler, fragTexCoord); + outputColor += lights[i].enabled * color * vec4(material.ambient + diffuseLight, 1.0) + specularLight; + } +} diff --git a/shaders/object.vs.glsl b/shaders/object.vs.glsl new file mode 100644 index 0000000..afb7f91 --- /dev/null +++ b/shaders/object.vs.glsl @@ -0,0 +1,20 @@ +#version 330 + +layout(location = 0) in vec3 position; +layout(location = 1) in vec2 texturePos; +layout(location = 2) in vec3 normalVec; + +out vec2 fragTexCoord; +out vec3 fragNormal; +out vec3 fragPos; + +uniform mat4 ModelMatrix; +uniform mat4 CameraMatrix; + +void main() { + gl_Position = CameraMatrix * ModelMatrix * vec4(position, 1.0); + + fragTexCoord = texturePos; + fragNormal = normalVec; + fragPos = vec3(ModelMatrix * vec4(position, 1)); +} diff --git a/src/org/kuchelmeister/engine/Scene.java b/src/org/kuchelmeister/engine/Scene.java new file mode 100644 index 0000000..7ef6445 --- /dev/null +++ b/src/org/kuchelmeister/engine/Scene.java @@ -0,0 +1,135 @@ +package org.kuchelmeister.engine; + +import java.util.LinkedList; +import java.util.List; + +import javax.swing.JFrame; + +import org.apache.commons.lang3.time.StopWatch; +import org.kuchelmeister.engine.camera.Camera; +import org.kuchelmeister.engine.geometry.GraphicalObject; +import org.kuchelmeister.engine.geometry.skybox.Skybox; +import org.kuchelmeister.engine.input.CameraKeyListener; + +import com.jogamp.opengl.GL3; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.awt.GLCanvas; +import com.jogamp.opengl.util.FPSAnimator; + +public class Scene extends JFrame implements GLEventListener { + private final StopWatch stopWatch; + private static final long serialVersionUID = 1L; + + protected final Camera camera; + private Skybox skybox; + private final List graphicsObjects; + + private final GLCanvas canvas; + private final FPSAnimator animator; + + private final CameraKeyListener kListener; + + public GLCanvas getCanvas() { + return canvas; + } + + public Scene(final int width, final int height, final String title) { + super(title); + + this.setSize(width, height); + this.setLocationRelativeTo(null); + this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + final GLProfile profile = GLProfile.get(GLProfile.GL3); + final GLCapabilities capabilities = new GLCapabilities(profile); + capabilities.setDoubleBuffered(true); + + canvas = new GLCanvas(capabilities); + this.getContentPane().add(canvas); + camera = new Camera(); + kListener = new CameraKeyListener(camera); + canvas.addKeyListener(kListener); + canvas.addGLEventListener(this); + + canvas.setAutoSwapBufferMode(false); + + this.getContentPane().add(canvas); + + this.graphicsObjects = new LinkedList<>(); + animator = new FPSAnimator(canvas, 60, true); + stopWatch = new StopWatch(); + stopWatch.start(); + } + + public void addGraphicalObject(final GraphicalObject gObject) { + gObject.setCamera(camera); + graphicsObjects.add(gObject); + } + + public void setSkybox(final String[] textures) { + this.skybox = new Skybox(this.camera, 10.0f, textures); + } + + @Override + public void init(final GLAutoDrawable drawable) { + + System.out.println("INFO: init()"); + System.setProperty("sun.awt.noerasebackground", "true"); + System.setProperty("sun.java2d.noddraw", "true"); + final GL3 gl = drawable.getGL().getGL3(); + gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + + if (skybox != null) { + skybox.init(gl); + } + for (final GraphicalObject graphicalObject : graphicsObjects) { + graphicalObject.init(gl); + } + } + + public void run() { + this.setVisible(true); + animator.start(); + } + + public void updateObj() { + + for (final GraphicalObject graphicalObject : graphicsObjects) { + graphicalObject.update(); + } + } + + @Override + public void display(final GLAutoDrawable drawable) { + updateObj(); + + // System.out.println("INFO: display()"); + + final GL3 gl = drawable.getGL().getGL3(); + gl.glClear(GL3.GL_COLOR_BUFFER_BIT | GL3.GL_DEPTH_BUFFER_BIT); + + if (skybox != null) { + skybox.display(gl); + } + for (final GraphicalObject graphicalObject : graphicsObjects) { + graphicalObject.display(gl); + } + gl.glFlush(); + canvas.swapBuffers(); + } + + @Override + public void dispose(final GLAutoDrawable drawable) { + System.out.println("INFO: dispose()"); + } + + @Override + public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { + System.out.printf("INFO: reshape(%d, %d, %d, %d)\n", x, y, width, height); + // windowHeight = height; + } + +} diff --git a/src/org/kuchelmeister/engine/camera/Camera.java b/src/org/kuchelmeister/engine/camera/Camera.java new file mode 100644 index 0000000..9b5d2cb --- /dev/null +++ b/src/org/kuchelmeister/engine/camera/Camera.java @@ -0,0 +1,177 @@ +package org.kuchelmeister.engine.camera; + +import org.joml.Matrix4f; +import org.joml.Vector3f; +import org.joml.Vector4f; + +public class Camera { + public static final float MAX_VERTICAL_ANGLE = 85.0f; + private Vector3f position; + private float fieldOfView; + + private float horizontalAngle; + private float verticalAngle; + + private float nearPlane; + private float farPlane; + + private float viewportAspectRatio; + + private Matrix4f view; + private Matrix4f projection; + + public Camera() { + this.setPosition(new Vector3f(0.0f, 0.0f, 0.0f)); + this.setHorizontalAngle(0.0f); + this.setVerticalAngle(0.0f); + this.setFieldOfView(50.0f); + this.setNearAndFarPlanes(0.01f, 100.0f); + this.setViewportAspectRatio(4.0f / 3.0f); + } + + public Camera(final Camera c) { + this.setPosition(new Vector3f(c.getPosition())); + this.setHorizontalAngle(c.getHorizontalAngle()); + this.setVerticalAngle(c.getVerticalAngle()); + this.setFieldOfView(c.getFieldOfView()); + this.setNearAndFarPlanes(c.getNearPlane(), c.getFarPlane()); + this.setViewportAspectRatio(c.getViewportAspectRatio()); + } + + public static float[] toFloatArray(final Matrix4f m) { + final float[] arr = new float[16]; + m.get(arr); + return arr; + } + + public void lookAt(final Vector3f lookAt) { + assert (!this.position.equals(lookAt)); + final Vector3f direction = (new Vector3f(this.position)).negate().add(lookAt); + direction.normalize(); + this.verticalAngle = (float) Math.toDegrees(Math.asin(-direction.y)); + this.horizontalAngle = (float) Math.toDegrees(-Math.atan2(-direction.x, -direction.z)); + normalizeAngles(); + } + + public void offsetPosition(final Vector3f offset) { + position.add(offset); + } + + public void setNearAndFarPlanes(final float nearPlane, final float farPlane) { + assert nearPlane > 0.0f && farPlane > nearPlane; + this.nearPlane = nearPlane; + this.farPlane = farPlane; + } + + public Matrix4f getOrientation() { + Matrix4f orientationMatrix = new Matrix4f(); + orientationMatrix = orientationMatrix.rotate((float) Math.toRadians(verticalAngle), + new Vector3f(1.0f, 0.0f, 0.0f)); + orientationMatrix = orientationMatrix.rotate((float) Math.toRadians(horizontalAngle), + new Vector3f(0.0f, 1.0f, 0.0f)); + return orientationMatrix; + } + + public void offsetOrientation(final float upAngle, final float rightAngle) { + this.horizontalAngle += rightAngle; + this.verticalAngle += upAngle; + } + + public Matrix4f getProjection() { + Matrix4f m = new Matrix4f(); + m = m.setPerspective((float) Math.toRadians(fieldOfView), viewportAspectRatio, nearPlane, farPlane); + return m; + } + + public Matrix4f getMatrix() { + return getProjection().mul(getView()); + } + + public Matrix4f getView() { + final Matrix4f m = getOrientation(); + Matrix4f p = new Matrix4f(); + p = p.translate(new Vector3f(this.getPosition()).negate()); + return m.mul(p); + } + + public Vector3f forwardVec() { + Vector4f vec = new Vector4f(0.0f, 0.0f, -1.0f, 1.0f); + vec = vec.mul(getOrientation()); + return new Vector3f(vec.x, vec.y, vec.z); + } + + public Vector3f rightVec() { + Vector4f vec = new Vector4f(1.0f, 0.0f, 0.0f, 1.0f); + vec = vec.mul(getOrientation()); + return new Vector3f(vec.x, vec.y, vec.z); + } + + public Vector3f upVec() { + Vector4f vec = new Vector4f(0.0f, 1.0f, 0.0f, 1.0f); + vec = vec.mul(getOrientation()); + return new Vector3f(vec.x, vec.y, vec.z); + } + + public float getFarPlane() { + return farPlane; + } + + public float getNearPlane() { + return nearPlane; + } + + public Vector3f getPosition() { + return position; + } + + public void setPosition(final Vector3f position) { + this.position = position; + } + + public float getFieldOfView() { + return fieldOfView; + } + + public void setFieldOfView(final float fieldOfView) { + this.fieldOfView = fieldOfView; + } + + public float getHorizontalAngle() { + return horizontalAngle; + } + + public void setHorizontalAngle(final float horizontalAngle) { + this.horizontalAngle = horizontalAngle; + } + + public float getVerticalAngle() { + return verticalAngle; + } + + public void setVerticalAngle(final float verticalAngle) { + this.verticalAngle = verticalAngle; + } + + public float getViewportAspectRatio() { + return viewportAspectRatio; + } + + public void setViewportAspectRatio(final float viewportAspectRatio) { + assert viewportAspectRatio > 0.0f; + this.viewportAspectRatio = viewportAspectRatio; + } + + public void normalizeAngles() { + horizontalAngle = horizontalAngle % 360.0f; + + if (horizontalAngle < 0) { + horizontalAngle += 360.0f; + } + if (verticalAngle > MAX_VERTICAL_ANGLE) { + verticalAngle = MAX_VERTICAL_ANGLE; + } else if (verticalAngle < -MAX_VERTICAL_ANGLE) { + verticalAngle = -MAX_VERTICAL_ANGLE; + } + } + +} diff --git a/src/org/kuchelmeister/engine/geometry/GraphicalObject.java b/src/org/kuchelmeister/engine/geometry/GraphicalObject.java new file mode 100644 index 0000000..f05366d --- /dev/null +++ b/src/org/kuchelmeister/engine/geometry/GraphicalObject.java @@ -0,0 +1,193 @@ +package org.kuchelmeister.engine.geometry; + +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.LinkedList; +import java.util.List; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.time.StopWatch; +import org.joml.Matrix4f; +import org.joml.Vector3f; +import org.kuchelmeister.engine.camera.Camera; +import org.kuchelmeister.engine.geometry.primitive.Triangle; + +import com.jogamp.common.nio.Buffers; +import com.jogamp.opengl.GL3; +import com.jogamp.opengl.util.GLBuffers; + +import shader.Shader; + +public abstract class GraphicalObject { + public static final int DRAWING_MODE = GL3.GL_TRIANGLES; + + private final StopWatch stopWatch; + protected Shader shader; + protected final List faces; + protected final List subGeometry; + + private Matrix4f transformation; + private Camera camera; + + private float[] floatArray; + private int vaoId; + + public GraphicalObject(final Shader shader, final Camera camera) { + this.shader = shader; + this.subGeometry = new LinkedList<>(); + this.faces = new LinkedList<>(); + this.floatArray = new float[0]; + + this.transformation = new Matrix4f(); + this.camera = camera; + this.stopWatch = new StopWatch(); + this.stopWatch.start(); + } + + public void setPosition(final Vector3f pos) { + this.transformation = transformation.setTranslation(pos); + } + + public void setRotation(final float angleX, final float angleY, final float angleZ) { + this.transformation.setRotationXYZ((float) Math.toRadians(angleX), (float) Math.toRadians(angleY), + (float) Math.toRadians(angleZ)); + } + + public void rotate(final float angleDeg, final Vector3f axis) { + this.transformation.rotate((float) Math.toRadians(angleDeg), axis.x, axis.y, axis.z); + } + + public void scale(final Vector3f factor) { + this.transformation.scale(factor.x, factor.y, factor.z); + } + + public void translate(final Vector3f vec) { + this.transformation.translate(vec.x, vec.y, vec.z); + } + + public void generateFaces() { + faces.clear(); + for (final SubGeometry sub : subGeometry) { + faces.addAll(sub.getTriangles()); + } + } + + public void setCamera(final Camera cam) { + this.camera = cam; + } + + public float[] getFloatArray() { + if (this.floatArray.length <= 0) { + generateFaces(); + floatArray = new float[0]; + for (final Triangle triangle : faces) { + floatArray = ArrayUtils.addAll(floatArray, triangle.getVertices()); + } + } + return floatArray; + } + + public void init(final GL3 gl) { + + // A simple temporary integer buffer to exchange data with the GPU + final int vertexArrayObject[] = new int[1]; + // Create a VAO -- Vertex Array Object -- in the GPU's memory + gl.glGenVertexArrays(1, IntBuffer.wrap(vertexArrayObject)); + vaoId = vertexArrayObject[0]; + + // A simple temporary integer buffer to exchange data with the GPU + final int vertexBufferObject[] = new int[1]; + // Create a buffer object in the GPU memory + gl.glGenBuffers(1, IntBuffer.wrap(vertexBufferObject)); + + // Bind our VAO to make it the active VAO in the OpenGL context + gl.glBindVertexArray(vaoId); + { + // Make the buffer the active array buffer: + // e.g. bind the newly created buffer object to the GL_ARRAY_BUFFER + // context + gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, vertexBufferObject[0]); + { + + final FloatBuffer buffer = GLBuffers.newDirectFloatBuffer(this.getFloatArray()); + // allocate the required memory on the GPU and copy the data + // from our vertexData-buffer into that memory + + gl.glBufferData(GL3.GL_ARRAY_BUFFER, this.getFloatArray().length * Buffers.SIZEOF_FLOAT, buffer, + GL3.GL_STATIC_DRAW); + + intiVertexAttributes(gl); + + } + gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, 0); + } + gl.glBindVertexArray(vaoId); + + shader.compile(gl); + + } + + public void setShader() { + + } + + public abstract void intiVertexAttributes(final GL3 gl); + + public void display(final GL3 gl) { + + preDisplay(gl); + + gl.glUseProgram(shader.getProgramId()); + { + + displayParametersANDUniforms(gl); + + gl.glBindVertexArray(vaoId); + gl.glDrawArrays(GraphicalObject.DRAWING_MODE, 0, this.faces.size() * 3); + + } + gl.glUseProgram(0); + gl.glFlush(); + + afterDisplay(gl); + } + + public void afterDisplay(final GL3 gl) { + } + + public void preDisplay(final GL3 gl) { + } + + public void displayParametersANDUniforms(final GL3 gl) { + final int transformationLocation = gl.glGetUniformLocation(this.getShader().getProgramId(), "ModelMatrix"); + if (transformationLocation != -1) { + final float[] mat = new float[16]; + gl.glUniformMatrix4fv(transformationLocation, 1, false, transformation.get(mat), 0); + } + final int cameraLocation = gl.glGetUniformLocation(this.getShader().getProgramId(), "CameraMatrix"); + if (transformationLocation != -1) { + final float[] mat = new float[16]; + gl.glUniformMatrix4fv(cameraLocation, 1, false, getCamera().getMatrix().get(mat), 0); + } + } + + public Camera getCamera() { + return camera; + } + + public Shader getShader() { + return shader; + } + + public final void update() { + stopWatch.stop(); + updateLogic(stopWatch); + stopWatch.reset(); + stopWatch.start(); + } + + public void updateLogic(final StopWatch sWatch) { + + } + +} diff --git a/src/org/kuchelmeister/engine/geometry/OrdinaryGraphicalObject.java b/src/org/kuchelmeister/engine/geometry/OrdinaryGraphicalObject.java new file mode 100644 index 0000000..e519ea1 --- /dev/null +++ b/src/org/kuchelmeister/engine/geometry/OrdinaryGraphicalObject.java @@ -0,0 +1,77 @@ +package org.kuchelmeister.engine.geometry; + +import org.joml.Vector3f; +import org.kuchelmeister.engine.camera.Camera; +import org.kuchelmeister.engine.geometry.texture.Texture; +import org.kuchelmeister.engine.lighting.GlobalLights; +import org.kuchelmeister.engine.lighting.Material; + +import com.jogamp.common.nio.Buffers; +import com.jogamp.opengl.GL3; + +import shader.Shader; + +public abstract class OrdinaryGraphicalObject extends GraphicalObject { + public static final int VERTEX_FLOAT_COUNT = 8; + private final Texture texture; + private final GlobalLights globalLights; + + public GlobalLights getGlobalLights() { + return globalLights; + } + + private Material material; + + public Material getMaterial() { + return material; + } + + public void setMaterial(final Material material) { + this.material = material; + } + + public OrdinaryGraphicalObject(final Camera camera, final String textureFile) { + super(new Shader("object.vs.glsl", "object.fs.glsl"), camera); + this.texture = new Texture(textureFile); + + this.globalLights = GlobalLights.getInstance(); + this.material = Material.getDefault(); + } + + @Override + public void intiVertexAttributes(final GL3 gl) { + gl.glEnable(GL3.GL_DEPTH_TEST); + texture.loadFromFile(gl); + + final int STRIDE = VERTEX_FLOAT_COUNT * Buffers.SIZEOF_FLOAT; + final int posOffset = 0; + final int textureOffset = 3 * Buffers.SIZEOF_FLOAT; + final int normalOffset = 5 * Buffers.SIZEOF_FLOAT; + // position attribute + gl.glVertexAttribPointer(0, 3, GL3.GL_FLOAT, false, STRIDE, posOffset); + gl.glEnableVertexAttribArray(0); + // texture position attribute + gl.glVertexAttribPointer(1, 2, GL3.GL_FLOAT, false, STRIDE, + textureOffset); + gl.glEnableVertexAttribArray(1); + // normal vectors + gl.glVertexAttribPointer(2, 3, GL3.GL_FLOAT, false, STRIDE, + normalOffset); + gl.glEnableVertexAttribArray(2); + + } + + @Override + public void displayParametersANDUniforms(final GL3 gl) { + texture.bind(gl); + super.displayParametersANDUniforms(gl); + final int eyePosLocation = gl.glGetUniformLocation(this.getShader().getProgramId(), "EyePos"); + if (eyePosLocation != -1) { + final Vector3f pos = this.getCamera().getPosition(); + gl.glUniform3fv(eyePosLocation, 1, new float[] {pos.x, pos.y, pos.z}, 0); + } + globalLights.glSetUniforms(gl, this.getShader()); + material.glSetUniforms(gl, this.getShader()); + } + +} diff --git a/src/org/kuchelmeister/engine/geometry/SubGeometry.java b/src/org/kuchelmeister/engine/geometry/SubGeometry.java new file mode 100644 index 0000000..b012c88 --- /dev/null +++ b/src/org/kuchelmeister/engine/geometry/SubGeometry.java @@ -0,0 +1,9 @@ +package org.kuchelmeister.engine.geometry; + +import java.util.List; + +import org.kuchelmeister.engine.geometry.primitive.Triangle; + +public interface SubGeometry { + public List getTriangles(); +} diff --git a/src/org/kuchelmeister/engine/geometry/primitive/Quadrilateral.java b/src/org/kuchelmeister/engine/geometry/primitive/Quadrilateral.java new file mode 100644 index 0000000..21305cf --- /dev/null +++ b/src/org/kuchelmeister/engine/geometry/primitive/Quadrilateral.java @@ -0,0 +1,28 @@ +package org.kuchelmeister.engine.geometry.primitive; + +import java.util.LinkedList; +import java.util.List; + +import org.kuchelmeister.engine.geometry.SubGeometry; +import org.kuchelmeister.engine.geometry.vertex.AbstractVertex; + +public class Quadrilateral implements SubGeometry { + public AbstractVertex a, b, c, d; + + public Quadrilateral(final AbstractVertex a, final AbstractVertex b, final AbstractVertex c, + final AbstractVertex d) { + this.a = a; + this.b = b; + this.c = c; + this.d = d; + } + + @Override + public List getTriangles() { + final List list = new LinkedList<>(); + list.add(new Triangle(a, b, c)); + list.add(new Triangle(c, d, a)); + return list; + } + +} diff --git a/src/org/kuchelmeister/engine/geometry/primitive/Triangle.java b/src/org/kuchelmeister/engine/geometry/primitive/Triangle.java new file mode 100644 index 0000000..71edf73 --- /dev/null +++ b/src/org/kuchelmeister/engine/geometry/primitive/Triangle.java @@ -0,0 +1,54 @@ +package org.kuchelmeister.engine.geometry.primitive; + +import java.util.LinkedList; +import java.util.List; + +import org.apache.commons.lang3.ArrayUtils; +import org.joml.Vector3f; +import org.kuchelmeister.engine.geometry.SubGeometry; +import org.kuchelmeister.engine.geometry.vertex.AbstractVertex; + +public class Triangle implements SubGeometry { + private final AbstractVertex a, b, c; + + /** + * Initialize new Triangle, a, b and c should be positioned + * counterclockwise. + */ + public Triangle(final AbstractVertex a, final AbstractVertex b, final AbstractVertex c) { + this.a = a; + this.b = b; + this.c = c; + } + + public List getPoints() { + final List pList = new LinkedList<>(); + pList.add(getA()); + pList.add(getB()); + pList.add(getC()); + return pList; + } + + public Vector3f getA() { + return a.getPosition(); + } + + public Vector3f getB() { + return b.getPosition(); + } + + public Vector3f getC() { + return c.getPosition(); + } + + public float[] getVertices() { + return ArrayUtils.addAll(ArrayUtils.addAll(a.getFloatArray(), b.getFloatArray()), c.getFloatArray()); + } + + @Override + public List getTriangles() { + final List list = new LinkedList<>(); + list.add(this); + return list; + } +} diff --git a/src/org/kuchelmeister/engine/geometry/skybox/Skybox.java b/src/org/kuchelmeister/engine/geometry/skybox/Skybox.java new file mode 100644 index 0000000..043c6eb --- /dev/null +++ b/src/org/kuchelmeister/engine/geometry/skybox/Skybox.java @@ -0,0 +1,91 @@ +package org.kuchelmeister.engine.geometry.skybox; + +import org.joml.Vector3f; +import org.kuchelmeister.engine.camera.Camera; +import org.kuchelmeister.engine.geometry.GraphicalObject; +import org.kuchelmeister.engine.geometry.primitive.Quadrilateral; +import org.kuchelmeister.engine.geometry.texture.CubemapTexture; +import org.kuchelmeister.engine.geometry.vertex.SkyboxVertex; +import org.kuchelmeister.solarsystem.camera.SkyboxCamera; + +import com.jogamp.common.nio.Buffers; +import com.jogamp.opengl.GL3; + +import shader.Shader; + +public class Skybox extends GraphicalObject { + public static final int VERTEX_FLOAT_COUNT = 6; + private final CubemapTexture cubemap; + + public Skybox(final Camera camera, final float size, final String[] textures) { + super(new Shader("cubemap.vs.glsl", "cubemap.fs.glsl"), camera); + + cubemap = new CubemapTexture(textures); + + final float halfSize = size / 2; + + final SkyboxVertex frontTopLeft = new SkyboxVertex(new Vector3f(-halfSize, halfSize, halfSize)); + final SkyboxVertex frontTopRight = new SkyboxVertex(new Vector3f(halfSize, halfSize, halfSize)); + final SkyboxVertex frontBottomLeft = new SkyboxVertex(new Vector3f(-halfSize, -halfSize, halfSize)); + final SkyboxVertex frontBottomRight = new SkyboxVertex(new Vector3f(halfSize, -halfSize, halfSize)); + + final SkyboxVertex backTopLeft = new SkyboxVertex(new Vector3f(-halfSize, halfSize, -halfSize)); + final SkyboxVertex backTopRight = new SkyboxVertex(new Vector3f(halfSize, halfSize, -halfSize)); + final SkyboxVertex backBottomLeft = new SkyboxVertex(new Vector3f(-halfSize, -halfSize, -halfSize)); + final SkyboxVertex backBottomRight = new SkyboxVertex(new Vector3f(halfSize, -halfSize, -halfSize)); + + // Front + this.subGeometry.add(new Quadrilateral(frontTopLeft, frontTopRight, frontBottomRight, frontBottomLeft)); + // Left + this.subGeometry.add(new Quadrilateral(frontBottomLeft, backBottomLeft, backTopLeft, frontTopLeft)); + // Top + this.subGeometry.add(new Quadrilateral(frontTopLeft, backTopLeft, backTopRight, frontTopRight)); + + // Back + this.subGeometry.add(new Quadrilateral(backBottomRight, backTopRight, backTopLeft, backBottomLeft)); + // Down + this.subGeometry.add(new Quadrilateral(backBottomLeft, frontBottomLeft, frontBottomRight, backBottomRight)); + // Right + this.subGeometry.add(new Quadrilateral(backBottomRight, frontBottomRight, frontTopRight, backTopRight)); + + } + + @Override + public Camera getCamera() { + final Camera skyboxCam = new SkyboxCamera(super.getCamera()); + return skyboxCam; + } + + @Override + public void intiVertexAttributes(final GL3 gl) { + cubemap.loadFromFile(gl); + + final int STRIDE = VERTEX_FLOAT_COUNT * Buffers.SIZEOF_FLOAT; + final int posOffset = 0; + final int textureOffset = 3 * Buffers.SIZEOF_FLOAT; + + // position attribute + gl.glVertexAttribPointer(0, 3, GL3.GL_FLOAT, false, STRIDE, posOffset); + gl.glEnableVertexAttribArray(0); + // texture position attribute + gl.glVertexAttribPointer(1, 3, GL3.GL_FLOAT, false, STRIDE, + textureOffset); + gl.glEnableVertexAttribArray(1); + } + + @Override + public void displayParametersANDUniforms(final GL3 gl) { + cubemap.bind(gl); + super.displayParametersANDUniforms(gl); + } + + @Override + public void afterDisplay(final GL3 gl) { + gl.glEnable(GL3.GL_DEPTH_TEST); + } + + @Override + public void preDisplay(final GL3 gl) { + gl.glDisable(GL3.GL_DEPTH_TEST); + } +} diff --git a/src/org/kuchelmeister/engine/geometry/sphere/Icosahedron.java b/src/org/kuchelmeister/engine/geometry/sphere/Icosahedron.java new file mode 100644 index 0000000..acb6fe4 --- /dev/null +++ b/src/org/kuchelmeister/engine/geometry/sphere/Icosahedron.java @@ -0,0 +1,153 @@ +package org.kuchelmeister.engine.geometry.sphere; + +import org.joml.Vector2f; +import org.joml.Vector3f; +import org.kuchelmeister.engine.camera.Camera; +import org.kuchelmeister.engine.geometry.OrdinaryGraphicalObject; +import org.kuchelmeister.engine.geometry.primitive.Triangle; +import org.kuchelmeister.engine.geometry.vertex.ObjectVertex; + +public class Icosahedron extends OrdinaryGraphicalObject { + private final Vector3f centre; + + public Icosahedron(final Vector3f centre, final float radius, final String texture) { + this(null, centre, radius, texture); + } + + public Icosahedron(final Camera camera, final Vector3f centrePos, final float radius, final String texture) { + super(camera, texture); + this.centre = centrePos; + final float golden = (float) ((1 + Math.sqrt(5d)) / 2); + final Vector3f[] points = new Vector3f[] { + new Vector3f(-1, golden, 0f), + new Vector3f(1, golden, 0f), + new Vector3f(-1, -golden, 0f), + new Vector3f(1, -golden, 0f), + + new Vector3f(0f, -1, golden), + new Vector3f(0f, 1, golden), + new Vector3f(0f, -1, -golden), + new Vector3f(0f, 1, -golden), + + new Vector3f(golden, 0f, -1), + new Vector3f(golden, 0f, 1), + new Vector3f(-golden, 0f, -1), + new Vector3f(-golden, 0f, 1), + }; + final Vector2f[] texturePoints = new Vector2f[points.length]; + final Vector3f[] normals = new Vector3f[points.length]; + + for (int i = 0; i < points.length; i++) { + points[i] = points[i].normalize(radius); + texturePoints[i] = Icosahedron.projectOnTexture(points[i], centre); + normals[i] = points[i]; + points[i] = points[i].add(centre); + } + + // Calculate Normals + + this.subGeometry.add(new Triangle( + new ObjectVertex(points[0], texturePoints[0], normals[0]), + new ObjectVertex(points[11], texturePoints[11], normals[11]), + new ObjectVertex(points[5], texturePoints[5], normals[5]))); + this.subGeometry.add(new Triangle( + new ObjectVertex(points[0], texturePoints[0], normals[0]), + new ObjectVertex(points[5], texturePoints[5], normals[5]), + new ObjectVertex(points[1], texturePoints[1], normals[1]))); + this.subGeometry.add(new Triangle( + new ObjectVertex(points[0], texturePoints[0], normals[0]), + new ObjectVertex(points[1], texturePoints[1], normals[1]), + new ObjectVertex(points[7], texturePoints[7], normals[7]))); + this.subGeometry.add(new Triangle( + new ObjectVertex(points[0], texturePoints[0], normals[0]), + new ObjectVertex(points[7], texturePoints[7], normals[7]), + new ObjectVertex(points[10], texturePoints[10], normals[10]))); + this.subGeometry.add(new Triangle( + new ObjectVertex(points[0], texturePoints[0], normals[0]), + new ObjectVertex(points[10], texturePoints[10], normals[10]), + new ObjectVertex(points[11], texturePoints[11], normals[11]))); + + this.subGeometry.add(new Triangle( + new ObjectVertex(points[1], texturePoints[1], normals[1]), + new ObjectVertex(points[5], texturePoints[5], normals[5]), + new ObjectVertex(points[9], texturePoints[9], normals[9]))); + this.subGeometry.add(new Triangle( + new ObjectVertex(points[5], texturePoints[5], normals[5]), + new ObjectVertex(points[11], texturePoints[11], normals[11]), + new ObjectVertex(points[4], texturePoints[4], normals[6]))); + this.subGeometry.add(new Triangle( + new ObjectVertex(points[11], texturePoints[11], normals[11]), + new ObjectVertex(points[10], texturePoints[10], normals[10]), + new ObjectVertex(points[2], texturePoints[2], normals[2]))); + this.subGeometry.add(new Triangle( + new ObjectVertex(points[10], texturePoints[10], normals[10]), + new ObjectVertex(points[7], texturePoints[7], normals[7]), + new ObjectVertex(points[6], texturePoints[6], normals[6]))); + this.subGeometry.add(new Triangle( + new ObjectVertex(points[7], texturePoints[7], normals[7]), + new ObjectVertex(points[1], texturePoints[1], normals[1]), + new ObjectVertex(points[8], texturePoints[8], normals[8]))); + + this.subGeometry.add(new Triangle( + new ObjectVertex(points[3], texturePoints[3], normals[3]), + new ObjectVertex(points[9], texturePoints[9], normals[9]), + new ObjectVertex(points[4], texturePoints[4], normals[4]))); + this.subGeometry.add(new Triangle( + new ObjectVertex(points[3], texturePoints[3], normals[3]), + new ObjectVertex(points[4], texturePoints[4], normals[4]), + new ObjectVertex(points[2], texturePoints[2], normals[2]))); + this.subGeometry.add(new Triangle( + new ObjectVertex(points[3], texturePoints[3], normals[3]), + new ObjectVertex(points[2], texturePoints[2], normals[2]), + new ObjectVertex(points[6], texturePoints[6], normals[6]))); + this.subGeometry.add(new Triangle( + new ObjectVertex(points[3], texturePoints[3], normals[3]), + new ObjectVertex(points[6], texturePoints[6], normals[6]), + new ObjectVertex(points[8], texturePoints[8], normals[8]))); + this.subGeometry.add(new Triangle( + new ObjectVertex(points[3], texturePoints[3], normals[3]), + new ObjectVertex(points[8], texturePoints[8], normals[8]), + new ObjectVertex(points[9], texturePoints[9], normals[9]))); + + this.subGeometry.add(new Triangle( + new ObjectVertex(points[4], texturePoints[4], normals[4]), + new ObjectVertex(points[9], texturePoints[9], normals[9]), + new ObjectVertex(points[5], texturePoints[5], normals[5]))); + this.subGeometry.add(new Triangle( + new ObjectVertex(points[2], texturePoints[2], normals[2]), + new ObjectVertex(points[4], texturePoints[4], normals[4]), + new ObjectVertex(points[11], texturePoints[11], normals[11]))); + this.subGeometry.add(new Triangle( + new ObjectVertex(points[6], texturePoints[6], normals[6]), + new ObjectVertex(points[2], texturePoints[2], normals[2]), + new ObjectVertex(points[10], texturePoints[10], normals[10]))); + this.subGeometry.add(new Triangle( + new ObjectVertex(points[8], texturePoints[8], normals[8]), + new ObjectVertex(points[6], texturePoints[6], normals[6]), + new ObjectVertex(points[7], texturePoints[7], normals[7]))); + this.subGeometry.add(new Triangle( + new ObjectVertex(points[9], texturePoints[9], normals[9]), + new ObjectVertex(points[8], texturePoints[8], normals[8]), + new ObjectVertex(points[1], texturePoints[1], normals[1]))); + } + + public static Vector2f projectOnTexture(final Vector3f point, final Vector3f centre) { + // https://stackoverflow.com/questions/5674149/3d-coordinates-on-a-sphere-to-latitude-and-longitude#5674243 + final double x = point.x - centre.x; + final double y = point.y - centre.y; + final double z = point.z - centre.z; + + final double r = Math.sqrt(x * x + y * y + z * z); + + final double theta = Math.acos(y / r); + final double phi = Math.atan(x / z); + + final float lon = (float) ((180.0d - Math.toDegrees(phi)) / 360.0d); + final float lat = (float) ((180.0d - Math.toDegrees(theta)) / 180.0d); + + // System.out.println("(" + x + ", " + y + ", " + z + ") => (" + lon + + // ", " + lat + ")"); + return new Vector2f(lon, lat); + } + +} diff --git a/src/org/kuchelmeister/engine/geometry/sphere/Sphere.java b/src/org/kuchelmeister/engine/geometry/sphere/Sphere.java new file mode 100644 index 0000000..efa0df6 --- /dev/null +++ b/src/org/kuchelmeister/engine/geometry/sphere/Sphere.java @@ -0,0 +1,76 @@ +package org.kuchelmeister.engine.geometry.sphere; + +import java.util.LinkedList; + +import org.joml.Vector3f; +import org.kuchelmeister.engine.geometry.primitive.Triangle; +import org.kuchelmeister.engine.geometry.vertex.ObjectVertex; + +public class Sphere extends Icosahedron { + public Sphere(final Vector3f centre, final float radius, final String texture, final int recursionLevel) { + super(centre, radius, texture); + + this.faces.clear(); + for (int j = 0; j < recursionLevel; j++) { + final LinkedList tmpList = new LinkedList<>(); + for (int i = this.subGeometry.size() - 1; i >= 0; i--) { + final Triangle t = (Triangle) this.subGeometry.get(i); + final Vector3f a = t.getA(); + final Vector3f b = t.getB(); + final Vector3f c = t.getC(); + + Vector3f o = Sphere.findMiddle(a, b); + Vector3f p = Sphere.findMiddle(b, c); + Vector3f q = Sphere.findMiddle(c, a); + + o = Sphere.setDistanceFromPoint(o, radius, centre); + p = Sphere.setDistanceFromPoint(p, radius, centre); + q = Sphere.setDistanceFromPoint(q, radius, centre); + + tmpList.add(new Triangle( + new ObjectVertex(a, Icosahedron.projectOnTexture(a, centre), a), + new ObjectVertex(o, Icosahedron.projectOnTexture(o, centre), o), + new ObjectVertex(q, Icosahedron.projectOnTexture(q, centre), q))); + tmpList.add(new Triangle( + new ObjectVertex(o, Icosahedron.projectOnTexture(o, centre), o), + new ObjectVertex(b, Icosahedron.projectOnTexture(b, centre), b), + new ObjectVertex(p, Icosahedron.projectOnTexture(p, centre), p))); + tmpList.add(new Triangle( + new ObjectVertex(p, Icosahedron.projectOnTexture(p, centre), p), + new ObjectVertex(c, Icosahedron.projectOnTexture(c, centre), c), + new ObjectVertex(q, Icosahedron.projectOnTexture(q, centre), q))); + tmpList.add(new Triangle( + new ObjectVertex(o, Icosahedron.projectOnTexture(o, centre), o), + new ObjectVertex(p, Icosahedron.projectOnTexture(p, centre), p), + new ObjectVertex(q, Icosahedron.projectOnTexture(q, centre), q))); + } + this.subGeometry.clear(); + this.subGeometry.addAll(tmpList); + + // System.out.println(this.subGeometry.size()); + } + } + + public static Vector3f findMiddle(final Vector3f a, final Vector3f b) { + // Total calculation a + 0.5*(b - a) + final Vector3f negA = (new Vector3f(a)).negate(); + Vector3f tmp = new Vector3f(b); + // b - a + tmp = tmp.add(negA); + // 0.5 * (b-a) + tmp = tmp.mul(0.5f); + // a + 0.5 * (b-a) + tmp = tmp.add(a); + return tmp; + } + + public static Vector3f setDistanceFromPoint(final Vector3f a, final float distance, final Vector3f point) { + Vector3f direction = new Vector3f(a); + final Vector3f negPoint = (new Vector3f(point)).negate(); + + direction = direction.add(negPoint); + direction.mul(distance / direction.length()); + + return direction.add(point); + } +} diff --git a/src/org/kuchelmeister/engine/geometry/texture/CubemapTexture.java b/src/org/kuchelmeister/engine/geometry/texture/CubemapTexture.java new file mode 100644 index 0000000..1d384cb --- /dev/null +++ b/src/org/kuchelmeister/engine/geometry/texture/CubemapTexture.java @@ -0,0 +1,59 @@ +package org.kuchelmeister.engine.geometry.texture; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.IntBuffer; + +import com.jogamp.opengl.GL3; +import com.jogamp.opengl.GLException; +import com.jogamp.opengl.util.texture.TextureData; +import com.jogamp.opengl.util.texture.TextureIO; + +public class CubemapTexture implements ITexture { + private IntBuffer textureID; + private final String[] textures; + + /** + * + * @param textures + * path to the textures (Order: right, left, top, bottom, back, + * front) + */ + public CubemapTexture(final String[] textures) { + assert (textures != null && textures.length == 6); + this.textures = textures; + } + + public void bind(final GL3 gl) { + gl.glBindTexture(GL3.GL_TEXTURE_CUBE_MAP, textureID.get(0)); + } + + public boolean loadFromFile(final GL3 gl) { + + textureID = IntBuffer.allocate(1); + gl.glGenTextures(1, textureID); + gl.glBindTexture(GL3.GL_TEXTURE_CUBE_MAP, textureID.get(0)); + + for (int i = 0; i < textures.length; i++) { + try { + final InputStream stream = new FileInputStream(new File(ITexture.TEXTURE_FOLDER + textures[i])); + final TextureData data = TextureIO.newTextureData(gl.getGLProfile(), stream, false, "jpg"); + gl.glTexImage2D(GL3.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL3.GL_RGB, data.getWidth(), + data.getHeight(), 0, GL3.GL_RGB, GL3.GL_UNSIGNED_BYTE, data.getBuffer()); + + } catch (GLException | IOException e) { + System.out.println("Failed to load Texture: " + textures[i]); + } + } + + gl.glTexParameteri(GL3.GL_TEXTURE_CUBE_MAP, GL3.GL_TEXTURE_MIN_FILTER, GL3.GL_LINEAR); + gl.glTexParameteri(GL3.GL_TEXTURE_CUBE_MAP, GL3.GL_TEXTURE_MAG_FILTER, GL3.GL_LINEAR); + gl.glTexParameteri(GL3.GL_TEXTURE_CUBE_MAP, GL3.GL_TEXTURE_WRAP_S, GL3.GL_CLAMP_TO_EDGE); + gl.glTexParameteri(GL3.GL_TEXTURE_CUBE_MAP, GL3.GL_TEXTURE_WRAP_T, GL3.GL_CLAMP_TO_EDGE); + gl.glTexParameteri(GL3.GL_TEXTURE_CUBE_MAP, GL3.GL_TEXTURE_WRAP_R, GL3.GL_CLAMP_TO_EDGE); + + return true; + } +} diff --git a/src/org/kuchelmeister/engine/geometry/texture/ITexture.java b/src/org/kuchelmeister/engine/geometry/texture/ITexture.java new file mode 100644 index 0000000..5ea1475 --- /dev/null +++ b/src/org/kuchelmeister/engine/geometry/texture/ITexture.java @@ -0,0 +1,11 @@ +package org.kuchelmeister.engine.geometry.texture; + +import com.jogamp.opengl.GL3; + +public interface ITexture { + public static final String TEXTURE_FOLDER = "textures/"; + + public void bind(GL3 gl); + + public boolean loadFromFile(GL3 gl); +} diff --git a/src/org/kuchelmeister/engine/geometry/texture/Texture.java b/src/org/kuchelmeister/engine/geometry/texture/Texture.java new file mode 100644 index 0000000..786d312 --- /dev/null +++ b/src/org/kuchelmeister/engine/geometry/texture/Texture.java @@ -0,0 +1,43 @@ +package org.kuchelmeister.engine.geometry.texture; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +import com.jogamp.opengl.GL3; +import com.jogamp.opengl.GLException; +import com.jogamp.opengl.util.texture.TextureData; +import com.jogamp.opengl.util.texture.TextureIO; + +public class Texture implements ITexture { + private final String texturePath; + private com.jogamp.opengl.util.texture.Texture texture; + + public Texture(final String texture) { + this.texturePath = ITexture.TEXTURE_FOLDER + texture; + } + + @Override + public void bind(final GL3 gl) { + // TODO Auto-generated method stub + texture.enable(gl); + texture.bind(gl); + } + + @Override + public boolean loadFromFile(final GL3 gl) { + try { + final InputStream stream = new FileInputStream(new File(texturePath)); + final TextureData data = TextureIO.newTextureData(gl.getGLProfile(), stream, false, "jpg"); + texture = TextureIO.newTexture(data); + gl.glTexParameteri(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_WRAP_S, GL3.GL_REPEAT); + gl.glTexParameteri(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_WRAP_T, GL3.GL_REPEAT); + return true; + } catch (GLException | IOException e) { + System.out.println("Failed to load Texture: " + texturePath); + return false; + } + } + +} diff --git a/src/org/kuchelmeister/engine/geometry/vertex/AbstractVertex.java b/src/org/kuchelmeister/engine/geometry/vertex/AbstractVertex.java new file mode 100644 index 0000000..cb0f42f --- /dev/null +++ b/src/org/kuchelmeister/engine/geometry/vertex/AbstractVertex.java @@ -0,0 +1,25 @@ +package org.kuchelmeister.engine.geometry.vertex; + +import org.joml.Vector3f; + +public abstract class AbstractVertex implements VertexInterface { + private final Vector3f position; + + public AbstractVertex(final Vector3f position) { + this.position = position; + } + + @Override + public float[] getFloatArray() { + final float[] fl = new float[3]; + fl[0] = position.x; + fl[1] = position.y; + fl[2] = position.z; + return fl; + } + + public Vector3f getPosition() { + return position; + } + +} diff --git a/src/org/kuchelmeister/engine/geometry/vertex/ObjectVertex.java b/src/org/kuchelmeister/engine/geometry/vertex/ObjectVertex.java new file mode 100644 index 0000000..c3d82fa --- /dev/null +++ b/src/org/kuchelmeister/engine/geometry/vertex/ObjectVertex.java @@ -0,0 +1,28 @@ +package org.kuchelmeister.engine.geometry.vertex; + +import org.apache.commons.lang3.ArrayUtils; +import org.joml.Vector2f; +import org.joml.Vector3f; + +public class ObjectVertex extends AbstractVertex { + private final Vector2f texture; + private final Vector3f normal; + + public ObjectVertex(final Vector3f position, final Vector2f texture, final Vector3f normal) { + super(position); + this.texture = texture; + this.normal = normal; + } + + @Override + public float[] getFloatArray() { + final float[] arr = new float[5]; + arr[0] = texture.x; + arr[1] = texture.y; + arr[2] = normal.x; + arr[3] = normal.y; + arr[4] = normal.z; + return ArrayUtils.addAll(super.getFloatArray(), arr); + } + +} diff --git a/src/org/kuchelmeister/engine/geometry/vertex/SkyboxVertex.java b/src/org/kuchelmeister/engine/geometry/vertex/SkyboxVertex.java new file mode 100644 index 0000000..7fe4d1e --- /dev/null +++ b/src/org/kuchelmeister/engine/geometry/vertex/SkyboxVertex.java @@ -0,0 +1,27 @@ +package org.kuchelmeister.engine.geometry.vertex; + +import org.apache.commons.lang3.ArrayUtils; +import org.joml.Vector3f; + +public class SkyboxVertex extends AbstractVertex { + Vector3f texture; + + public SkyboxVertex(final Vector3f position, final Vector3f texture) { + super(position); + this.texture = texture; + } + + public SkyboxVertex(final Vector3f position) { + this(position, position); + } + + @Override + public float[] getFloatArray() { + final float[] arr = new float[3]; + arr[0] = texture.x; + arr[1] = texture.y; + arr[2] = texture.z; + return ArrayUtils.addAll(super.getFloatArray(), arr); + } + +} diff --git a/src/org/kuchelmeister/engine/geometry/vertex/VertexInterface.java b/src/org/kuchelmeister/engine/geometry/vertex/VertexInterface.java new file mode 100644 index 0000000..62107dc --- /dev/null +++ b/src/org/kuchelmeister/engine/geometry/vertex/VertexInterface.java @@ -0,0 +1,5 @@ +package org.kuchelmeister.engine.geometry.vertex; + +public interface VertexInterface { + public float[] getFloatArray(); +} diff --git a/src/org/kuchelmeister/engine/input/CameraKeyListener.java b/src/org/kuchelmeister/engine/input/CameraKeyListener.java new file mode 100644 index 0000000..0bbdf33 --- /dev/null +++ b/src/org/kuchelmeister/engine/input/CameraKeyListener.java @@ -0,0 +1,70 @@ +package org.kuchelmeister.engine.input; + +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; + +import org.kuchelmeister.engine.camera.Camera; + +public class CameraKeyListener implements KeyListener { + Camera camera; + + public CameraKeyListener(final Camera camera) { + this.camera = camera; + } + + @Override + public void keyPressed(final KeyEvent e) { + final float stepsPosition = 0.1f; + final float stepsRotation = 10.0f; + System.out.println("Key Pressed: " + e.getKeyChar() + " | " + e.getKeyCode()); + if (e.getKeyCode() == KeyEvent.VK_DOWN) { + // Rotate up + camera.offsetOrientation(stepsRotation, 0.0f); + } else if (e.getKeyCode() == KeyEvent.VK_UP) { + // Rotate down + camera.offsetOrientation(-stepsRotation, 0.0f); + } + + if (e.getKeyCode() == KeyEvent.VK_RIGHT) { + // Rotate left + camera.offsetOrientation(0.0f, stepsRotation); + } else if (e.getKeyCode() == KeyEvent.VK_LEFT) { + // Rotate right + camera.offsetOrientation(0.0f, -stepsRotation); + } + + if (e.getKeyCode() == KeyEvent.VK_A) { + // GO Left + camera.offsetPosition(camera.rightVec().mul(-stepsPosition)); + } else if (e.getKeyCode() == KeyEvent.VK_D) { + // Go Right + camera.offsetPosition(camera.rightVec().mul(stepsPosition)); + ; + + } + if (e.getKeyCode() == KeyEvent.VK_W) { + // GO Forward + camera.offsetPosition(camera.forwardVec().mul(stepsPosition)); + } else if (e.getKeyCode() == KeyEvent.VK_S) { + // Go Backward + camera.offsetPosition(camera.forwardVec().mul(-stepsPosition)); + } + if (e.getKeyCode() == KeyEvent.VK_E) { + // GO UP + camera.offsetPosition(camera.upVec().mul(stepsPosition)); + } else if (e.getKeyCode() == KeyEvent.VK_Q) { + // Go Down + camera.offsetPosition(camera.upVec().mul(-stepsPosition)); + } + } + + @Override + public void keyReleased(final KeyEvent e) { + } + + @Override + public void keyTyped(final KeyEvent e) { + + } + +} diff --git a/src/org/kuchelmeister/engine/lighting/GlobalLights.java b/src/org/kuchelmeister/engine/lighting/GlobalLights.java new file mode 100644 index 0000000..102aeb7 --- /dev/null +++ b/src/org/kuchelmeister/engine/lighting/GlobalLights.java @@ -0,0 +1,56 @@ +package org.kuchelmeister.engine.lighting; + +import java.util.LinkedList; +import java.util.List; + +import com.jogamp.opengl.GL3; + +import shader.Shader; + +public class GlobalLights { + private static GlobalLights globalLights; + + public static GlobalLights getInstance() { + if (globalLights == null) { + globalLights = new GlobalLights(); + } + return globalLights; + } + + public static int MAX_LIGHTS = 10; + List lights; + + public GlobalLights() { + lights = new LinkedList<>(); + } + + public void add(final Light light) { + if (lights.size() < MAX_LIGHTS) { + lights.add(light); + } + } + + public void glSetUniforms(final GL3 gl, final Shader shader) { + for (int i = 0; i < MAX_LIGHTS; i++) { + final int lightPositionLocation = gl.glGetUniformLocation(shader.getProgramId(), + "lights[" + i + "].position"); + final int lightEnabledLocation = gl.glGetUniformLocation(shader.getProgramId(), + "lights[" + i + "].enabled"); + + if (lights.size() > i) { + if (lightPositionLocation != -1) { + gl.glUniform3f(lightPositionLocation, lights.get(i).position.x, lights.get(i).position.y, + lights.get(i).position.z); + } + if (lightEnabledLocation != -1) { + gl.glUniform1i(lightEnabledLocation, 1); + } + } else { + if (lightEnabledLocation != -1) { + gl.glUniform1i(lightEnabledLocation, 0); + } + } + } + + } +} diff --git a/src/org/kuchelmeister/engine/lighting/Light.java b/src/org/kuchelmeister/engine/lighting/Light.java new file mode 100644 index 0000000..964cbab --- /dev/null +++ b/src/org/kuchelmeister/engine/lighting/Light.java @@ -0,0 +1,11 @@ +package org.kuchelmeister.engine.lighting; + +import org.joml.Vector3f; + +public class Light { + Vector3f position; + + public Light(final Vector3f position) { + this.position = position; + } +} diff --git a/src/org/kuchelmeister/engine/lighting/Material.java b/src/org/kuchelmeister/engine/lighting/Material.java new file mode 100644 index 0000000..3e8504f --- /dev/null +++ b/src/org/kuchelmeister/engine/lighting/Material.java @@ -0,0 +1,52 @@ +package org.kuchelmeister.engine.lighting; + +import org.joml.Vector3f; + +import com.jogamp.opengl.GL3; + +import shader.Shader; + +public class Material { + Vector3f ambient, diffuse, specular; + int shininess; + + public Material(final float ambient, final float diffuse, final float specular) { + this(new Vector3f(ambient, ambient, ambient), + new Vector3f(diffuse, diffuse, diffuse), + new Vector3f(specular, specular, specular), + 2); + } + + public Material(final Vector3f ambient, final Vector3f diffuse, final Vector3f specular, final int shininess) { + this.ambient = ambient; + this.diffuse = diffuse; + this.specular = specular; + this.shininess = shininess; + } + + public static Material getDefault() { + final float ambient = 0.4f; + final float diffuse = 1.0f; + final float specular = 0.5f; + return new Material(ambient, diffuse, specular); + } + + public void glSetUniforms(final GL3 gl, final Shader shader) { + final int materialAmbientPos = gl.glGetUniformLocation(shader.getProgramId(), "material.ambient"); + if (materialAmbientPos != -1) { + gl.glUniform3f(materialAmbientPos, ambient.x, ambient.y, ambient.z); + } + final int materialDiffuseLocation = gl.glGetUniformLocation(shader.getProgramId(), "material.diffuse"); + if (materialDiffuseLocation != -1) { + gl.glUniform3f(materialDiffuseLocation, diffuse.x, diffuse.y, diffuse.z); + } + final int materialSpecularLocation = gl.glGetUniformLocation(shader.getProgramId(), "material.specular"); + if (materialSpecularLocation != -1) { + gl.glUniform3f(materialSpecularLocation, specular.x, specular.y, specular.z); + } + final int materialShininessLocation = gl.glGetUniformLocation(shader.getProgramId(), "material.shininess"); + if (materialShininessLocation != -1) { + gl.glUniform1i(materialShininessLocation, shininess); + } + } +} diff --git a/src/org/kuchelmeister/engine/solarsystem/Main.java b/src/org/kuchelmeister/engine/solarsystem/Main.java new file mode 100644 index 0000000..14dd526 --- /dev/null +++ b/src/org/kuchelmeister/engine/solarsystem/Main.java @@ -0,0 +1,15 @@ +package org.kuchelmeister.engine.solarsystem; + +import org.kuchelmeister.engine.Scene; + +public class Main { + + public static void main(final String[] args) { + Scene myScene; + + myScene = new SolarSystemScene(800, 600, "Solar System Visualisation by Hannes Kuchelmeister!"); + myScene.run(); + + } + +} \ No newline at end of file diff --git a/src/org/kuchelmeister/engine/solarsystem/SolarSystemScene.java b/src/org/kuchelmeister/engine/solarsystem/SolarSystemScene.java new file mode 100644 index 0000000..057bc27 --- /dev/null +++ b/src/org/kuchelmeister/engine/solarsystem/SolarSystemScene.java @@ -0,0 +1,120 @@ +package org.kuchelmeister.engine.solarsystem; + +import org.joml.Vector3f; +import org.kuchelmeister.engine.Scene; +import org.kuchelmeister.solarsystem.geometry.Moon; +import org.kuchelmeister.solarsystem.geometry.Orbit; +import org.kuchelmeister.solarsystem.geometry.Planet; +import org.kuchelmeister.solarsystem.geometry.Sun; +import org.kuchelmeister.solarsystem.geometry.Universe; +import org.kuchelmeister.solarsystem.input.UniverseKeyListener; + +public class SolarSystemScene extends Scene { + + public SolarSystemScene(final int width, final int height, final String title) { + super(width, height, title); + camera.setPosition(new Vector3f(0.0f, 8.0f, 0.0f)); + camera.lookAt(new Vector3f(0.0f, 0.0f, 0.0f)); + final Universe uv = new Universe(); + + this.getCanvas().addKeyListener(new UniverseKeyListener(uv)); + // Mercury + this.addGraphicalObject(new Planet( + new Orbit(new Vector3f(0.0f, 0.0f, 0.0f), + 0.467f, + 0.308f), + uv, + 0.38f, + "spheres/mercury.jpg", 115.88f, 57.94f)); + // Venus + this.addGraphicalObject(new Planet( + new Orbit(new Vector3f(0.0f, 0.0f, 0.0f), + 0.723f, + 0.718f), + uv, + 0.38f, + "spheres/venus.jpg", 224.701f, 243.0f)); + + // Earth + final Planet earth = new Planet( + new Orbit(new Vector3f(0.0f, 0.0f, 0.0f), + 0.98f, + 1.02f), + uv, + 1.0f, + "spheres/earth.jpg", 365.256f, 1.0f); + this.addGraphicalObject(earth); + // Moon + this.addGraphicalObject(new Moon( + earth, + new Orbit(new Vector3f(0.0f, 0.0f, 0.0f), + 2 * Universe.EARTH_RADIUS, + 2 * Universe.EARTH_RADIUS), + uv, + 0.3f, + "spheres/moon.jpg", + 29.530589f, + 29.530589f)); + // Mars + this.addGraphicalObject(new Planet( + new Orbit(new Vector3f(0.0f, 0.0f, 0.0f), + 1.5f, + 1.4f), + uv, + 0.2657f * 2, + "spheres/mars.jpg", + 686.971f, + 1.0275f)); + + // Jupiter + this.addGraphicalObject(new Planet( + new Orbit(new Vector3f(0.0f, 0.0f, 0.0f), + 5.2f - 3.3f, + 4.9f - 3.3f), + uv, + 12.0f / 12f, + "spheres/jupiter.jpg", + 4330.0f, + 0.4132f)); + // Saturn + this.addGraphicalObject(new Planet( + new Orbit(new Vector3f(0.0f, 0.0f, 0.0f), + 9.5f - 7f, + 9f - 7f), + uv, + 10.0f / 10f, + "spheres/saturn.jpg", + 10751.805f, + 0.45f)); + // Uranus + this.addGraphicalObject(new Planet( + new Orbit(new Vector3f(0.0f, 0.0f, 0.0f), + 19f - 16f, + 18f - 16f), + uv, + 4.0f / 6, + "spheres/uranus.jpg", + 30660.0f, + 0.72f)); + // Neptun + this.addGraphicalObject(new Planet( + new Orbit(new Vector3f(0.0f, 0.0f, 0.0f), + 30f - 26.0f, + 29f - 26.0f), + uv, + 3.88f / 6, + "spheres/neptune.jpg", + 30660.0f, + 0.673f)); + this.addGraphicalObject(new Sun(new Vector3f(0.0f, 0.0f, 0.0f), 3.0f, "spheres/sun.jpg")); + + this.setSkybox(new String[] { + "skybox/space_left_0.png", + "skybox/space_right_1.png", + "skybox/space_down_2.png", + "skybox/space_up_3.png", + "skybox/space_front_4.png", + "skybox/space_back_5.png"}); + } + +} diff --git a/src/org/kuchelmeister/solarsystem/camera/SkyboxCamera.java b/src/org/kuchelmeister/solarsystem/camera/SkyboxCamera.java new file mode 100644 index 0000000..c9f5763 --- /dev/null +++ b/src/org/kuchelmeister/solarsystem/camera/SkyboxCamera.java @@ -0,0 +1,16 @@ +package org.kuchelmeister.solarsystem.camera; + +import org.joml.Vector3f; +import org.kuchelmeister.engine.camera.Camera; + +public class SkyboxCamera extends Camera { + public SkyboxCamera(final Camera camera) { + super(camera); + } + + @Override + public Vector3f getPosition() { + return new Vector3f(0.0f, 0.0f, 0.0f); + } + +} diff --git a/src/org/kuchelmeister/solarsystem/geometry/Moon.java b/src/org/kuchelmeister/solarsystem/geometry/Moon.java new file mode 100644 index 0000000..012e045 --- /dev/null +++ b/src/org/kuchelmeister/solarsystem/geometry/Moon.java @@ -0,0 +1,21 @@ +package org.kuchelmeister.solarsystem.geometry; + +import org.apache.commons.lang3.time.StopWatch; + +public class Moon extends Planet { + Planet homePlanet; + + public Moon(final Planet homePlanter, final Orbit orb, final Universe universe, final float radius, + final String texture, final float yearLength, final float dayLength) { + super(orb, universe, radius, texture, yearLength, dayLength); + this.homePlanet = homePlanter; + } + + @Override + public void updateLogic(final StopWatch sWatch) { + super.orbit.setCentre(homePlanet.getCentre()); + ; + super.updateLogic(sWatch); + } + +} diff --git a/src/org/kuchelmeister/solarsystem/geometry/Orbit.java b/src/org/kuchelmeister/solarsystem/geometry/Orbit.java new file mode 100644 index 0000000..fd531e1 --- /dev/null +++ b/src/org/kuchelmeister/solarsystem/geometry/Orbit.java @@ -0,0 +1,30 @@ +package org.kuchelmeister.solarsystem.geometry; + +import org.joml.Vector3f; + +public class Orbit { + private final float width, height; + private Vector3f centre; + + public Orbit(final Vector3f centre, final float width, final float height) { + this.height = height; + this.width = width; + this.centre = new Vector3f(centre); + + } + + public Vector3f getPoint(final float angle) { + return new Vector3f( + (float) (width * Math.cos(Math.toRadians(angle)) + centre.x), + centre.y, + (float) (height * Math.sin(Math.toRadians(angle)) + centre.z)); + } + + public void setCentre(final Vector3f centre) { + this.centre = centre; + } + + public Vector3f getCentre() { + return centre; + } +} diff --git a/src/org/kuchelmeister/solarsystem/geometry/Planet.java b/src/org/kuchelmeister/solarsystem/geometry/Planet.java new file mode 100644 index 0000000..ffcf7ac --- /dev/null +++ b/src/org/kuchelmeister/solarsystem/geometry/Planet.java @@ -0,0 +1,54 @@ +package org.kuchelmeister.solarsystem.geometry; + +import org.apache.commons.lang3.time.StopWatch; +import org.joml.Vector3f; + +public class Planet extends SphericalSpaceObject { + /** The length of a year on this planet in hours */ + private final float yearLength; + private final float dayLength; + private final Universe universe; + private float orbitDegrees; + private float dayAxisDegrees; + protected final Orbit orbit; + + public Planet(final Orbit orb, final Universe universe, final float radius, final String texture, + final float yearLength, final float dayLength) { + super(orb.getCentre(), radius, texture); + this.universe = universe; + this.yearLength = yearLength; + this.orbitDegrees = 0; + this.orbit = orb; + dayAxisDegrees = 0f; + this.dayLength = dayLength * Universe.EART_DAY_LENGTH; + } + + public Vector3f getCentre() { + return orbit.getPoint(orbitDegrees); + } + + @Override + public void updateLogic(final StopWatch sWatch) { + final double elapsedDays = sWatch.getTime() / 1000.0d * universe.getTimeScale(); + + final float dayOrbitRoatation = 360.0f / yearLength; + orbitDegrees += (float) (dayOrbitRoatation * elapsedDays); + + if (orbitDegrees >= 360.0f) { + orbitDegrees %= 360.0f; + } + // System.out.println("Position of Planet: " + + // orbit.getPoint(orbitDegrees)); + + // TODO: implement rotattion axis + final float dayAxisRotation = 360f / dayLength; + dayAxisDegrees += (float) (elapsedDays * dayAxisRotation); + this.setRotation(0.0f, dayAxisDegrees, 0.0f); + if (dayAxisDegrees >= 360.0f) { + dayAxisDegrees %= 360.0f; + } + + this.setPosition(orbit.getPoint(orbitDegrees)); + } + +} diff --git a/src/org/kuchelmeister/solarsystem/geometry/SphericalSpaceObject.java b/src/org/kuchelmeister/solarsystem/geometry/SphericalSpaceObject.java new file mode 100644 index 0000000..2506a3d --- /dev/null +++ b/src/org/kuchelmeister/solarsystem/geometry/SphericalSpaceObject.java @@ -0,0 +1,11 @@ +package org.kuchelmeister.solarsystem.geometry; + +import org.joml.Vector3f; +import org.kuchelmeister.engine.geometry.sphere.Sphere; + +public abstract class SphericalSpaceObject extends Sphere { + public SphericalSpaceObject(final Vector3f centre, final float radius, final String texture) { + super(centre, radius * Universe.EARTH_RADIUS, texture, 3); + + } +} diff --git a/src/org/kuchelmeister/solarsystem/geometry/Sun.java b/src/org/kuchelmeister/solarsystem/geometry/Sun.java new file mode 100644 index 0000000..0b20516 --- /dev/null +++ b/src/org/kuchelmeister/solarsystem/geometry/Sun.java @@ -0,0 +1,13 @@ +package org.kuchelmeister.solarsystem.geometry; + +import org.joml.Vector3f; +import org.kuchelmeister.engine.lighting.Light; +import org.kuchelmeister.engine.lighting.Material; + +public class Sun extends SphericalSpaceObject { + public Sun(final Vector3f centre, final float radius, final String texture) { + super(centre, radius, texture); + this.setMaterial(new Material(1.0f, 1.0f, 0.0f)); + this.getGlobalLights().add(new Light(centre)); + } +} diff --git a/src/org/kuchelmeister/solarsystem/geometry/Universe.java b/src/org/kuchelmeister/solarsystem/geometry/Universe.java new file mode 100644 index 0000000..391d432 --- /dev/null +++ b/src/org/kuchelmeister/solarsystem/geometry/Universe.java @@ -0,0 +1,48 @@ +package org.kuchelmeister.solarsystem.geometry; + +public class Universe { + /** + * radius of the earth in AU + */ + public static float EARTH_RADIUS = 0.09f; + public static float EART_DAY_LENGTH = 1.0f; + + /** + * The timescale multiplyer 1 means one second is one day + */ + private float timeScale; + private boolean paused; + + public Universe() { + timeScale = 80.0f; + paused = false; + } + + public float getTimeScale() { + if (paused) { + return 0.0f; + } + return timeScale; + } + + public void tooglePause() { + paused = !paused; + } + + public void doubleTimeScale() { + timeScale *= 2; + } + + public void halfTimeScale() { + timeScale /= 2; + } + + public boolean isPaused() { + return paused; + } + + public void reverseTime() { + timeScale = -timeScale; + } + +} diff --git a/src/org/kuchelmeister/solarsystem/input/UniverseKeyListener.java b/src/org/kuchelmeister/solarsystem/input/UniverseKeyListener.java new file mode 100644 index 0000000..1818db2 --- /dev/null +++ b/src/org/kuchelmeister/solarsystem/input/UniverseKeyListener.java @@ -0,0 +1,50 @@ +package org.kuchelmeister.solarsystem.input; + +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; + +import org.kuchelmeister.solarsystem.geometry.Universe; + +public class UniverseKeyListener implements KeyListener { + Universe universe; + + public UniverseKeyListener(final Universe universe) { + this.universe = universe; + } + + @Override + public void keyPressed(final KeyEvent e) { + final float stepsPosition = 0.1f; + final float stepsRotation = 10.0f; + if (!universe.isPaused()) { + if (e.getKeyCode() == KeyEvent.VK_PLUS) { + // Faster time scale + universe.doubleTimeScale(); + System.out.println("Time Scale Doubled to: " + universe.getTimeScale()); + } else if (e.getKeyCode() == KeyEvent.VK_MINUS) { + // Slower timescale + universe.halfTimeScale(); + System.out.println("Time scale halfed to: " + universe.getTimeScale()); + } else if (e.getKeyCode() == KeyEvent.VK_R) { + // Reverse timescale + universe.reverseTime(); + System.out.println("Time scale halfed to: " + universe.getTimeScale()); + } + } + } + + @Override + public void keyReleased(final KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_SPACE) { + // Pause + universe.tooglePause(); + System.out.println("Toggledpause:" + universe.getTimeScale()); + } + } + + @Override + public void keyTyped(final KeyEvent e) { + + } + +} diff --git a/src/shader/Shader.java b/src/shader/Shader.java new file mode 100644 index 0000000..d6cfb4f --- /dev/null +++ b/src/shader/Shader.java @@ -0,0 +1,32 @@ +package shader; + +import com.jogamp.opengl.GL3; + +import tools.ShaderHelper; + +public class Shader { + public static final String SHADER_FOLDER = "shaders/"; + + private int fsId; + private int vsId; + private int programId; + + private final String fsPath; + private final String vsPath; + + public Shader(final String vertexShaderName, final String fragmentShaderName) { + this.vsPath = SHADER_FOLDER + vertexShaderName; + this.fsPath = SHADER_FOLDER + fragmentShaderName; + } + + public void compile(final GL3 gl) { + vsId = ShaderHelper.createVertexShader(gl, vsPath); + fsId = ShaderHelper.createFragmentShader(gl, fsPath); + + programId = ShaderHelper.createProgram(gl, vsId, fsId); + } + + public int getProgramId() { + return programId; + } +} diff --git a/src/tools/ShaderHelper.java b/src/tools/ShaderHelper.java new file mode 100644 index 0000000..87ff41b --- /dev/null +++ b/src/tools/ShaderHelper.java @@ -0,0 +1,165 @@ +package tools; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +import com.jogamp.common.nio.Buffers; +import com.jogamp.opengl.GL3; + +/** + * Helper Class for loading and linking vertex and fragment shaders. + * + * @author Björn Zimmer + * + */ +public class ShaderHelper { + + public static String loadShaderFromFile(String fileName) { + // allocate a string builder to add line per line + StringBuilder strBuilder = new StringBuilder(); + + try { + InputStream stream = new FileInputStream(fileName); + BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); + + String line = reader.readLine(); + // get text from file, line per line + while (line != null) { + strBuilder.append(line + "\n"); + line = reader.readLine(); + } + // close resources + reader.close(); + stream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + return strBuilder.toString(); + } + + /** + * Loads and compiles a vertex shader from the given source file. Returns + * the shader ID. + * + * @param gl + * @param fileName + * @return + */ + public static int createVertexShader(GL3 gl, String fileName) { + return createShader(gl, fileName, GL3.GL_VERTEX_SHADER); + } + + /** + * Loads and compiles a fragment shader from the given source file. Returns + * the shader ID. + * + * @param gl + * @param fileName + * @return + */ + public static int createFragmentShader(GL3 gl, String fileName) { + return createShader(gl, fileName, GL3.GL_FRAGMENT_SHADER); + } + + /** + * + * @param gl + * @param fileName + * @param shaderType + * GL3.GL_VERTEX_SHADER or GL3.GL_FRAGMENT_SHADER + * @return + */ + private static int createShader(GL3 gl, String fileName, int shaderType) { + // load the source + String shaderSource = loadShaderFromFile(fileName); + + // create the shader id + int shaderId = gl.glCreateShader(shaderType); + // link the id and the source + gl.glShaderSource(shaderId, 1, new String[] { shaderSource }, null); + // compile the shader + gl.glCompileShader(shaderId); + + IntBuffer shaderCompileInfo = Buffers.newDirectIntBuffer(1); + // test if the shader was compiled correctly + gl.glGetShaderiv(shaderId, GL3.GL_COMPILE_STATUS, shaderCompileInfo); + + System.out.println("Shader compile info:" + shaderCompileInfo); + if (shaderCompileInfo.get() == GL3.GL_FALSE) { + String logMessage = getProgramInfoLog(gl, shaderId); + + System.out.println("Shader compilation failed: " + logMessage); + + IntBuffer logLength = Buffers.newDirectIntBuffer(1); + gl.glGetShaderiv(shaderId, GL3.GL_INFO_LOG_LENGTH, logLength); + + ByteBuffer log = Buffers.newDirectByteBuffer(logLength.get(0)); + gl.glGetShaderInfoLog(shaderId, log.limit(), logLength, log); + final byte[] infoBytes = new byte[logLength.get(0)]; + log.get(infoBytes); + System.out.println("Shader compilation failed:\n " + new String(infoBytes)); + } + return shaderId; + } + + /** + * Retrieves the info log for the program. + * + * @param gl + * @param program + * @return + */ + public static String getProgramInfoLog(GL3 gl, int program) { + // get the GL info log + final int par[] = new int[1]; + gl.glGetProgramiv(program, GL3.GL_INFO_LOG_LENGTH, par, 0); + final int logLen = par[0]; + // final int logLen = getProgramParameter(gl, obj, + // GL3.GL_INFO_LOG_LENGTH); + if (logLen <= 0) + return ""; + + // Get the log + final int[] retLength = new int[1]; + final byte[] bytes = new byte[logLen + 1]; + gl.glGetProgramInfoLog(program, logLen, retLength, 0, bytes, 0); + final String logMessage = new String(bytes); + + return logMessage; + } + + /** + * Links a vertex- and fragmentshader to the programm. + * + * @param gl + * @param vertexShaderId + * @param fragmentShaderId + * @return + */ + public static int createProgram(GL3 gl, int vertexShaderId, int fragmentShaderId) { + // generate the id of the program + int programId = gl.glCreateProgram(); + // attach the two shaders + gl.glAttachShader(programId, vertexShaderId); + gl.glAttachShader(programId, fragmentShaderId); + // link them + gl.glLinkProgram(programId); + + IntBuffer linkInfo = Buffers.newDirectIntBuffer(1); + gl.glGetProgramiv(programId, GL3.GL_LINK_STATUS, linkInfo); + System.out.println("Link info: " + linkInfo); + if (linkInfo.get() == GL3.GL_FALSE) { + String logMessage = getProgramInfoLog(gl, programId); + System.out.println("Shader linking failed: " + logMessage); + } + + return programId; + } + +} diff --git a/textures/skybox/space_back_5.png b/textures/skybox/space_back_5.png new file mode 100644 index 0000000..58b65a4 Binary files /dev/null and b/textures/skybox/space_back_5.png differ diff --git a/textures/skybox/space_down_2.png b/textures/skybox/space_down_2.png new file mode 100644 index 0000000..519cef2 Binary files /dev/null and b/textures/skybox/space_down_2.png differ diff --git a/textures/skybox/space_front_4.png b/textures/skybox/space_front_4.png new file mode 100644 index 0000000..7427127 Binary files /dev/null and b/textures/skybox/space_front_4.png differ diff --git a/textures/skybox/space_left_0.png b/textures/skybox/space_left_0.png new file mode 100644 index 0000000..d5c96ff Binary files /dev/null and b/textures/skybox/space_left_0.png differ diff --git a/textures/skybox/space_right_1.png b/textures/skybox/space_right_1.png new file mode 100644 index 0000000..392bef7 Binary files /dev/null and b/textures/skybox/space_right_1.png differ diff --git a/textures/skybox/space_up_3.png b/textures/skybox/space_up_3.png new file mode 100644 index 0000000..6c29b93 Binary files /dev/null and b/textures/skybox/space_up_3.png differ diff --git a/textures/spheres/earth.jpg b/textures/spheres/earth.jpg new file mode 100644 index 0000000..6cdcffe Binary files /dev/null and b/textures/spheres/earth.jpg differ diff --git a/textures/spheres/jupiter.jpg b/textures/spheres/jupiter.jpg new file mode 100644 index 0000000..21f1951 Binary files /dev/null and b/textures/spheres/jupiter.jpg differ diff --git a/textures/spheres/mars.jpg b/textures/spheres/mars.jpg new file mode 100644 index 0000000..b3654a9 Binary files /dev/null and b/textures/spheres/mars.jpg differ diff --git a/textures/spheres/mercury.jpg b/textures/spheres/mercury.jpg new file mode 100644 index 0000000..eebaed9 Binary files /dev/null and b/textures/spheres/mercury.jpg differ diff --git a/textures/spheres/moon.jpg b/textures/spheres/moon.jpg new file mode 100644 index 0000000..8a1de86 Binary files /dev/null and b/textures/spheres/moon.jpg differ diff --git a/textures/spheres/neptune.jpg b/textures/spheres/neptune.jpg new file mode 100644 index 0000000..30e7ac5 Binary files /dev/null and b/textures/spheres/neptune.jpg differ diff --git a/textures/spheres/saturn.jpg b/textures/spheres/saturn.jpg new file mode 100644 index 0000000..d8b23df Binary files /dev/null and b/textures/spheres/saturn.jpg differ diff --git a/textures/spheres/sun.jpg b/textures/spheres/sun.jpg new file mode 100644 index 0000000..9d787d8 Binary files /dev/null and b/textures/spheres/sun.jpg differ diff --git a/textures/spheres/uranus.jpg b/textures/spheres/uranus.jpg new file mode 100644 index 0000000..d0abf4c Binary files /dev/null and b/textures/spheres/uranus.jpg differ diff --git a/textures/spheres/venus.jpg b/textures/spheres/venus.jpg new file mode 100644 index 0000000..6448848 Binary files /dev/null and b/textures/spheres/venus.jpg differ