First player sprite iterations

This commit is contained in:
Gnarwhal 2024-08-07 05:02:53 +00:00
commit 68c7c8cbf3
Signed by: Gnarwhal
GPG key ID: 0989A73D8C421174
37 changed files with 3093 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
.idea/
out/
*.iml

1370
res/img/player/player.ai Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 KiB

19
res/shaders/s2b/frag.gls Normal file
View file

@ -0,0 +1,19 @@
#version 330 core
uniform sampler2D layer0;
uniform sampler2D layer1;
uniform float offset0 = 1;
uniform float offset1 = 1;
in vec2 texCoords;
out vec4 color;
void main() {
vec4 color0 = texture(layer0, texCoords + vec2(0, offset0));
vec4 color1 = texture(layer1, texCoords + vec2(0, offset1));
color = mix(color0, color1, 1 - color0.a);
if (color.a == 0)
discard;
}

13
res/shaders/s2b/vert.gls Normal file
View file

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

9
res/shaders/s2c/frag.gls Normal file
View file

@ -0,0 +1,9 @@
#version 330 core
uniform vec4 iColor = vec4(0, 0.6, 0.9, 1);
out vec4 color;
void main() {
color = iColor;
}

9
res/shaders/s2c/vert.gls Normal file
View file

@ -0,0 +1,9 @@
#version 330 core
uniform mat4 mvp;
layout (location = 0) in vec3 vertices;
void main() {
gl_Position = mvp * vec4(vertices, 1);
}

13
res/shaders/s2t/frag.gls Normal file
View file

@ -0,0 +1,13 @@
#version 330 core
uniform sampler2D sampler;
in vec2 texCoords;
out vec4 color;
void main() {
color = texture(sampler, texCoords);
if (color.a == 0)
discard;
}

13
res/shaders/s2t/vert.gls Normal file
View file

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

4
src/META-INF/MANIFEST.MF Normal file
View file

@ -0,0 +1,4 @@
Manifest-Version: 1.0
Main-Class: com.gnarwhal.ld46.game.Main

View file

@ -0,0 +1,37 @@
package com.gnarwhal.ld46.engine.audio;
import org.lwjgl.openal.AL;
import org.lwjgl.openal.ALC;
import org.lwjgl.openal.ALC10;
import org.lwjgl.openal.ALCCapabilities;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import static org.lwjgl.openal.ALC10.*;
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);
}
}

View file

@ -0,0 +1,38 @@
package com.gnarwhal.ld46.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);
}
}

View file

@ -0,0 +1,83 @@
package com.gnarwhal.ld46.engine.audio;
import org.lwjgl.BufferUtils;
import org.lwjgl.openal.AL10;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.*;
import java.nio.ByteBuffer;
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;
}
}
}

View file

@ -0,0 +1,100 @@
package com.gnarwhal.ld46.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;
}
}

View file

@ -0,0 +1,93 @@
package com.gnarwhal.ld46.engine.display;
import com.gnarwhal.ld46.engine.texture.Texture;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL32.glFramebufferTexture;
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);
}
}

View file

@ -0,0 +1,194 @@
package com.gnarwhal.ld46.engine.display;
import org.joml.Vector3f;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWVidMode;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL.createCapabilities;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL13.GL_MULTISAMPLE;
public class Window {
public static int
SCREEN_WIDTH,
SCREEN_HEIGHT,
REFRESH_RATE;
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;
REFRESH_RATE = vidMode.refreshRate();
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_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_MULTISAMPLE);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
int[] awidth = new int[1], aheight = new int[1];
glfwGetWindowSize(window, awidth, aheight);
width = awidth[0];
height = aheight[0];
}
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.02f, 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;
}
}

View file

@ -0,0 +1,120 @@
package com.gnarwhal.ld46.engine.model;
import com.gnarwhal.ld46.engine.display.Camera;
import com.gnarwhal.ld46.engine.shaders.Shader;
import com.gnarwhal.ld46.engine.shaders.Shader2c;
import org.joml.Vector3f;
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);
}
}

View file

@ -0,0 +1,49 @@
package com.gnarwhal.ld46.engine.model;
import com.gnarwhal.ld46.engine.display.Camera;
import com.gnarwhal.ld46.engine.shaders.Shader;
import com.gnarwhal.ld46.engine.shaders.Shader2c;
import org.joml.Matrix4f;
import org.joml.Vector3f;
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;
}
}

View file

@ -0,0 +1,117 @@
package com.gnarwhal.ld46.engine.model;
import com.gnarwhal.ld46.engine.display.Camera;
import com.gnarwhal.ld46.engine.shaders.Shader;
import com.gnarwhal.ld46.engine.shaders.Shader2c;
import org.joml.Vector3f;
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;
}
}

View file

@ -0,0 +1,137 @@
package com.gnarwhal.ld46.engine.model;
import com.gnarwhal.ld46.engine.display.Camera;
import org.joml.Vector2f;
import org.joml.Vector3f;
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 Vector2f getPosition() {
return new Vector2f(position.x, position.y);
}
public float getWidth() {
return width;
}
public float getHeight() {
return height;
}
public Vector2f getDimensions() {
return new Vector2f(width, 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;
}
}

View file

@ -0,0 +1,44 @@
package com.gnarwhal.ld46.engine.model;
import com.gnarwhal.ld46.engine.display.Camera;
import com.gnarwhal.ld46.engine.shaders.Shader;
import com.gnarwhal.ld46.engine.shaders.Shader2t;
import com.gnarwhal.ld46.engine.texture.Texture;
import org.joml.Matrix4f;
import org.joml.Vector3f;
public class TexRect extends Rect {
private Texture texture;
private Shader2t shader = Shader.SHADER2T;
protected float direction = 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));
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;
}
}

View file

@ -0,0 +1,50 @@
package com.gnarwhal.ld46.engine.model;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
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);
}
}

View file

@ -0,0 +1,8 @@
package com.gnarwhal.ld46.engine.properties;
public class ImproperFormattingException extends RuntimeException {
public ImproperFormattingException(String message) {
super(message);
}
}

View file

@ -0,0 +1,104 @@
package com.gnarwhal.ld46.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;
}
}

View file

@ -0,0 +1,91 @@
package com.gnarwhal.ld46.engine.properties;
import com.gnarwhal.ld46.engine.properties.Properties.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
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;
}
}

View file

@ -0,0 +1,8 @@
package com.gnarwhal.ld46.engine.properties;
public class UndeclaredPropertyException extends Exception {
public UndeclaredPropertyException(String exception) {
super(exception);
}
}

View file

@ -0,0 +1,85 @@
package com.gnarwhal.ld46.engine.shaders;
import org.joml.Matrix4f;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import static org.lwjgl.opengl.GL20.*;
public abstract class Shader {
public static Shader2c SHADER2C;
public static Shader2t SHADER2T;
public static Shader2b SHADER2B;
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();
SHADER2B = new Shader2b();
}
}

View file

@ -0,0 +1,32 @@
package com.gnarwhal.ld46.engine.shaders;
import static org.lwjgl.opengl.GL20.*;
public class Shader2b extends Shader {
private int offset0Loc;
private int offset1Loc;
protected Shader2b() {
super("res/shaders/s2b/vert.gls", "res/shaders/s2b/frag.gls");
getUniforms();
}
public void setOffset(float offset0, float offset1) {
glUniform1f(offset0Loc, offset0);
glUniform1f(offset1Loc, offset1);
}
@Override
protected void getUniforms() {
offset0Loc = glGetUniformLocation(program, "offset0");
offset1Loc = glGetUniformLocation(program, "offset1");
int layer0 = glGetUniformLocation(program, "layer0");
int layer1 = glGetUniformLocation(program, "layer1");
enable();
glUniform1i(layer0, 0);
glUniform1i(layer1, 1);
}
}

View file

@ -0,0 +1,28 @@
package com.gnarwhal.ld46.engine.shaders;
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
import static org.lwjgl.opengl.GL20.glUniform4f;
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);
}
}

View file

@ -0,0 +1,12 @@
package com.gnarwhal.ld46.engine.shaders;
public class Shader2t extends Shader {
protected Shader2t() {
super("res/shaders/s2t/vert.gls", "res/shaders/s2t/frag.gls");
getUniforms();
}
@Override
protected void getUniforms() {}
}

View file

@ -0,0 +1,88 @@
package com.gnarwhal.ld46.engine.texture;
import org.lwjgl.BufferUtils;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
import static org.lwjgl.opengl.GL13.glActiveTexture;
public class Texture {
protected int id, width, height;
public Texture(String name) {
this(name, GL_CLAMP);
}
public Texture(String name, int wrap) {
BufferedImage bi = null;
try {
bi = ImageIO.read(new File(name));
} catch (IOException e) {
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();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap);
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() {
bind(0);
}
public void bind(int activeTexture) {
glActiveTexture(GL_TEXTURE0 + activeTexture);
glBindTexture(GL_TEXTURE_2D, id);
}
public void unbind() {
glBindTexture(GL_TEXTURE_2D, 0);
}
public void destroy() {
glDeleteTextures(id);
}
}

View file

@ -0,0 +1,20 @@
package com.gnarwhal.ld46.engine.texture;
public class TextureSet {
private Texture[] textures;
public TextureSet(String[] paths) {
textures = new Texture[paths.length];
for (int i = 0; i < textures.length; ++i)
textures[i] = new Texture(paths[i]);
}
public int length() {
return textures.length;
}
public Texture get(int index) {
return textures[index];
}
}

View file

@ -0,0 +1,23 @@
package com.gnarwhal.ld46.game;
import com.gnarwhal.ld46.engine.display.Camera;
import com.gnarwhal.ld46.engine.display.Window;
public class GamePanel {
private Window window;
private Camera camera;
public GamePanel(Window window, Camera camera) {
this.window = window;
this.camera = camera;
}
public void update() {
}
public void render() {
}
}

View file

@ -0,0 +1,78 @@
package com.gnarwhal.ld46.game;
import com.gnarwhal.ld46.engine.audio.ALManagement;
import com.gnarwhal.ld46.engine.audio.Sound;
import com.gnarwhal.ld46.engine.display.Camera;
import com.gnarwhal.ld46.engine.display.Window;
import com.gnarwhal.ld46.engine.shaders.Shader;
public class Main {
public static int fps;
public static double dtime;
private ALManagement al;
private Window window;
private Camera camera;
private GamePanel panel;
public void start() {
init();
int frames = 0;
long curTime, pastTime, pastSec, nspf = 1000000000 / Window.REFRESH_RATE;
pastTime = System.nanoTime();
pastSec = pastTime;
while(!window.shouldClose()) {
curTime = System.nanoTime();
if (curTime - pastTime > nspf) {
dtime = nspf / 1000000000d;
update();
render();
pastTime += nspf;
++frames;
}
if (curTime - pastSec > 1000000000) {
fps = frames;
frames = 0;
pastSec += 1000000000;
}
if (nspf - curTime + pastTime > 10000000) try {
Thread.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
al.destroy();
Window.terminate();
}
private void init() {
al = new ALManagement();
final int WIN_WIDTH = 768, WIN_HEIGHT = 432;
window = new Window("Ludum Dare 46", true);
//window = new Window(WIN_WIDTH, WIN_HEIGHT, "Ludum Dare 46", true, true, true);
camera = new Camera(WIN_WIDTH, WIN_HEIGHT);
Shader.init();
panel = new GamePanel(window, camera);
}
private void update() {
window.update();
panel.update();
camera.update();
}
private void render() {
window.clear();
panel.render();
window.swap();
}
public static void main(String[] args) {
new Main().start();
}
}