From 79787f6525b0495648be9d22a40601cedeca0078 Mon Sep 17 00:00:00 2001 From: Gnarwhal Date: Wed, 7 Aug 2024 05:04:15 +0000 Subject: [PATCH] Added initial engine --- .gitignore | 3 + res/img/player-ship.png | Bin 0 -> 553 bytes res/shaders/s2c/frag.gls | 9 + res/shaders/s2c/vert.gls | 9 + res/shaders/s2t/frag.gls | 21 ++ res/shaders/s2t/vert.gls | 13 + src/com/gnarly/engine/audio/ALManagement.java | 39 +++ src/com/gnarly/engine/audio/Sound.java | 38 +++ src/com/gnarly/engine/audio/WaveData.java | 88 ++++++ src/com/gnarly/engine/display/Camera.java | 100 +++++++ .../gnarly/engine/display/Framebuffer.java | 119 +++++++++ src/com/gnarly/engine/display/Window.java | 250 ++++++++++++++++++ src/com/gnarly/engine/model/Circle.java | 121 +++++++++ src/com/gnarly/engine/model/ColRect.java | 50 ++++ src/com/gnarly/engine/model/Line.java | 118 +++++++++ src/com/gnarly/engine/model/Rect.java | 130 +++++++++ src/com/gnarly/engine/model/TexRect.java | 69 +++++ src/com/gnarly/engine/model/Vao.java | 63 +++++ .../ImproperFormattingException.java | 8 + .../gnarly/engine/properties/Properties.java | 104 ++++++++ .../engine/properties/PropertyReader.java | 90 +++++++ .../UndeclaredPropertyException.java | 8 + src/com/gnarly/engine/shaders/Shader.java | 99 +++++++ src/com/gnarly/engine/shaders/Shader2c.java | 27 ++ src/com/gnarly/engine/shaders/Shader2t.java | 33 +++ src/com/gnarly/engine/texture/Texture.java | 97 +++++++ src/com/gnarly/game/Button.java | 85 ++++++ src/com/gnarly/game/GamePanel.java | 35 +++ src/com/gnarly/game/Main.java | 78 ++++++ src/com/gnarly/game/Panel.java | 10 + 30 files changed, 1914 insertions(+) create mode 100644 .gitignore create mode 100644 res/img/player-ship.png create mode 100644 res/shaders/s2c/frag.gls create mode 100644 res/shaders/s2c/vert.gls create mode 100644 res/shaders/s2t/frag.gls create mode 100644 res/shaders/s2t/vert.gls create mode 100644 src/com/gnarly/engine/audio/ALManagement.java create mode 100644 src/com/gnarly/engine/audio/Sound.java create mode 100644 src/com/gnarly/engine/audio/WaveData.java create mode 100644 src/com/gnarly/engine/display/Camera.java create mode 100644 src/com/gnarly/engine/display/Framebuffer.java create mode 100644 src/com/gnarly/engine/display/Window.java create mode 100644 src/com/gnarly/engine/model/Circle.java create mode 100644 src/com/gnarly/engine/model/ColRect.java create mode 100644 src/com/gnarly/engine/model/Line.java create mode 100644 src/com/gnarly/engine/model/Rect.java create mode 100644 src/com/gnarly/engine/model/TexRect.java create mode 100644 src/com/gnarly/engine/model/Vao.java create mode 100644 src/com/gnarly/engine/properties/ImproperFormattingException.java create mode 100644 src/com/gnarly/engine/properties/Properties.java create mode 100644 src/com/gnarly/engine/properties/PropertyReader.java create mode 100644 src/com/gnarly/engine/properties/UndeclaredPropertyException.java create mode 100644 src/com/gnarly/engine/shaders/Shader.java create mode 100644 src/com/gnarly/engine/shaders/Shader2c.java create mode 100644 src/com/gnarly/engine/shaders/Shader2t.java create mode 100644 src/com/gnarly/engine/texture/Texture.java create mode 100644 src/com/gnarly/game/Button.java create mode 100644 src/com/gnarly/game/GamePanel.java create mode 100644 src/com/gnarly/game/Main.java create mode 100644 src/com/gnarly/game/Panel.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..32e849e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +DJam\ 2.iml +out/ diff --git a/res/img/player-ship.png b/res/img/player-ship.png new file mode 100644 index 0000000000000000000000000000000000000000..78358716b2379052a90ac12d44b5043303f69f9e GIT binary patch literal 553 zcmV+^0@nSBP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0lrB@K~z{r?Upfb z!Y~kp9Y!R?uVCnil$jZcfxl2#+n>{}(2-E~yp}dyhIRjw*4~K*PR8V&x zyp|w1fYg4b&N4i_1CdrQ&S&52^+;#487Y&0?>(;f4_)R=-4I?&aLpVH1_NCc`0j_w z05ArwO?M51xE4fg6HK9!u{3*-Bnjzau^^R@mZj7Inr;q^t7bhM4t4cMtJTt#8>u5E z0F0qN?Viu)x~hjAf&zq?-;3pPNuH(y|7mX1z>8&wId8UmfG$+th9QIoYc`vtwF2Cu z3u&5?1_#(~x1@FmpEJOQ%|WBn=|rc~N#P0w#v$E+v2EV(_oLFuwApM*hr~JUc3W3U zb-P_%71*=4O(bBfOZh0COeQACcsw@0;eZ^3L$Em;+XmC=)QmM6jV}De0O~8t-rtn^ z+2!?Txk~^+IK=UIB!#(c%tYVHjFo*{`pE%69)eT|05}8(a6SJK04kY->bt;U4&peb r%?qktK3v9(GXVam9}zd>4x!X9JYhC#v|(eD00000NkvXXu0mjfIok4$ literal 0 HcmV?d00001 diff --git a/res/shaders/s2c/frag.gls b/res/shaders/s2c/frag.gls new file mode 100644 index 0000000..1481224 --- /dev/null +++ b/res/shaders/s2c/frag.gls @@ -0,0 +1,9 @@ +#version 330 core + +uniform vec4 iColor = vec4(0, 0.6, 0.9, 1); + +out vec4 color; + +void main() { + color = iColor; +} \ No newline at end of file diff --git a/res/shaders/s2c/vert.gls b/res/shaders/s2c/vert.gls new file mode 100644 index 0000000..f404630 --- /dev/null +++ b/res/shaders/s2c/vert.gls @@ -0,0 +1,9 @@ +#version 330 core + +uniform mat4 mvp; + +layout (location = 0) in vec3 vertices; + +void main() { + gl_Position = mvp * vec4(vertices, 1); +} \ No newline at end of file diff --git a/res/shaders/s2t/frag.gls b/res/shaders/s2t/frag.gls new file mode 100644 index 0000000..6d0ed1d --- /dev/null +++ b/res/shaders/s2t/frag.gls @@ -0,0 +1,21 @@ +#version 330 core + +uniform sampler2D sampler; + +uniform vec4 iColor = vec4(1, 1, 1, 1); +uniform float alpha = 1; +uniform float amount = 1; + +in vec2 texCoords; + +out vec4 color; + +void main() { + vec4 texColor = texture(sampler, texCoords); + if(texColor.a == 0) + discard; + else { + color = mix(iColor, texColor, amount); + color.a = color.a * alpha; + } +} \ No newline at end of file diff --git a/res/shaders/s2t/vert.gls b/res/shaders/s2t/vert.gls new file mode 100644 index 0000000..6c3699d --- /dev/null +++ b/res/shaders/s2t/vert.gls @@ -0,0 +1,13 @@ +#version 330 core + +uniform mat4 mvp; + +layout (location = 0) in vec3 vertices; +layout (location = 1) in vec2 itexCoords; + +out vec2 texCoords; + +void main() { + texCoords = itexCoords; + gl_Position = mvp * vec4(vertices, 1); +} \ No newline at end of file diff --git a/src/com/gnarly/engine/audio/ALManagement.java b/src/com/gnarly/engine/audio/ALManagement.java new file mode 100644 index 0000000..00c854b --- /dev/null +++ b/src/com/gnarly/engine/audio/ALManagement.java @@ -0,0 +1,39 @@ +package com.gnarly.engine.audio; + +import static org.lwjgl.openal.ALC10.alcCreateContext; +import static org.lwjgl.openal.ALC10.alcMakeContextCurrent; +import static org.lwjgl.openal.ALC10.alcOpenDevice; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +import org.lwjgl.openal.AL; +import org.lwjgl.openal.ALC; +import org.lwjgl.openal.ALC10; +import org.lwjgl.openal.ALCCapabilities; + +public class ALManagement { + + private long device, context; + private ALCCapabilities deviceCaps; + + public ALManagement() { + device = alcOpenDevice((ByteBuffer) null); + if (device == 0) + throw new IllegalStateException("Failed to open the default device."); + + deviceCaps = ALC.createCapabilities(device); + + context = alcCreateContext(device, (IntBuffer) null); + if (context == 0) + throw new IllegalStateException("Failed to create an OpenAL context."); + + alcMakeContextCurrent(context); + AL.createCapabilities(deviceCaps); + } + + public void destroy() { + ALC10.alcDestroyContext(context); + ALC10.alcCloseDevice(device); + } +} diff --git a/src/com/gnarly/engine/audio/Sound.java b/src/com/gnarly/engine/audio/Sound.java new file mode 100644 index 0000000..2e88ca3 --- /dev/null +++ b/src/com/gnarly/engine/audio/Sound.java @@ -0,0 +1,38 @@ +package com.gnarly.engine.audio; + +import org.lwjgl.openal.AL10; + +public class Sound { + + private int buffer; + private int sourceId; + + public Sound(String path) { + sourceId = AL10.alGenSources(); + buffer = AL10.alGenBuffers(); + WaveData waveData = WaveData.create(path); + AL10.alBufferData(buffer, waveData.format, waveData.data, waveData.samplerate); + AL10.alSourcei(sourceId, AL10.AL_BUFFER, buffer); + AL10.alSourcef(sourceId, AL10.AL_GAIN, 1); + AL10.alSourcef(sourceId, AL10.AL_PITCH, 1); + } + + public void play(boolean loop) { + AL10.alSourcei(sourceId, AL10.AL_LOOPING, loop ? 1 : 0); + AL10.alSource3f(sourceId, AL10.AL_POSITION, 0, 0, 0); + AL10.alSourcePlay(sourceId); + } + + public void stop() { + AL10.alSourceStop(sourceId); + } + + public void setVolume(float volume) { + AL10.alSourcef(sourceId, AL10.AL_GAIN, volume); + } + + public void destroy() { + AL10.alDeleteBuffers(buffer); + AL10.alDeleteSources(sourceId); + } +} diff --git a/src/com/gnarly/engine/audio/WaveData.java b/src/com/gnarly/engine/audio/WaveData.java new file mode 100644 index 0000000..3205142 --- /dev/null +++ b/src/com/gnarly/engine/audio/WaveData.java @@ -0,0 +1,88 @@ +package com.gnarly.engine.audio; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.UnsupportedAudioFileException; + +import org.lwjgl.BufferUtils; +import org.lwjgl.openal.AL10; + +public class WaveData { + + final int format; + final int samplerate; + final int totalBytes; + final int bytesPerFrame; + final ByteBuffer data; + + private final AudioInputStream audioStream; + private final byte[] dataArray; + + private WaveData(AudioInputStream stream) { + this.audioStream = stream; + AudioFormat audioFormat = stream.getFormat(); + format = getOpenAlFormat(audioFormat.getChannels(), audioFormat.getSampleSizeInBits()); + this.samplerate = (int) audioFormat.getSampleRate(); + this.bytesPerFrame = audioFormat.getFrameSize(); + this.totalBytes = (int) (stream.getFrameLength() * bytesPerFrame); + this.data = BufferUtils.createByteBuffer(totalBytes); + this.dataArray = new byte[totalBytes]; + loadData(); + } + + protected void dispose() { + try { + audioStream.close(); + data.clear(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private ByteBuffer loadData() { + try { + int bytesRead = audioStream.read(dataArray, 0, totalBytes); + data.clear(); + data.put(dataArray, 0, bytesRead); + data.flip(); + } catch (IOException e) { + e.printStackTrace(); + System.err.println("Couldn't read bytes from audio stream!"); + } + return data; + } + + public static WaveData create(String file) { + WaveData wavStream = null; + try { + InputStream stream = new FileInputStream(new File(file)); + InputStream bufferedInput = new BufferedInputStream(stream); + AudioInputStream audioStream = null; + audioStream = AudioSystem.getAudioInputStream(bufferedInput); + wavStream = new WaveData(audioStream); + } catch (UnsupportedAudioFileException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return wavStream; + } + + + private static int getOpenAlFormat(int channels, int bitsPerSample) { + if (channels == 1) { + return bitsPerSample == 8 ? AL10.AL_FORMAT_MONO8 : AL10.AL_FORMAT_MONO16; + } else { + return bitsPerSample == 8 ? AL10.AL_FORMAT_STEREO8 : AL10.AL_FORMAT_STEREO16; + } + } + +} diff --git a/src/com/gnarly/engine/display/Camera.java b/src/com/gnarly/engine/display/Camera.java new file mode 100644 index 0000000..6812b49 --- /dev/null +++ b/src/com/gnarly/engine/display/Camera.java @@ -0,0 +1,100 @@ +package com.gnarly.engine.display; + +import org.joml.Matrix4f; +import org.joml.Vector3f; + +public class Camera { + + private Matrix4f projection, projView; + + private float width, height; + private Vector3f position; + private float rotation; + + public Camera(float width, float height) { + setDims(width, height); + position = new Vector3f(); + rotation = 0; + projView = new Matrix4f(); + } + + public void setDims(float width, float height) { + this.width = width; + this.height = height; + projection = new Matrix4f().setOrtho(0, width, height, 0, 0, 1); + } + + public void update() { + projection.translate(position.negate(new Vector3f()), projView).rotateZ(-rotation); + } + + public Matrix4f getProjection() { + return new Matrix4f(projection); + } + + public Matrix4f getMatrix() { + return new Matrix4f(projView); + } + + public float getX() { + return position.x; + } + + public float getY() { + return position.y; + } + + public Vector3f getPosition() { + return new Vector3f(position); + } + + public float getWidth() { + return width; + } + + public float getHeight() { + return height; + } + + public void setX(float x) { + position.x = x; + } + + public void setY(float y) { + position.y = y; + } + + public void setPosition(float x, float y) { + position.set(x, y, position.z); + } + + public void setPosition(Vector3f position) { + this.position.x = position.x; + this.position.y = position.y; + } + + public void setCenter(float x, float y) { + position.set(x - width / 2, y - height / 2, position.z); + } + + public void setCenter(Vector3f position) { + this.position.x = position.x - width / 2; + this.position.y = position.y - height / 2; + } + + public void translate(float x, float y, float z) { + position.add(x, y, z); + } + + public void translate(Vector3f transform) { + position.add(transform); + } + + public void setRotation(float angle) { + rotation = angle; + } + + public void rotate(float angle) { + rotation += angle; + } +} diff --git a/src/com/gnarly/engine/display/Framebuffer.java b/src/com/gnarly/engine/display/Framebuffer.java new file mode 100644 index 0000000..ea02641 --- /dev/null +++ b/src/com/gnarly/engine/display/Framebuffer.java @@ -0,0 +1,119 @@ +package com.gnarly.engine.display; + +import static org.lwjgl.opengl.GL11.GL_CLAMP; +import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; +import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; +import static org.lwjgl.opengl.GL11.GL_DEPTH_COMPONENT; +import static org.lwjgl.opengl.GL11.GL_NEAREST; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T; +import static org.lwjgl.opengl.GL11.glBindTexture; +import static org.lwjgl.opengl.GL11.glClear; +import static org.lwjgl.opengl.GL11.glClearColor; +import static org.lwjgl.opengl.GL11.glDrawBuffer; +import static org.lwjgl.opengl.GL11.glGenTextures; +import static org.lwjgl.opengl.GL11.glTexParameterf; +import static org.lwjgl.opengl.GL11.glViewport; +import static org.lwjgl.opengl.GL30.GL_COLOR_ATTACHMENT0; +import static org.lwjgl.opengl.GL30.GL_DEPTH_ATTACHMENT; +import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER; +import static org.lwjgl.opengl.GL30.GL_RENDERBUFFER; +import static org.lwjgl.opengl.GL30.glBindFramebuffer; +import static org.lwjgl.opengl.GL30.glBindRenderbuffer; +import static org.lwjgl.opengl.GL30.glDeleteFramebuffers; +import static org.lwjgl.opengl.GL30.glDeleteRenderbuffers; +import static org.lwjgl.opengl.GL30.glFramebufferRenderbuffer; +import static org.lwjgl.opengl.GL30.glGenFramebuffers; +import static org.lwjgl.opengl.GL30.glGenRenderbuffers; +import static org.lwjgl.opengl.GL30.glRenderbufferStorage; +import static org.lwjgl.opengl.GL32.glFramebufferTexture; + +import com.gnarly.engine.texture.Texture; + +public class Framebuffer { + + int fbo, rbo, width, height; + int colorBuf, depthTex; + float r, g, b, a; + + Framebuffer(int width, int height, float r, float g, float b, float a) { + this.width = width; + this.height = height; + + this.r = r; + this.g = g; + this.b = b; + this.a = a; + + fbo = glGenFramebuffers(); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + + rbo = 0; + colorBuf = 0; + depthTex = 0; + } + + Framebuffer addColorAttachment(Texture texture) { + if (colorBuf == 0) { + int id = glGenTextures(); + glBindTexture(GL_TEXTURE_2D, id); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + texture = new Texture(id, width, height); + colorBuf = 1; + } + return this; + } + + Framebuffer addDepthTextureAttachment(Texture texture) { + if (depthTex == 0) { + int id = glGenTextures(); + glBindTexture(GL_TEXTURE_2D, id); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, id, 0); + texture = new Texture(id, width, height); + depthTex = 1; + } + return this; + } + + Framebuffer addDepthBufferAttachment() { + if (rbo == 0) { + rbo = glGenRenderbuffers(); + glBindRenderbuffer(GL_RENDERBUFFER, rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo); + } + return this; + } + + void bind() { + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glViewport(0, 0, width, height); + + glClearColor(r, g, b, a); + } + + void unbind(Window window) { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, window.getWidth(), window.getHeight()); + window.activateClearColor(); + } + + void clear() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + + public void cleanup() { + if (rbo != 0) + glDeleteRenderbuffers(rbo); + glDeleteFramebuffers(fbo); + } +} diff --git a/src/com/gnarly/engine/display/Window.java b/src/com/gnarly/engine/display/Window.java new file mode 100644 index 0000000..73aba3f --- /dev/null +++ b/src/com/gnarly/engine/display/Window.java @@ -0,0 +1,250 @@ +package com.gnarly.engine.display; + +import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MAJOR; +import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MINOR; +import static org.lwjgl.glfw.GLFW.GLFW_DECORATED; +import static org.lwjgl.glfw.GLFW.GLFW_FALSE; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_LAST; +import static org.lwjgl.glfw.GLFW.GLFW_MAXIMIZED; +import static org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_LAST; +import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_CORE_PROFILE; +import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_FORWARD_COMPAT; +import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_PROFILE; +import static org.lwjgl.glfw.GLFW.GLFW_PRESS; +import static org.lwjgl.glfw.GLFW.GLFW_RELEASE; +import static org.lwjgl.glfw.GLFW.GLFW_REPEAT; +import static org.lwjgl.glfw.GLFW.GLFW_RESIZABLE; +import static org.lwjgl.glfw.GLFW.GLFW_SAMPLES; +import static org.lwjgl.glfw.GLFW.GLFW_TRUE; +import static org.lwjgl.glfw.GLFW.glfwCreateWindow; +import static org.lwjgl.glfw.GLFW.glfwGetCursorPos; +import static org.lwjgl.glfw.GLFW.glfwGetPrimaryMonitor; +import static org.lwjgl.glfw.GLFW.glfwGetVideoMode; +import static org.lwjgl.glfw.GLFW.glfwGetWindowSize; +import static org.lwjgl.glfw.GLFW.glfwInit; +import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent; +import static org.lwjgl.glfw.GLFW.glfwPollEvents; +import static org.lwjgl.glfw.GLFW.glfwSetErrorCallback; +import static org.lwjgl.glfw.GLFW.glfwSetKeyCallback; +import static org.lwjgl.glfw.GLFW.glfwSetMouseButtonCallback; +import static org.lwjgl.glfw.GLFW.glfwSetWindowShouldClose; +import static org.lwjgl.glfw.GLFW.glfwSetWindowSizeCallback; +import static org.lwjgl.glfw.GLFW.glfwSwapBuffers; +import static org.lwjgl.glfw.GLFW.glfwSwapInterval; +import static org.lwjgl.glfw.GLFW.glfwTerminate; +import static org.lwjgl.glfw.GLFW.glfwWindowHint; +import static org.lwjgl.glfw.GLFW.glfwWindowShouldClose; +import static org.lwjgl.opengl.GL.createCapabilities; +import static org.lwjgl.opengl.GL11.GL_BLEND; +import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; +import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; +import static org.lwjgl.opengl.GL11.GL_DEPTH_TEST; +import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA; +import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; +import static org.lwjgl.opengl.GL11.GL_TRUE; +import static org.lwjgl.opengl.GL11.glBlendFunc; +import static org.lwjgl.opengl.GL11.glClear; +import static org.lwjgl.opengl.GL11.glClearColor; +import static org.lwjgl.opengl.GL11.glEnable; +import static org.lwjgl.opengl.GL11.glViewport; +import static org.lwjgl.opengl.GL13.GL_MULTISAMPLE; + +import org.joml.Vector3f; +import org.lwjgl.glfw.GLFWErrorCallback; +import org.lwjgl.glfw.GLFWVidMode; + +public class Window { + + public static String resolution; + + public static int + SCREEN_WIDTH, + SCREEN_HEIGHT; + + public static final int + BUTTON_RELEASED = 0, + BUTTON_UNPRESSED = 1, + BUTTON_PRESSED = 2, + BUTTON_HELD = 3, + BUTTON_REPEAT = 4; + + public static float SCALE; + + private long window; + private int width, height; + private boolean resized; + + private int[] mouseButtons = new int[GLFW_MOUSE_BUTTON_LAST + 1]; + private int[] keys = new int[GLFW_KEY_LAST + 1]; + + public Window(String title, boolean vSync) { + init(0, 0, title, vSync, false, false, false); + } + + public Window(String title, boolean vSync, boolean resizable, boolean decorated) { + init(800, 500, title, vSync, resizable, decorated, true); + } + + public Window(int width, int height, String title, boolean vSync, boolean resizable, boolean decorated) { + init(width, height, title, vSync, resizable, decorated, false); + } + + public void init(int lwidth, int lheight, String title, boolean vSync, boolean resizable, boolean decorated, boolean maximized) { + glfwSetErrorCallback(GLFWErrorCallback.createPrint(System.err)); + + for (int i = 0; i < mouseButtons.length; i++) + mouseButtons[i] = 0; + + if(!glfwInit()) { + System.err.println("GLFW failed to initialize!"); + System.exit(-1); + } + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + + glfwWindowHint(GLFW_SAMPLES, 8); + glfwWindowHint(GLFW_RESIZABLE, resizable ? GLFW_TRUE : GLFW_FALSE); + glfwWindowHint(GLFW_DECORATED, decorated ? GLFW_TRUE : GLFW_FALSE); + glfwWindowHint(GLFW_MAXIMIZED, maximized ? GLFW_TRUE : GLFW_FALSE); + + GLFWVidMode vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); + SCREEN_WIDTH = vidMode.width(); + SCREEN_HEIGHT = vidMode.height(); + SCALE = SCREEN_HEIGHT / 1080f; + if(lwidth == 0 || lheight == 0) { + width = vidMode.width(); + height = vidMode.height(); + window = glfwCreateWindow(width, height, title, glfwGetPrimaryMonitor(), 0); + } + else { + this.width = lwidth; + this.height = lheight; + window = glfwCreateWindow(width, height, title, 0, 0); + } + + glfwMakeContextCurrent(window); + createCapabilities(); + + glfwSwapInterval(vSync ? 1 : 0); + + glfwSetWindowSizeCallback(window, (long window, int w, int h) -> { + width = w; + height = h; + resized = true; + glViewport(0, 0, width, height); + }); + + glfwSetMouseButtonCallback(window, (long window, int button, int action, int mods) -> { + if (action == GLFW_RELEASE) + mouseButtons[button] = BUTTON_RELEASED; + if (action == GLFW_PRESS) + mouseButtons[button] = BUTTON_PRESSED; + if (action == GLFW_REPEAT) + mouseButtons[button] = BUTTON_REPEAT; + }); + + glfwSetKeyCallback(window, (long window, int key, int scancode, int action, int mods) -> { + if (key != -1) { + if (action == GLFW_RELEASE) + keys[key] = BUTTON_RELEASED; + if (action == GLFW_PRESS) + keys[key] = BUTTON_PRESSED; + if (action == GLFW_REPEAT) + keys[key] = BUTTON_REPEAT; + } + }); + + activateClearColor(); + + glEnable(GL_TEXTURE_2D); + + glEnable(GL_DEPTH_TEST); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_MULTISAMPLE); + + int[] awidth = new int[1], aheight = new int[1]; + glfwGetWindowSize(window, awidth, aheight); + width = awidth[0]; + height = aheight[0]; + + if(SCREEN_HEIGHT > 2160) + resolution = "8k"; + else if(SCREEN_HEIGHT > 1440) + resolution = "4k"; + else if(SCREEN_HEIGHT > 1080) + resolution = "1440p"; + else if(SCREEN_HEIGHT > 720) + resolution = "1080p"; + else + resolution = "720p"; + } + + public void update() { + for (int i = 0; i < mouseButtons.length; i++) + if (mouseButtons[i] == BUTTON_RELEASED || mouseButtons[i] == BUTTON_PRESSED) + ++mouseButtons[i]; + for (int i = 0; i < keys.length; i++) + if (keys[i] == BUTTON_RELEASED || keys[i] == BUTTON_PRESSED) + ++keys[i]; + resized = false; + glfwPollEvents(); + } + + public void activateClearColor() { + glClearColor(0, 0, 0, 1); + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public void clear() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + + public void swap() { + glfwSwapBuffers(window); + } + + public void close() { + glfwSetWindowShouldClose(window, true); + } + + public static void terminate() { + glfwTerminate(); + } + + public boolean shouldClose() { + return glfwWindowShouldClose(window); + } + + public int keyPressed(int keyCode) { + return keys[keyCode]; + } + + public Vector3f getMouseCoords(Camera camera) { + double[] x = new double[1], y = new double[1]; + glfwGetCursorPos(window, x, y); + Vector3f ret = new Vector3f((float) x[0], (float) y[0], 0); + return ret.mul(camera.getWidth() / this.width, camera.getHeight() / this.height, 1); + } + + public int mousePressed(int button) { + return mouseButtons[button]; + } + + public boolean wasResized() { + return resized; + } +} diff --git a/src/com/gnarly/engine/model/Circle.java b/src/com/gnarly/engine/model/Circle.java new file mode 100644 index 0000000..87f249b --- /dev/null +++ b/src/com/gnarly/engine/model/Circle.java @@ -0,0 +1,121 @@ +package com.gnarly.engine.model; + +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.shaders.Shader; +import com.gnarly.engine.shaders.Shader2c; + +public class Circle { + + private static Vao vao; + + private Camera camera; + private Shader2c shader; + private Vector3f position; + private float radius; + private float r, g, b, a; + + public Circle(Camera camera, float x, float y, float z, float radius) { + this.camera = camera; + position = new Vector3f(x, y, z); + this.radius = radius; + shader = Shader.SHADER2C; + r = 1; + g = 0; + b = 0; + a = 1; + if(vao == null) + initVao(); + } + + private void initVao() { + final int NUM_POINTS = 30; + float[] cVertices = new float[NUM_POINTS * 3]; + int[] cIndices = new int[(NUM_POINTS - 2) * 3]; + for (int i = 0; i < cVertices.length; i += 3) { + double angle = Math.PI * 2 * i / (NUM_POINTS * 3); + cVertices[i ] = (float) Math.cos(angle); + cVertices[i + 1] = (float) Math.sin(angle); + cVertices[i + 2] = 0; + } + for (int i = 0; i < cIndices.length; i += 3) { + cIndices[i ] = 0; + cIndices[i + 1] = i / 3 + 1; + cIndices[i + 2] = i / 3 + 2; + } + vao = new Vao(cVertices, cIndices); + } + + public void render() { + shader.enable(); + shader.setMVP(camera.getMatrix().translate(position).scale(radius)); + shader.setColor(r, g, b, a); + vao.render(); + } + + public Vector3f getPosition() { + return position; + } + + public void setX(float x) { + position.x = x; + } + + public void setY(float y) { + position.y = y; + } + + public void setZ(float z) { + position.z = z; + } + + public void setPosition(float x, float y) { + position.x = x; + position.y = y; + } + + public void setPosition(float x, float y, float z) { + position.x = x; + position.y = y; + position.z = z; + } + + public void setPosition(Vector3f position) { + this.position.set(position); + } + + public void translate(float x, float y) { + position.x += x; + position.y += y; + } + + public void translate(float x, float y, float z) { + position.x += x; + position.y += y; + position.z += z; + } + + public void translate(Vector3f position) { + this.position.add(position); + } + + public void setRadius(float radius) { + this.radius = radius; + } + + public void setDiameter(float diameter) { + this.radius = diameter / 2; + } + + public void setColor(float r, float g, float b, float a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + public boolean contains(Vector3f vector) { + return (position.sub(vector, new Vector3f()).lengthSquared() < radius * radius); + } +} diff --git a/src/com/gnarly/engine/model/ColRect.java b/src/com/gnarly/engine/model/ColRect.java new file mode 100644 index 0000000..94c132e --- /dev/null +++ b/src/com/gnarly/engine/model/ColRect.java @@ -0,0 +1,50 @@ +package com.gnarly.engine.model; + +import org.joml.Matrix4f; +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.shaders.Shader; +import com.gnarly.engine.shaders.Shader2c; + +public class ColRect extends Rect { + + private Shader2c shader; + + protected float r, g, b, a; + + public ColRect(Camera camera, float x, float y, float z, float width, float height, float r, float g, float b, float a, boolean gui) { + super(camera, x, y, z, width, height, 0, gui); + shader = Shader.SHADER2C; + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + public void render() { + shader.enable(); + shader.setColor(r, g, b, a); + Matrix4f cmat = gui ? camera.getProjection() : camera.getMatrix(); + shader.setMVP(cmat.translate(position.add(width * scale / 2, height * scale / 2, 0, new Vector3f())).rotateZ(rotation * 3.1415927f / 180).scale(width * scale, height * scale, 1).translate(-0.5f, -0.5f, 0)); + vao.render(); + shader.disable(); + } + + public void setColor(float r, float g, float b) { + this.r = r; + this.g = g; + this.b = b; + } + + public void setColor(float r, float g, float b, float a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + public void setAlpha(float alpha) { + a = alpha; + } +} diff --git a/src/com/gnarly/engine/model/Line.java b/src/com/gnarly/engine/model/Line.java new file mode 100644 index 0000000..a78b6b1 --- /dev/null +++ b/src/com/gnarly/engine/model/Line.java @@ -0,0 +1,118 @@ +package com.gnarly.engine.model; + +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.shaders.Shader; +import com.gnarly.engine.shaders.Shader2c; + +public class Line { + + private static Vao cap, rect; + + private Camera camera; + private Shader2c shader; + + private Vector3f position; + private float angle, length, thickness; + private float r, g, b, a; + + public Line(Camera camera, float x1, float y1, float x2, float y2, float depth, float thickness) { + this.camera = camera; + shader = Shader.SHADER2C; + if(cap == null) + initVaos(); + this.thickness = thickness; + position = new Vector3f(x1, y1, depth); + setPoints(x1, y1, x2, y2); + r = 1; + g = 1; + b = 1; + a = 1; + } + + private void initVaos() { + float[] rVertices = { + 0, 0.5f, 0, + 0, -0.5f, 0, + 1, -0.5f, 0, + 1, 0.5f, 0 + }; + int rIndices[] = { + 0, 1, 3, + 1, 2, 3 + }; + rect = new Vao(rVertices, rIndices); + final int NUM_POINTS = 10; + float[] cVertices = new float[NUM_POINTS * 3]; + int[] cIndices = new int[(NUM_POINTS - 2) * 3]; + for (int i = 0; i < cVertices.length; i += 3) { + double angle = Math.PI * i / (NUM_POINTS * 3 - 3) + Math.PI / 2; + cVertices[i ] = (float) Math.cos(angle) / 2; + cVertices[i + 1] = (float) Math.sin(angle) / 2; + cVertices[i + 2] = 0; + } + for (int i = 0; i < cIndices.length; i += 3) { + cIndices[i ] = 0; + cIndices[i + 1] = i / 3 + 1; + cIndices[i + 2] = i / 3 + 2; + } + cap = new Vao(cVertices, cIndices); + } + + public void render() { + shader.enable(); + shader.setColor(r, g, b, a); + shader.setMVP(camera.getMatrix().translate(position).rotateZ(angle).scale(thickness)); + cap.render(); + shader.setMVP(camera.getMatrix().translate(position).rotateZ(angle).scale(length, thickness, 1)); + rect.render(); + shader.setMVP(camera.getMatrix().translate(position.add((float) (Math.cos(angle) * length), (float) (-Math.sin(Math.PI + angle) * length), 0, new Vector3f())).rotateZ((float) Math.PI).rotateZ(angle).scale(thickness)); + cap.render(); + shader.disable(); + } + + public void setAngle(float x, float y, float angle, float length) { + position.x = x; + position.y = y; + this.angle = angle; + this.length = length; + } + + public void setPoints(float x1, float y1, float x2, float y2) { + float xl = x2 - x1; + float yl = y2 - y1; + length = (float) Math.sqrt(xl * xl + yl * yl); + if(x1 != x2) { + angle = (float) Math.atan(yl / xl); + if(xl < 0) + angle += Math.PI; + setAngle(x1, y1, angle, length); + } + else if(y1 > y2) + setAngle(x1, y1, (float) Math.PI * 1.5f, length); + else if(y1 < y2) + setAngle(x1, y1, (float) Math.PI * 0.5f, length); + else + setAngle(x1, y1, 0, 0); + } + + public void setPoints(Vector3f p1, Vector3f p2) { + setPoints(p1.x, p1.y, p2.x, p2.y); + } + + public void setThickness(float thickness) { + this.thickness = thickness; + } + + public void setDepth(float z) { + position.z = z; + } + + public void setColor(float r, float g, float b, float a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } +} diff --git a/src/com/gnarly/engine/model/Rect.java b/src/com/gnarly/engine/model/Rect.java new file mode 100644 index 0000000..9a6c950 --- /dev/null +++ b/src/com/gnarly/engine/model/Rect.java @@ -0,0 +1,130 @@ +package com.gnarly.engine.model; + +import org.joml.Vector2f; +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; + +public class Rect { + + protected static Vao vao; + + protected Camera camera; + + protected float width, height; + protected Vector3f position; + protected float rotation, scale; + protected boolean gui; + + protected Rect(Camera camera, float x, float y, float z, float width, float height, float rotation, boolean gui) { + this.camera = camera; + this.width = width; + this.height = height; + position = new Vector3f(x, y, z); + scale = 1; + this.rotation = rotation; + this.gui = gui; + if(vao == null) { + float vertices[] = { + 1, 0, 0, // Top left + 1, 1, 0, // Bottom left + 0, 1, 0, // Bottom right + 0, 0, 0 // Top right + }; + int indices[] = { + 0, 1, 3, + 1, 2, 3 + }; + float[] texCoords = { + 1, 0, + 1, 1, + 0, 1, + 0, 0 + }; + vao = new Vao(vertices, indices); + vao.addAttrib(texCoords, 2); + } + } + + public float getX() { + return position.x; + } + + public float getY() { + return position.y; + } + + public float getWidth() { + return width; + } + + public float getHeight() { + return height; + } + + public void setX(float x) { + position.x = x; + } + + public void setY(float y) { + position.y = y; + } + + public void set(float x, float y, float width, float height) { + position.x = x; + position.y = y; + this.width = width; + this.height = height; + } + + public void setWidth(float width) { + this.width = width; + } + + public void setHeight(float height) { + this.height = height; + } + + public void setPosition(float x, float y) { + position.set(x, y, position.z); + } + + public void setPosition(float x, float y, float z) { + position.set(x, y, z); + } + + public void setPosition(Vector3f position) { + this.position.x = position.x; + this.position.y = position.y; + this.position.z = position.z; + } + + public void setPosition(Vector2f position) { + this.position.x = position.x; + this.position.y = position.y; + } + + public void translate(Vector3f vector) { + position.add(vector); + } + + public void translate(float x, float y, float z) { + position.add(x, y, z); + } + + public void setRotation(float angle) { + rotation = angle; + } + + public void rotate(float angle) { + rotation += angle; + } + + public void setScale(float scale) { + this.scale = scale; + } + + public void setAngle(float angle) { + this.rotation = angle; + } +} diff --git a/src/com/gnarly/engine/model/TexRect.java b/src/com/gnarly/engine/model/TexRect.java new file mode 100644 index 0000000..c01d76e --- /dev/null +++ b/src/com/gnarly/engine/model/TexRect.java @@ -0,0 +1,69 @@ +package com.gnarly.engine.model; + +import org.joml.Matrix4f; +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.shaders.Shader; +import com.gnarly.engine.shaders.Shader2t; +import com.gnarly.engine.texture.Texture; + +public class TexRect extends Rect { + + private Texture texture; + private Shader2t shader = Shader.SHADER2T; + protected float direction = 1; + private float alpha = 1; + private float r; + private float g; + private float b; + private float a; + private float amount = 1; + + public TexRect(Camera camera, String path, float x, float y, float z, float width, float height, float rotation, boolean gui) { + super(camera, x, y, z, width, height, rotation, gui); + texture = new Texture(path); + } + + public TexRect(Camera camera, Texture texture, float x, float y, float z, float width, float height, float rotation, boolean gui) { + super(camera, x, y, z, width, height, rotation, gui); + this.texture = texture; + } + + public void render() { + texture.bind(); + shader.enable(); + Matrix4f cmat = gui ? camera.getProjection() : camera.getMatrix(); + shader.setMVP(cmat.translate(position.add(width * scale / 2, height * scale / 2, 0, new Vector3f())).rotateZ(rotation).scale(width * scale * direction, height * scale, 1).translate(-0.5f, -0.5f, 0)); + shader.setAlpha(alpha); + shader.setMixColor(r, g, b, a, amount); + vao.render(); + shader.disable(); + texture.unbind(); + } + + public void setCenter(float x, float y) { + position.x = x - width / 2; + position.y = y - height / 2; + } + + public void setTexture(Texture texture) { + this.texture = texture; + } + + public void setMix(float r, float g, float b, float a, float amount) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + this.amount = 1 - amount; + } + + public void setAlpha(float alpha) { + this.alpha = alpha; + } + + public float getAlpha() { + return alpha; + } +} diff --git a/src/com/gnarly/engine/model/Vao.java b/src/com/gnarly/engine/model/Vao.java new file mode 100644 index 0000000..da101be --- /dev/null +++ b/src/com/gnarly/engine/model/Vao.java @@ -0,0 +1,63 @@ +package com.gnarly.engine.model; + +import static org.lwjgl.opengl.GL11.GL_FLOAT; +import static org.lwjgl.opengl.GL11.GL_TRIANGLES; +import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT; +import static org.lwjgl.opengl.GL11.glDrawElements; +import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER; +import static org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER; +import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW; +import static org.lwjgl.opengl.GL15.glBindBuffer; +import static org.lwjgl.opengl.GL15.glBufferData; +import static org.lwjgl.opengl.GL15.glDeleteBuffers; +import static org.lwjgl.opengl.GL15.glGenBuffers; +import static org.lwjgl.opengl.GL20.glDisableVertexAttribArray; +import static org.lwjgl.opengl.GL20.glEnableVertexAttribArray; +import static org.lwjgl.opengl.GL20.glVertexAttribPointer; +import static org.lwjgl.opengl.GL30.glBindVertexArray; +import static org.lwjgl.opengl.GL30.glDeleteVertexArrays; +import static org.lwjgl.opengl.GL30.glGenVertexArrays; + +public class Vao { + + private int numAttribs = 0; + + private int vao, ibo, count; + + private int[] vbos = new int[15]; + + public Vao(float[] vertices, int[] indices) { + vao = glGenVertexArrays(); + glBindVertexArray(vao); + addAttrib(vertices, 3); + ibo = glGenBuffers(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW); + count = indices.length; + } + + public void addAttrib(float[] data, int size) { + int vbo = glGenBuffers(); + vbos[numAttribs] = vbo; + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, data, GL_STATIC_DRAW); + glVertexAttribPointer(numAttribs, size, GL_FLOAT, false, 0, 0); + ++numAttribs; + } + + public void render() { + glBindVertexArray(vao); + for(int i = 0; i < numAttribs; ++i) + glEnableVertexAttribArray(i); + glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, 0); + for(int i = 0; i < numAttribs; ++i) + glDisableVertexAttribArray(i); + } + + public void destroy() { + for(int vbo : vbos) + glDeleteBuffers(vbo); + glDeleteBuffers(ibo); + glDeleteVertexArrays(vao); + } +} diff --git a/src/com/gnarly/engine/properties/ImproperFormattingException.java b/src/com/gnarly/engine/properties/ImproperFormattingException.java new file mode 100644 index 0000000..202410e --- /dev/null +++ b/src/com/gnarly/engine/properties/ImproperFormattingException.java @@ -0,0 +1,8 @@ +package com.gnarly.engine.properties; + +public class ImproperFormattingException extends RuntimeException { + + public ImproperFormattingException(String message) { + super(message); + } +} diff --git a/src/com/gnarly/engine/properties/Properties.java b/src/com/gnarly/engine/properties/Properties.java new file mode 100644 index 0000000..9006add --- /dev/null +++ b/src/com/gnarly/engine/properties/Properties.java @@ -0,0 +1,104 @@ +package com.gnarly.engine.properties; + +public class Properties { + + private String name; + private PropNode head, cur; + + public Properties(String name) { + this.name = new String(name); + } + + public void add(PropNode node) { + if(head == null) { + head = node; + cur = node; + } + else { + cur.next = node; + cur = cur.next; + } + } + + private PropNode get(String key) throws UndeclaredPropertyException { + String[] keys = key.split("\\."); + PropNode mobile = head; + while (mobile != null) { + if(mobile.key.equals(keys[0])) { + if(keys.length > 1 && mobile instanceof BlockNode) + return ((BlockNode) mobile).data.get(key.substring(keys[0].length() + 1)); + else + return mobile; + } + mobile = mobile.next; + } + throw new UndeclaredPropertyException("Property '" + key + "' in properties '" + name + "' was not found!"); + } + + public String getAsString(String key) throws UndeclaredPropertyException { + return ((StringNode) get(key)).data; + } + + public int getAsInt(String key) throws UndeclaredPropertyException { + return ((IntNode) get(key)).data; + } + + public int[] getAsIntArray(String key) throws UndeclaredPropertyException { + PropNode node = get(key); + if(node instanceof IntNode) + return new int[] { ((IntNode) node).data }; + return ((IntArrayNode) get(key)).data; + } + + public double getAsDouble(String key) throws UndeclaredPropertyException { + PropNode node = get(key); + if(node instanceof IntNode) + return (double) ((IntNode) node).data; + return ((DoubleNode) get(key)).data; + } + + public double[] getAsDoubleArray(String key) throws UndeclaredPropertyException { + PropNode node = get(key); + if(node instanceof DoubleNode) + return new double[] { ((DoubleNode) node).data }; + if(node instanceof IntNode) + return new double[] { ((IntNode) node).data }; + if(node instanceof IntArrayNode) { + int[] ints = getAsIntArray(key); + double[] ret = new double[ints.length]; + for (int i = 0; i < ints.length; ++i) + ret[i] = ints[i]; + return ret; + } + return ((DoubleArrayNode) get(key)).data; + } + + public static class PropNode { + public String key; + public PropNode next; + } + + public static class BlockNode extends PropNode { + public Properties data; + } + + public static class StringNode extends PropNode { + public String data; + } + + public static class IntNode extends PropNode { + public int data; + } + + public static class IntArrayNode extends PropNode { + public int[] data; + } + + public static class DoubleNode extends PropNode { + public double data; + } + + public static class DoubleArrayNode extends PropNode { + public double[] data; + } +} diff --git a/src/com/gnarly/engine/properties/PropertyReader.java b/src/com/gnarly/engine/properties/PropertyReader.java new file mode 100644 index 0000000..12353fb --- /dev/null +++ b/src/com/gnarly/engine/properties/PropertyReader.java @@ -0,0 +1,90 @@ +package com.gnarly.engine.properties; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Scanner; +import com.gnarly.engine.properties.Properties.*; + +public class PropertyReader { + + private static int lineNum; + private static String path; + + public static Properties readProperties(String path) { + Properties props = null; + try { + File file = new File(path); + Scanner scanner = new Scanner(file); + PropertyReader.path = path; + lineNum = 0; + props = readBlock(file.getName(), scanner).data; + scanner.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + System.exit(-1); + } + return props; + } + + private static BlockNode readBlock(String name, Scanner scanner) { + BlockNode props = new BlockNode(); + props.key = name; + props.data = new Properties(name); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + line = line.replaceAll("\\s", ""); + if(line.equals("}")) + break; + else if(line.length() < 2 || !line.substring(0, 2).equals("//")){ + String[] pair = line.split(":"); + if (pair.length != 2) + throw new ImproperFormattingException("Formatting exception on line " + line + " in file '" + path + "!"); + pair[1] = pair[1].replaceAll("\\s", ""); + if (pair[1].equals("{")) + props.data.add(readBlock(pair[0], scanner)); + else if (pair[1].matches("(\\d+|0x[\\da-f]+)")) { + IntNode node = new IntNode(); + node.key = pair[0]; + node.data = Integer.decode(pair[1]); + props.data.add(node); + } + else if (pair[1].matches("(\\d+|0x[\\d0-9]+)(,(\\d+|0x[\\d0-9]+))+")) { + String[] data = pair[1].split(","); + int[] ints = new int[data.length]; + for (int i = 0; i < ints.length; ++i) + ints[i] = Integer.decode(data[i]); + IntArrayNode node = new IntArrayNode(); + node.key = pair[0]; + node.data = ints; + props.data.add(node); + + } + else if (pair[1].matches("\\d+\\.\\d+")) { + DoubleNode node = new DoubleNode(); + node.key = pair[0]; + node.data = Double.parseDouble(pair[1]); + props.data.add(node); + } + else if (pair[1].matches("\\d+\\.\\d+(,\\d+\\.\\d+)+")) { + String[] data = pair[1].split(","); + double[] doubles = new double[data.length]; + for (int i = 0; i < doubles.length; ++i) + doubles[i] = Double.parseDouble(data[i]); + DoubleArrayNode node = new DoubleArrayNode(); + node.key = pair[0]; + node.data = doubles; + props.data.add(node); + + } + else { + StringNode node = new StringNode(); + node.key = pair[0]; + node.data = pair[1]; + props.data.add(node); + } + } + ++lineNum; + } + return props; + } +} diff --git a/src/com/gnarly/engine/properties/UndeclaredPropertyException.java b/src/com/gnarly/engine/properties/UndeclaredPropertyException.java new file mode 100644 index 0000000..56bb7dd --- /dev/null +++ b/src/com/gnarly/engine/properties/UndeclaredPropertyException.java @@ -0,0 +1,8 @@ +package com.gnarly.engine.properties; + +public class UndeclaredPropertyException extends Exception { + + public UndeclaredPropertyException(String exception) { + super(exception); + } +} diff --git a/src/com/gnarly/engine/shaders/Shader.java b/src/com/gnarly/engine/shaders/Shader.java new file mode 100644 index 0000000..fda1e06 --- /dev/null +++ b/src/com/gnarly/engine/shaders/Shader.java @@ -0,0 +1,99 @@ +package com.gnarly.engine.shaders; + +import static org.lwjgl.opengl.GL20.GL_COMPILE_STATUS; +import static org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER; +import static org.lwjgl.opengl.GL20.GL_VERTEX_SHADER; +import static org.lwjgl.opengl.GL20.glAttachShader; +import static org.lwjgl.opengl.GL20.glCompileShader; +import static org.lwjgl.opengl.GL20.glCreateProgram; +import static org.lwjgl.opengl.GL20.glCreateShader; +import static org.lwjgl.opengl.GL20.glDeleteProgram; +import static org.lwjgl.opengl.GL20.glDeleteShader; +import static org.lwjgl.opengl.GL20.glDetachShader; +import static org.lwjgl.opengl.GL20.glGetShaderInfoLog; +import static org.lwjgl.opengl.GL20.glGetShaderi; +import static org.lwjgl.opengl.GL20.glGetUniformLocation; +import static org.lwjgl.opengl.GL20.glLinkProgram; +import static org.lwjgl.opengl.GL20.glShaderSource; +import static org.lwjgl.opengl.GL20.glUniformMatrix4fv; +import static org.lwjgl.opengl.GL20.glUseProgram; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +import org.joml.Matrix4f; + +public abstract class Shader { + + public static Shader2c SHADER2C; + public static Shader2t SHADER2T; + + protected int program; + + protected int mvpLoc; + + protected Shader(String vertPath, String fragPath) { + program = glCreateProgram(); + + int vert = loadShader(vertPath, GL_VERTEX_SHADER); + int frag = loadShader(fragPath, GL_FRAGMENT_SHADER); + + glAttachShader(program, vert); + glAttachShader(program, frag); + + glLinkProgram(program); + + glDetachShader(program, vert); + glDetachShader(program, frag); + + glDeleteShader(vert); + glDeleteShader(frag); + + mvpLoc = glGetUniformLocation(program, "mvp"); + } + + private int loadShader(String path, int type) { + StringBuilder file = new StringBuilder(); + try { + BufferedReader reader = new BufferedReader(new FileReader(new File(path))); + String line; + while((line = reader.readLine()) != null) + file.append(line + '\n'); + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + String source = file.toString(); + int shader = glCreateShader(type); + glShaderSource(shader, source); + glCompileShader(shader); + if(glGetShaderi(shader, GL_COMPILE_STATUS) != 1) + throw new RuntimeException("Failed to compile shader: " + path + "! " + glGetShaderInfoLog(shader)); + return shader; + } + + protected abstract void getUniforms(); + + public void setMVP(Matrix4f matrix) { + glUniformMatrix4fv(mvpLoc, false, matrix.get(new float[16])); + } + + public void enable() { + glUseProgram(program); + } + + public void disable() { + glUseProgram(0); + } + + public void destroy() { + glDeleteProgram(program); + } + + public static void init() { + SHADER2C = new Shader2c(); + SHADER2T = new Shader2t(); + } +} diff --git a/src/com/gnarly/engine/shaders/Shader2c.java b/src/com/gnarly/engine/shaders/Shader2c.java new file mode 100644 index 0000000..6939682 --- /dev/null +++ b/src/com/gnarly/engine/shaders/Shader2c.java @@ -0,0 +1,27 @@ +package com.gnarly.engine.shaders; + +import static org.lwjgl.opengl.GL20.*; + +public class Shader2c extends Shader { + + int colorLoc; + + protected Shader2c(String vert, String frag) { + super(vert, frag); + getUniforms(); + } + + protected Shader2c() { + super("res/shaders/s2c/vert.gls", "res/shaders/s2c/frag.gls"); + getUniforms(); + } + + @Override + protected void getUniforms() { + colorLoc = glGetUniformLocation(program, "iColor"); + } + + public void setColor(float r, float g, float b, float a) { + glUniform4f(colorLoc, r, g, b, a); + } +} diff --git a/src/com/gnarly/engine/shaders/Shader2t.java b/src/com/gnarly/engine/shaders/Shader2t.java new file mode 100644 index 0000000..8b473b2 --- /dev/null +++ b/src/com/gnarly/engine/shaders/Shader2t.java @@ -0,0 +1,33 @@ +package com.gnarly.engine.shaders; + +import static org.lwjgl.opengl.GL20.glGetUniformLocation; +import static org.lwjgl.opengl.GL20.glUniform1f; +import static org.lwjgl.opengl.GL20.glUniform4f; + +public class Shader2t extends Shader { + + private int alphaLoc; + private int colorLoc; + private int amountLoc; + + protected Shader2t() { + super("res/shaders/s2t/vert.gls", "res/shaders/s2t/frag.gls"); + getUniforms(); + } + + public void setMixColor(float r, float g, float b, float a, float amount) { + glUniform4f(colorLoc, r, g, b, a); + glUniform1f(amountLoc, amount); + } + + public void setAlpha(float a) { + glUniform1f(alphaLoc, a); + } + + @Override + protected void getUniforms() { + alphaLoc = glGetUniformLocation(program, "alpha"); + colorLoc = glGetUniformLocation(program, "iColor"); + amountLoc = glGetUniformLocation(program, "amount"); + } +} \ No newline at end of file diff --git a/src/com/gnarly/engine/texture/Texture.java b/src/com/gnarly/engine/texture/Texture.java new file mode 100644 index 0000000..5461aa3 --- /dev/null +++ b/src/com/gnarly/engine/texture/Texture.java @@ -0,0 +1,97 @@ +package com.gnarly.engine.texture; + +import static org.lwjgl.opengl.GL11.GL_CLAMP; +import static org.lwjgl.opengl.GL11.GL_NEAREST; +import static org.lwjgl.opengl.GL11.GL_RGBA; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T; +import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE; +import static org.lwjgl.opengl.GL11.glBindTexture; +import static org.lwjgl.opengl.GL11.glDeleteTextures; +import static org.lwjgl.opengl.GL11.glGenTextures; +import static org.lwjgl.opengl.GL11.glTexImage2D; +import static org.lwjgl.opengl.GL11.glTexParameterf; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; + +import javax.imageio.ImageIO; + +import org.lwjgl.BufferUtils; + +import com.gnarly.engine.display.Window; + +public class Texture { + + protected int id, width, height; + + public Texture(String name) { + BufferedImage bi = null; + try { + bi = ImageIO.read(new File("res/img/" + Window.resolution + "/" + name)); + } catch (IOException e) { + try { + bi = ImageIO.read(new File("res/img/const/" + name)); + } catch (IOException ex) { + e.printStackTrace(); + } + } + if (bi != null) { + width = bi.getWidth(); + height = bi.getHeight(); + int[] pixels = bi.getRGB(0, 0, width, height, null, 0, width); + ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * 4); + + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + int pixel = pixels[i * width + j]; + buffer.put((byte)((pixel >> 16) & 0xFF)); // Red + buffer.put((byte)((pixel >> 8) & 0xFF)); // Green + buffer.put((byte)((pixel ) & 0xFF)); // Blue + buffer.put((byte)((pixel >> 24) & 0xFF)); // Alpha + } + } + buffer.flip(); + + id = glGenTextures(); + bind(); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + unbind(); + } + } + + public Texture(int id, int width, int height) { + this.id = id; + this.width = width; + this.height = height; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public void bind() { + glBindTexture(GL_TEXTURE_2D, id); + } + + public void unbind() { + glBindTexture(GL_TEXTURE_2D, 0); + } + + public void destroy() { + glDeleteTextures(id); + } +} diff --git a/src/com/gnarly/game/Button.java b/src/com/gnarly/game/Button.java new file mode 100644 index 0000000..8bc0d7a --- /dev/null +++ b/src/com/gnarly/game/Button.java @@ -0,0 +1,85 @@ +package com.gnarly.game; + +import static org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_1; + +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; +import com.gnarly.engine.model.TexRect; + +public class Button { + + public static final int + UNPRESSED = 0, + RELEASED = 1, + PRESSED = 2, + HELD = 3; + + private Window window; + private Camera camera; + + private TexRect[] states; + + private float x, y, width, height; + + private int state, tex; + + public Button(Window window, Camera camera, String tex1, String tex2, String tex3, float x, float y, float depth, float width, float height, boolean gui) { + this.window = window; + this.camera = camera; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + states = new TexRect[3]; + states[0] = new TexRect(camera, tex1, x, y, depth, width, height, 0, gui); + states[1] = new TexRect(camera, tex2, x, y, depth, width, height, 0, gui); + states[2] = new TexRect(camera, tex3, x, y, depth, width, height, 0, gui); + tex = 0; + state = 0; + } + + public void update() { + if(contains(window.getMouseCoords(camera))) { + if(window.mousePressed(GLFW_MOUSE_BUTTON_1) > Window.BUTTON_UNPRESSED) { + tex = 2; + if(state <= RELEASED) + state = PRESSED; + else + state = HELD; + } + else { + tex = 1; + if(state >= PRESSED) + state = RELEASED; + else + state = UNPRESSED; + } + } + else { + tex = 0; + state = UNPRESSED; + } + } + + public void render() { + states[tex].render(); + } + + public boolean contains(Vector3f coords) { + return coords.x >= x && coords.y >= y && coords.x < x + width && coords.y < y + height; + } + + public int getState() { + return state; + } + + public void setTex(int tex) { + this.tex = tex; + } + + public float getHeight() { + return states[0].getHeight(); + } +} diff --git a/src/com/gnarly/game/GamePanel.java b/src/com/gnarly/game/GamePanel.java new file mode 100644 index 0000000..2aa03ff --- /dev/null +++ b/src/com/gnarly/game/GamePanel.java @@ -0,0 +1,35 @@ +package com.gnarly.game; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; + +public class GamePanel extends Panel { + + private Window window; + private Camera camera; + + public GamePanel(Window window, Camera camera) { + this.window = window; + this.camera = camera; + + state = Main.GAME_PANEL; + } + + public void update() { + + } + + public void render() { + + } + + public void reset() { + + } + + public int checkState() { + int state = this.state; + this.state = Main.GAME_PANEL; + return state; + } +} diff --git a/src/com/gnarly/game/Main.java b/src/com/gnarly/game/Main.java new file mode 100644 index 0000000..c068208 --- /dev/null +++ b/src/com/gnarly/game/Main.java @@ -0,0 +1,78 @@ +package com.gnarly.game; + +import com.gnarly.engine.audio.ALManagement; +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; +import com.gnarly.engine.shaders.Shader; + +public class Main { + + public static long FPS = 999; + public static double dtime; + + public static final int + NUM_PANELS = 1, + GAME_PANEL = 0; + + private ALManagement al; + + private Window window; + private Camera camera; + + private Panel[] panels; + private int panel; + + public void start() { + long curTime, pastTime, nspf = 1000000000 / FPS; + init(); + pastTime = System.nanoTime(); + while(!window.shouldClose()) { + curTime = System.nanoTime(); + if (curTime - pastTime > nspf) { + dtime = (curTime - pastTime) / 1000000000d; + update(); + render(); + pastTime = curTime; + } + } + al.destroy(); + Window.terminate(); + } + + private void init() { + al = new ALManagement(); + window = new Window("Gamer Time", true); + //window = new Window(100, 100, "Gamer Time", true, true, true); + camera = new Camera(1920, 1080); + Shader.init(); + + panels = new Panel[NUM_PANELS]; + panels[GAME_PANEL] = new GamePanel(window, camera); + panel = GAME_PANEL; + } + + private void update() { + window.update(); + int state = panels[panel].checkState(); + if (state != panel) { + switch (state) { + case GAME_PANEL: + GamePanel game = (GamePanel) panels[GAME_PANEL]; + game.reset(); + } + panel = state; + } + panels[panel].update(); + camera.update(); + } + + private void render() { + window.clear(); + panels[panel].render(); + window.swap(); + } + + public static void main(String[] args) { + new Main().start(); + } +} diff --git a/src/com/gnarly/game/Panel.java b/src/com/gnarly/game/Panel.java new file mode 100644 index 0000000..14d6d7a --- /dev/null +++ b/src/com/gnarly/game/Panel.java @@ -0,0 +1,10 @@ +package com.gnarly.game; + +public abstract class Panel { + + protected int state; + + public abstract void update(); + public abstract void render(); + public abstract int checkState(); +}