Project as is

This commit is contained in:
Gnarwhal 2024-08-07 04:28:53 +00:00
commit 80c9e2d168
Signed by: Gnarwhal
GPG key ID: 0989A73D8C421174
55 changed files with 1573 additions and 0 deletions

BIN
res/hitboxes/stages/mountain.shb Executable file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

9
res/shaders/default/default.fs Executable file
View file

@ -0,0 +1,9 @@
#version 450
uniform sampler2D sampler;
in vec2 textureCoords;
void main() {
gl_FragColor = texture2D(sampler, textureCoords);
}

13
res/shaders/default/default.vs Executable file
View file

@ -0,0 +1,13 @@
#version 450
uniform mat4 projection;
in vec3 vertices;
in vec2 texCoords;
out vec2 textureCoords;
void main() {
textureCoords = texCoords;
gl_Position = projection * vec4(vertices, 1);
}

5
res/shaders/shapes/shapes.fs Executable file
View file

@ -0,0 +1,5 @@
#version 450
void main() {
gl_FragColor = vec4(0, 1, 1, 0.5);
}

9
res/shaders/shapes/shapes.vs Executable file
View file

@ -0,0 +1,9 @@
#version 450
uniform mat4 projection;
in vec3 vertices;
void main() {
gl_Position = projection * vec4(vertices, 1);
}

View file

@ -0,0 +1,74 @@
package com.gnarly.engine.components;
import com.gnarly.engine.utils.Library;
public class Animation {
int curFrame, numFrames;
float pastTime, curTime, mspf;
boolean play, loop;
Texture[] frames;
public Animation(String name, String type, int numFrames, int fps, boolean loop) {
this.numFrames = numFrames;
this.loop = loop;
play = true;
mspf = 1000.0f / (float) fps;
pastTime = System.nanoTime() / 1000000.0f;
frames = new Texture[numFrames];
for (int i = 0; i < frames.length; i++)
frames[i] = Library.getTexture(name + " " + (i + 1) + "." + type);
}
public Animation(String name) {
frames = new Texture[1];
frames[0] = Library.getTexture(name);
}
public void update() {
if(frames.length > 1) {
curTime = System.nanoTime() / 1000000.0f;
while(play && curTime - pastTime > mspf) {
if(curFrame != frames.length - 1)
++curFrame;
else if(loop)
curFrame = 0;
else
pause();
pastTime += mspf;
}
}
}
public int getWidth() {
return frames[curFrame].getWidth();
}
public int getHeight() {
return frames[curFrame].getHeight();
}
public void pause() {
play = false;
}
public void play() {
if(!play) {
pastTime = System.nanoTime() / 1000000.0f;
play = true;
}
}
public void reset() {
curFrame = 0;
pastTime = System.nanoTime() / 1000000.0f;
}
public void bind() {
frames[curFrame].bind();
}
public void unbind() {
frames[curFrame].unbind();
}
}

View file

@ -0,0 +1,153 @@
package com.gnarly.engine.components;
import static com.gnarly.engine.utils.MemoryUtils.GL_PROGRAM;
import static com.gnarly.engine.utils.MemoryUtils.GL_SHADER;
import static com.gnarly.engine.utils.MemoryUtils.add;
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.glBindAttribLocation;
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.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.glUniform1f;
import static org.lwjgl.opengl.GL20.glUniform1i;
import static org.lwjgl.opengl.GL20.glUniform2f;
import static org.lwjgl.opengl.GL20.glUniform3f;
import static org.lwjgl.opengl.GL20.glUniformMatrix4fv;
import static org.lwjgl.opengl.GL20.glUseProgram;
import static org.lwjgl.opengl.GL20.glValidateProgram;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.FloatBuffer;
import java.util.HashMap;
import java.util.Map;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.lwjgl.BufferUtils;
public class Shader {
private String name;
private int program, vs, fs;
public static int VERT_ATTRIB = 0, TEX_COORD_ATTRIB = 1;
boolean enabled;
Map<String, Integer> uniforms;
public Shader(String vertPath, String fragPath) {
name = new File(new File(vertPath).getParent()).getName();
uniforms = new HashMap<>();
String vert = load(vertPath);
String frag = load(fragPath);
create(vert, frag);
}
private String load(String path) {
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();
}
return file.toString();
}
public void create(String vert, String frag) {
program = glCreateProgram();
add(GL_PROGRAM, program);
vs = glCreateShader(GL_VERTEX_SHADER);
add(GL_SHADER, vs);
glShaderSource(vs, vert);
glCompileShader(vs);
if(glGetShaderi(vs, GL_COMPILE_STATUS) != 1)
throw new RuntimeException("Failed to compile shader! " + glGetShaderInfoLog(vs));
fs = glCreateShader(GL_FRAGMENT_SHADER);
add(GL_SHADER, fs);
glShaderSource(fs, frag);
glCompileShader(fs);
if(glGetShaderi(fs, GL_COMPILE_STATUS) != 1)
throw new RuntimeException("Failed to compile shader! " + glGetShaderInfoLog(fs));
glAttachShader(program, vs);
glAttachShader(program, fs);
glBindAttribLocation(program, VERT_ATTRIB, "vertices");
glBindAttribLocation(program, TEX_COORD_ATTRIB, "texCoords");
glLinkProgram(program);
glValidateProgram(program);
}
public int getLocation(String name) {
if(uniforms.containsKey(name))
return uniforms.get(name);
int location = glGetUniformLocation(program, name);
uniforms.put(name, location);
if(location != -1)
return location;
else
throw new RuntimeException("Could not find uniform: " + name);
}
public void setUniform1i(String name, int value) {
enable();
glUniform1i(getLocation(name), value);
disable();
}
public void setUniform1f(String name, float value) {
enable();
glUniform1f(getLocation(name), value);
disable();
}
public void setUniform2f(String name, float x, float y) {
enable();
glUniform2f(getLocation(name), x, y);
disable();
}
public void setUniform3f(String name, Vector3f vector) {
enable();
glUniform3f(getLocation(name), vector.x, vector.y, vector.z);
disable();
}
public void setUniformMat4f(String name, Matrix4f matrix) {
enable();
FloatBuffer buffer = BufferUtils.createFloatBuffer(16);
matrix.get(buffer);
glUniformMatrix4fv(getLocation(name), false, buffer);
disable();
}
public String getName() {
return name;
}
public void enable() {
enabled = true;
glUseProgram(program);
}
public void disable() {
enabled = false;
glUseProgram(0);
}
}

View file

@ -0,0 +1,89 @@
package com.gnarly.engine.components;
import static com.gnarly.engine.utils.MemoryUtils.GL_TEXTURE;
import static com.gnarly.engine.utils.MemoryUtils.add;
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_UNSIGNED_BYTE;
import static org.lwjgl.opengl.GL11.glBindTexture;
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;
public class Texture {
private String name;
private int id, width, height;
public Texture(String fileName) {
try {
File file = new File(fileName);
name = file.getName();
BufferedImage bi = ImageIO.read(file);
width = bi.getWidth();
height = bi.getHeight();
int[] pixelsRaw = new int[width * height];
pixelsRaw = bi.getRGB(0, 0, width, height, null, 0, width);
ByteBuffer pixels = BufferUtils.createByteBuffer(width * height * 4);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int pixel = pixelsRaw[i * width + j];
pixels.put((byte)((pixel >> 16) & 0xFF)); //RED
pixels.put((byte)((pixel >> 8) & 0xFF)); //GREEN
pixels.put((byte)((pixel ) & 0xFF)); //BLUE
pixels.put((byte)((pixel >> 24) & 0xFF)); //ALPHA
}
}
pixels.flip();
id = glGenTextures();
add(GL_TEXTURE, id);
bind();
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
unbind();
} catch(IOException e) {
e.printStackTrace();
}
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public String getName() {
return name;
}
public void bind() {
glBindTexture(GL_TEXTURE_2D, id);
}
public void unbind() {
glBindTexture(GL_TEXTURE_2D, 0);
}
}

View file

@ -0,0 +1,87 @@
package com.gnarly.engine.components;
import static com.gnarly.engine.utils.MemoryUtils.GL_BUFFER;
import static com.gnarly.engine.utils.MemoryUtils.add;
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.glGenBuffers;
import static org.lwjgl.opengl.GL20.glDisableVertexAttribArray;
import static org.lwjgl.opengl.GL20.glEnableVertexAttribArray;
import static org.lwjgl.opengl.GL20.glVertexAttribPointer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import org.lwjgl.BufferUtils;
public class VAO {
private int count, vbo, ibo, tcbo;
public VAO(float[] vertices, int[] indices, float[] texCoords) {
count = indices.length;
init(vertices, indices, texCoords);
}
private void init(float[] vertices, int[] indices, float[] texCoords) {
vbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, createFloatBuffer(vertices), GL_STATIC_DRAW);
add(GL_BUFFER, vbo);
ibo = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, createIntBuffer(indices), GL_STATIC_DRAW);
add(GL_BUFFER, ibo);
tcbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, tcbo);
glBufferData(GL_ARRAY_BUFFER, createFloatBuffer(texCoords), GL_STATIC_DRAW);
add(GL_BUFFER, tcbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
public void render() {
glEnableVertexAttribArray(Shader.VERT_ATTRIB);
glEnableVertexAttribArray(Shader.TEX_COORD_ATTRIB);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(Shader.VERT_ATTRIB, 3, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, tcbo);
glVertexAttribPointer(Shader.TEX_COORD_ATTRIB, 2, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(Shader.VERT_ATTRIB);
glDisableVertexAttribArray(Shader.TEX_COORD_ATTRIB);
}
public FloatBuffer createFloatBuffer(float[] data) {
FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);
buffer.put(data);
buffer.flip();
return buffer;
}
public IntBuffer createIntBuffer(int[] data) {
IntBuffer buffer = BufferUtils.createIntBuffer(data.length);
buffer.put(data);
buffer.flip();
return buffer;
}
}

View file

@ -0,0 +1,82 @@
package com.gnarly.engine.display;
import org.joml.Matrix4f;
import org.joml.Vector3f;
public class Camera {
private int width, height;
private Vector3f position;
private Matrix4f projection;
public Camera(int width, int height) {
this.width = width;
this.height = height;
position = new Vector3f(0,0,0);
setProjection(width, height);
}
public void setProjection(int width, int height) {
projection = new Matrix4f().setOrtho2D(0, width, height, 0);
}
public void setPosition(Vector3f position) {
this.position.x = -position.x;
this.position.y = -position.y;
this.position.z = -position.z;
}
public void setPosition(float x, float y, float z) {
position.x = -x;
position.y = -y;
position.z = -z;
}
public void setCenterPosition(Vector3f position) {
this.position.x = -position.x + width / 2;
this.position.y = -position.y + height / 2;
this.position.z = -position.z;
}
public void setCenterPosition(float x, float y, float z) {
position.x = -x + width / 2;
position.y = -y + height / 2;
position.z = -z;
}
public void translate(Vector3f position) {
this.position.x -= position.x;
this.position.y -= position.y;
this.position.z -= position.z;
}
public void translate(float x, float y, float z) {
position.x -= x;
position.y -= y;
position.z -= z;
}
public Matrix4f getUnatransformedProjection() {
return new Matrix4f(projection);
}
public Matrix4f getProjection() {
return projection.translate(position, new Matrix4f());
}
public float getX() {
return -position.x;
}
public float getY() {
return -position.y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}

View file

@ -0,0 +1,178 @@
package com.gnarly.engine.display;
import static org.lwjgl.glfw.GLFW.GLFW_FALSE;
import static org.lwjgl.glfw.GLFW.GLFW_PRESS;
import static org.lwjgl.glfw.GLFW.GLFW_RESIZABLE;
import static org.lwjgl.glfw.GLFW.GLFW_TRUE;
import static org.lwjgl.glfw.GLFW.GLFW_VISIBLE;
import static org.lwjgl.glfw.GLFW.glfwCreateWindow;
import static org.lwjgl.glfw.GLFW.glfwDestroyWindow;
import static org.lwjgl.glfw.GLFW.glfwGetKey;
import static org.lwjgl.glfw.GLFW.glfwGetMouseButton;
import static org.lwjgl.glfw.GLFW.glfwGetPrimaryMonitor;
import static org.lwjgl.glfw.GLFW.glfwGetVideoMode;
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.glfwSetCursorPosCallback;
import static org.lwjgl.glfw.GLFW.glfwSetErrorCallback;
import static org.lwjgl.glfw.GLFW.glfwSetWindowPos;
import static org.lwjgl.glfw.GLFW.glfwSetWindowShouldClose;
import static org.lwjgl.glfw.GLFW.glfwShowWindow;
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.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_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_VERSION;
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.glGetString;
import static org.lwjgl.system.MemoryUtil.NULL;
import java.awt.Dimension;
import java.awt.Toolkit;
import org.joml.Vector3f;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.opengl.GL;
public class Window {
private long window;
private int width, height, mx, my;
private boolean vSync;
public Window(Camera camera, String name, float scale, boolean vSync, boolean resizable) {
width = camera.getWidth();
height = camera.getHeight();
this.vSync = vSync;
init(name, scale, resizable, false);
}
public Window(float percentWidth, float percentHeight, String name, boolean vSync, boolean resizable) {
this.vSync = vSync;
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
width = (int) (percentWidth / 100.0f * screen.getWidth());
height = (int) (percentHeight / 100.0f * screen.getHeight());
init(name, 1, resizable, false);
}
public Window(boolean vSync) {
this.vSync = vSync;
init("null", 1, false, true);
}
private void init(String name, float scale, boolean resizable, boolean fullscreen) {
glfwSetErrorCallback(GLFWErrorCallback.createPrint(System.err));
if(!glfwInit())
throw new IllegalStateException("Could not initalize GLFW!");
if(!fullscreen)
glfwWindowHint(GLFW_RESIZABLE, resizable ? GLFW_TRUE : GLFW_FALSE);
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
GLFWVidMode vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
if(fullscreen || vidMode.width() < width || vidMode.height() < height) {
width = vidMode.width();
height = vidMode.height();
window = glfwCreateWindow(width, height, name, glfwGetPrimaryMonitor(), NULL);
}
else {
window = glfwCreateWindow((int)(width * scale), (int)(height * scale), name, NULL, NULL);
glfwSetWindowPos(window, (int)((vidMode.width() - (width * scale)) / 2), (int)((vidMode.height() - (height * scale)) / 2));
}
glfwSetCursorPosCallback(window, (long window, double xpos, double ypos) -> {
mx = (int)xpos;
my = (int)ypos;
});
glfwMakeContextCurrent(window);
GL.createCapabilities();
if(vSync)
glfwSwapInterval(1);
glfwShowWindow(window);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
System.out.println("OpenGL Version: " + glGetString(GL_VERSION));
}
public void update() {
glfwPollEvents();
}
public void clear() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
public void swap() {
glfwSwapBuffers(window);
}
public Vector3f getMouseCoords() {
return new Vector3f(mx, my, 0);
}
public int isMousePressed() {
int button = -1;
for (int i = 0; i < 8 && button == -1; i++)
if(glfwGetMouseButton(window, i) == GLFW_PRESS)
button = i;
return button;
}
public boolean isKeyPressed(int keyCode) {
return glfwGetKey(window, keyCode) == GLFW_PRESS;
}
public void close() {
glfwSetWindowShouldClose(window, true);
}
public boolean shouldClose() {
boolean close = glfwWindowShouldClose(window);
if(close) {
glfwDestroyWindow(window);
glfwTerminate();
}
return close;
}
public static void cleanup() {
}
public long getWindow() {
return window;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}

View file

@ -0,0 +1,55 @@
package com.gnarly.engine.utils;
import org.joml.Vector3f;
public class CHitbox {
private Vector3f center;
private float radius;
public CHitbox(float x, float y, float radius) {
center = new Vector3f(x, y, 0);
this.radius = radius;
}
public Vector3f collisionAdjust(CHitbox hitbox) {
Vector3f distance = hitbox.center.sub(center, new Vector3f());
distance.x = (float)Math.abs(distance.x);
distance.y = (float)Math.abs(distance.y);
if (2 * radius * radius < distance.lengthSquared()) {
float angle = (float) Math.asin((center.x - hitbox.center.x)/(center.y - hitbox.center.y));
distance.x = (float) Math.cos(angle) * 2 * radius * radius;
distance.y = (float) Math.sin(angle) * 2 * radius * radius;
}
return distance;
}
public boolean checkCollision(CHitbox hitbox) {
Vector3f distance = hitbox.center.sub(center, new Vector3f());
distance.x = (float)Math.abs(distance.x);
distance.y = (float)Math.abs(distance.y);
return 2 * radius * radius < distance.lengthSquared();
}
public void setPosition(float x, float y) {
center.x = x;
center.y = y;
}
public float getX() {
return center.x;
}
public float getY() {
return center.y;
}
public Vector3f getCenter() {
return center;
}
public float radius() {
return radius;
}
}

View file

@ -0,0 +1,86 @@
package com.gnarly.engine.utils;
import java.io.File;
import java.util.ArrayList;
import com.gnarly.engine.components.Shader;
import com.gnarly.engine.components.Texture;
public class Library {
private static Texture[] textures;
private static Shader[] shaders;
private static File[] hitboxes;
private Library() {}
public static void init(String texStart, String shaderStart, String hitboxStart) {
loadTextures(texStart);
loadShaders(shaderStart);
loadHitboxes(hitboxStart);
}
private static void loadTextures(String texStart) {
String[] paths = loadStructure(texStart);
textures = new Texture[paths.length];
for (int i = 0; i < paths.length; i++)
textures[i] = new Texture(paths[i]);
}
private static void loadShaders(String shaderStart) {
String[] paths = loadStructure(shaderStart);
shaders = new Shader[paths.length / 2];
for (int i = 0; i < paths.length; i += 2)
shaders[i / 2] = new Shader(paths[i + 1], paths[i]);
}
private static void loadHitboxes(String hitboxStart) {
String[] paths = loadStructure(hitboxStart);
hitboxes = new File[paths.length];
for (int i = 0; i < paths.length; i++)
hitboxes[i] = new File(paths[i]);
}
private static String[] loadStructure(String structureStart) {
ArrayList<String> check = new ArrayList<>();
ArrayList<String> files = new ArrayList<>();
check.add(structureStart);
while(check.size() > 0) {
File file = new File(check.get(0));
String path = file.getPath();
String[] paths = file.list();
if(paths != null) {
for (int i = 0; i < paths.length; i++)
check.add(path + "/" + paths[i]);
}
else
files.add(path);
check.remove(0);
}
String[] ret = new String[files.size()];
for (int i = 0; i < ret.length; i++)
ret[i] = files.get(i);
return ret;
}
public static Texture getTexture(String name) {
for (int i = 0; i < textures.length; i++)
if(textures[i].getName().equals(name))
return textures[i];
throw new RuntimeException("Could not find texture: " + name + "!");
}
public static Shader getShader(String name) {
for (int i = 0; i < shaders.length; i++)
if(shaders[i].getName().equals(name))
return shaders[i];
throw new RuntimeException("Could not find shader: " + name + "!");
}
public static File getHitboxes(String name) {
for (int i = 0; i < hitboxes.length; i++)
if(hitboxes[i].getName().equals(name))
return hitboxes[i];
throw new RuntimeException("Could not find hitboxes: " + name + "!");
}
}

View file

@ -0,0 +1,58 @@
package com.gnarly.engine.utils;
import static org.lwjgl.openal.AL10.alDeleteBuffers;
import static org.lwjgl.openal.AL10.alDeleteSources;
import static org.lwjgl.opengl.GL11.glDeleteTextures;
import static org.lwjgl.opengl.GL15.glDeleteBuffers;
import static org.lwjgl.opengl.GL20.glDeleteProgram;
import static org.lwjgl.opengl.GL20.glDeleteShader;
import java.util.ArrayList;
public class MemoryUtils {
private static final byte numTypes = 6;
private static boolean init = false;
public static final byte
AL_BUFFER = 0,
AL_SOURCE = 1,
GL_BUFFER = 2,
GL_PROGRAM = 3,
GL_SHADER = 4,
GL_TEXTURE = 5;
private static ArrayList<Integer>[] data;
private MemoryUtils() {}
private static void init() {
data = new ArrayList[numTypes];
for (int i = 0; i < numTypes; i++)
data[i] = new ArrayList<Integer>();
init = true;
}
public static void add(byte type, int num) {
if(!init)
init();
data[type].add(num);
}
public static void destroy() {
if(init) {
for (int i : data[AL_BUFFER])
alDeleteBuffers(i);
for (int i : data[AL_SOURCE])
alDeleteSources(i);
for (int i : data[GL_BUFFER])
glDeleteBuffers(i);
for (int i : data[GL_PROGRAM])
glDeleteProgram(i);
for (int i : data[GL_SHADER])
glDeleteShader(i);
for (int i : data[GL_TEXTURE])
glDeleteTextures(i);
}
}
}

View file

@ -0,0 +1,99 @@
package com.gnarly.engine.utils;
import org.joml.Vector3f;
public class RHitbox {
private Vector3f center, halfExtent;
public RHitbox(float x, float y, float width, float height) {
center = new Vector3f(x + width / 2, y + height / 2, 0);
halfExtent = new Vector3f(width / 2, height / 2, 0);
}
public Vector3f collisionAdjust(RHitbox hitbox) {
Vector3f ret = new Vector3f();
Vector3f distance = hitbox.center.sub(center, new Vector3f());
distance.x = (float)Math.abs(distance.x);
distance.y = (float)Math.abs(distance.y);
distance.sub(halfExtent.add(hitbox.getHalfExtent(), new Vector3f()));
if (distance.x < 0 && distance.y < 0) {
Vector3f correction = hitbox.getCenter().sub(center, new Vector3f());
if(distance.x > distance.y) {
if(correction.x > 0)
ret.x = distance.x;
else
ret.x = -distance.x;
}
else if(distance.x < distance.y) {
if(correction.y > 0)
ret.y = distance.y;
else
ret.y = -distance.y;
}
else {
if(correction.x > 0)
ret.x = distance.x;
else
ret.x = -distance.x;
if(correction.y > 0)
ret.y = distance.y;
else
ret.y = -distance.y;
}
}
return ret;
}
public boolean checkCollision(RHitbox hitbox) {
Vector3f distance = hitbox.center.sub(center, new Vector3f());
distance.x = (float)Math.abs(distance.x);
distance.y = (float)Math.abs(distance.y);
distance.sub(halfExtent.add(hitbox.getHalfExtent(), new Vector3f()));
return (distance.x < 0 && distance.y < 0);
}
public void setPosition(float x, float y) {
center.x = x + halfExtent.x;
center.y = y + halfExtent.y;
}
public void translate(Vector3f translate) {
center.x += translate.x;
center.y += translate.y;
}
public void setBounds(float width, float height) {
halfExtent.x = width / 2;
halfExtent.y = height / 2;
center.x += (width - halfExtent.x) / 2;
center.y += (height - halfExtent.y) / 2;
}
public float getX() {
return center.x - halfExtent.x;
}
public float getY() {
return center.y - halfExtent.y;
}
public float getWidth() {
return halfExtent.x * 2;
}
public float getHeight() {
return halfExtent.y * 2;
}
public Vector3f getCenter() {
return center;
}
public Vector3f getHalfExtent() {
return halfExtent;
}
}

83
src/com/gnarly/game/Main.java Executable file
View file

@ -0,0 +1,83 @@
package com.gnarly.game;
import com.gnarly.engine.display.Camera;
import com.gnarly.engine.display.Window;
import com.gnarly.engine.utils.Library;
import com.gnarly.engine.utils.MemoryUtils;
import com.gnarly.game.panels.PlayPanel;
public class Main implements Runnable {
private final int UPS = 120;
private final int FPS = 120;
private final int PIXEL = 5;
private Window window;
private Camera camera;
private Thread gameLoop;
private PlayPanel panel;
public Main() {
gameLoop = new Thread(this);
gameLoop.start();
}
public void run() {
init();
float pastUTime = (float) System.nanoTime() / 1000000.0f;
float curUTime = 0.0f;
float mspu = 1000.0f / (float)UPS;
float pastFTime = pastUTime;
float curFTime = 0.0f;
float mspf = 1000.0f / (float)FPS;
float pastSec = pastUTime / 1000f;
float curSec = 0.0f;
int frames = 0;
int updates = 0;
while(!window.shouldClose()) {
curUTime = (float) System.nanoTime() / 1000000.0f;
curFTime = curUTime;
if(curUTime - pastUTime > mspu) {
update();
pastUTime += mspu;
++updates;
}
if(curFTime - pastFTime > mspf) {
render();
pastFTime += mspf;
++frames;
}
curSec = (float) System.nanoTime() / 1000000000.0f;
if(curSec - pastSec > 1.0f) {
System.out.println(frames);
frames = 0;
updates = 0;
pastSec += 1;
}
}
MemoryUtils.destroy();
}
private void init() {
camera = new Camera(1920 / PIXEL, 1080 / PIXEL);
window = new Window(true);
Library.init("res/img", "res/shaders", "res/hitboxes");
panel = new PlayPanel(window, camera);
}
private void update() {
window.update();
panel.update();
}
private void render() {
window.clear();
panel.render();
window.swap();
}
public static void main(String[] args) {
new Main();
}
}

View file

@ -0,0 +1,314 @@
package com.gnarly.game.objects;
import static org.lwjgl.glfw.GLFW.GLFW_KEY_A;
import static org.lwjgl.glfw.GLFW.GLFW_KEY_D;
import static org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT_SHIFT;
import static org.lwjgl.glfw.GLFW.GLFW_KEY_S;
import static org.lwjgl.glfw.GLFW.GLFW_KEY_SPACE;
import com.gnarly.engine.components.Animation;
import com.gnarly.engine.components.Shader;
import com.gnarly.engine.components.VAO;
import com.gnarly.engine.display.Camera;
import com.gnarly.engine.display.Window;
import com.gnarly.engine.utils.Library;
import com.gnarly.engine.utils.RHitbox;
public class Character {
private final boolean
LEFT = true,
RIGHT = false;
private final int
IDLE = 0,
WALK = 1,
RUN = 2,
JUMP = 3,
FALL = 4;
private final float
WALK_ACCEL = 1,
SPRINT_ACCEL = 2,
STRAFE_ACCEL = 0.05f,
WALK_SPEED = 1,
SPRINT_SPEED = 2,
STRAFE_SPEED = 0.8f,
GROUND_DECAY = 0.15f,
AERIAL_DECAY = 0.01f,
FASTFALL = 2.0f,
BOUNCE_SPEED = 6.0f,
BOUNCE_SCALE = 0.8f;
private final float
GRAVITY = 0.1f,
MAX_GRAV = 8.0f;
private final float
SHORT_HOP = 0.65f,
LONG_JUMP = 0.35f,
AERIAL_JUMP = 3.0f;
private final int
NUM_JUMPS = 50,
MIN_JUMP = 4,
MAX_JUMP = 7;
private float fallSpeed;
private int state = 0;
private float x, y, width, height, dx, dy;
private boolean airborne = false;
private boolean dir = false;
private int jump = 0;
private int jumps = 0;
private int jumpFrames = 0;
private Animation anims[];
private Shader shader;
private VAO right;
private VAO left;
private Camera camera;
private Window window;
private RHitbox rHitbox;
public Character(Window window, Camera camera, String name, float x, float y) {
this.camera = camera;
this.window = window;
anims = new Animation[5];
anims[IDLE] = new Animation(name + " idle", "png", 8, 10, true);
anims[WALK] = new Animation(name + " walk", "png", 9, 10, true);
anims[RUN] = new Animation(name + " run", "png", 4, 10, true);
anims[JUMP] = new Animation(name + " jump", "png", 6, 20, true);
anims[FALL] = new Animation(name + " fall", "png", 6, 20, true);
this.x = x;
this.y = y - anims[0].getHeight();
width = anims[0].getWidth();
height = anims[0].getHeight();
shader = Library.getShader("default");
rHitbox = new RHitbox(this.x, this.y, width, height);
float[] vertices = new float[] {
0.0f, 0.0f, 0.5f, //TOP LEFT
0.0f, height, 0.5f, //BOTTOM LEFT
width, height, 0.5f, //BOTTOM RIGHT
width, 0.0f, 0.5f //TOP RIGHT
};
int[] indices = new int[] {
0, 1, 3,
1, 2, 3
};
float[] texCoords = new float[] {
0, 0,
0, 1,
1, 1,
1, 0
};
right = new VAO(vertices, indices, texCoords);
texCoords = new float[] {
1, 0,
1, 1,
0, 1,
0, 0
};
left = new VAO(vertices, indices, texCoords);
}
public void update() {
boolean move = false;
if(window.isKeyPressed(GLFW_KEY_D)) {
move = true;
if(window.isKeyPressed(GLFW_KEY_LEFT_SHIFT) && !airborne && dx < 2) {
if(dx > 0)
dx += SPRINT_ACCEL;
else
dx += SPRINT_ACCEL / 20;
if(dx > SPRINT_SPEED)
dx = SPRINT_SPEED;
}
else if(!airborne && dx < 1) {
if(dx > 0)
dx += WALK_ACCEL;
else
dx += WALK_ACCEL / 20;
if(dx > WALK_SPEED)
dx = WALK_SPEED;
}
else if(dx < STRAFE_SPEED)
dx += STRAFE_ACCEL;
}
if(window.isKeyPressed(GLFW_KEY_A)) {
move = true;
if(window.isKeyPressed(GLFW_KEY_LEFT_SHIFT) && !airborne && dx > -2) {
if(dx < 0)
dx -= SPRINT_ACCEL;
else
dx -= SPRINT_ACCEL / 20;
if(dx < -SPRINT_SPEED)
dx = -SPRINT_SPEED;
}
else if(!airborne && dx > -1) {
if(dx < 0)
dx -= WALK_ACCEL;
else
dx -= WALK_ACCEL / 20;
if(dx < -WALK_SPEED)
dx = -WALK_SPEED;
}
else if(dx > -STRAFE_SPEED)
dx -= STRAFE_ACCEL;
}
if(window.isKeyPressed(GLFW_KEY_S) && airborne) {
if(dy > 0)
fallSpeed = FASTFALL;
dy += fallSpeed;
}
jump();
updateAnim();
if(dy < MAX_GRAV) {
if(dy + GRAVITY > MAX_GRAV)
dy = MAX_GRAV;
else
dy += GRAVITY;
}
x += dx;
y += dy;
anims[state].update();
rHitbox.setPosition(x, y);
if(!move) {
if(!airborne && dx > 0) {
dx -= GROUND_DECAY;
if(dx < 0)
dx = 0;
}
else if(!airborne && dx < 0) {
dx += GROUND_DECAY;
if(dx > 0)
dx = 0;
}
}
else if(dx > 0) {
dx -= AERIAL_DECAY;
if(dx < 0)
dx = 0;
}
else if(dx < 0) {
dx += AERIAL_DECAY;
if(dx > 0)
dx = 0;
}
if(window.isKeyPressed(GLFW_KEY_S) && airborne) {
dy -= fallSpeed;
}
}
public void render() {
shader.setUniformMat4f("projection", camera.getProjection().translate(x, y, 0));
anims[state].bind();
shader.enable();
if(dir == RIGHT)
right.render();
else if(dir == LEFT)
left.render();
shader.disable();
anims[state].unbind();
}
private void jump() {
if(airborne && jumps < 2)
jumps = 2;
if((window.isKeyPressed(GLFW_KEY_SPACE) || (jump > 0 && jump < 3)) && jumpFrames < MIN_JUMP) {
if(jump == 0) {
jump = 1;
if(dx > 1)
dx = 1;
else if(dx < -1)
dx = -1;
}
dy -= SHORT_HOP;
airborne = true;
}
else if(window.isKeyPressed(GLFW_KEY_SPACE) && jumpFrames < MAX_JUMP)
dy -= LONG_JUMP;
if(jump % 2 == 1 && !window.isKeyPressed(GLFW_KEY_SPACE))
++jump;
else if(jump % 2 == 0 && jump > 1 && window.isKeyPressed(GLFW_KEY_SPACE) && jumps < NUM_JUMPS) {
++jump;
++jumps;
dy = -AERIAL_JUMP;
if(window.isKeyPressed(GLFW_KEY_A))
dx = -1f;
if(window.isKeyPressed(GLFW_KEY_D))
dx = 1f;
}
if(jumps == 1)
jumpFrames = MAX_JUMP;
else if(jumpFrames < MAX_JUMP && jump > 0)
++jumpFrames;
}
private void updateAnim() {
int tAnim = 0;
if(!airborne) {
if(dx > 1 || dx < -1)
tAnim = RUN;
else if(dx > 0 || dx < 0)
tAnim = WALK;
else
tAnim = IDLE;
if(dx > 0)
dir = RIGHT;
else if(dx < 0)
dir = LEFT;
}
else if(airborne && dy <= 0)
tAnim = JUMP;
else if(airborne && dy > 0)
tAnim = FALL;
if(tAnim != state) {
anims[state].pause();
anims[state].reset();
anims[tAnim].play();
state = tAnim;
}
}
public void hitStage(boolean hit) {
if(!hit)
airborne = true;
else {
if(rHitbox.getX() != x) {
if(Math.abs(dx) < BOUNCE_SPEED)
dx = 0;
else
dx = -dx * BOUNCE_SCALE;
}
else if(rHitbox.getY() < y) {
if(Math.abs(dy) < BOUNCE_SPEED) {
fallSpeed = 0.2f;
dy = 0;
jump = 0;
jumpFrames = 0;
jumps = 0;
airborne = false;
}
else
dy = -dy * BOUNCE_SCALE;
}
else if(rHitbox.getY() > y) {
if(Math.abs(dy) < BOUNCE_SPEED)
dy = 0;
else
dy = -dy * BOUNCE_SCALE;
}
x = rHitbox.getX();
y = rHitbox.getY();
}
}
public RHitbox getRHitbox() {
return rHitbox;
}
}

View file

@ -0,0 +1,48 @@
package com.gnarly.game.objects;
import com.gnarly.engine.components.Shader;
import com.gnarly.engine.components.VAO;
import com.gnarly.engine.display.Camera;
import com.gnarly.engine.utils.Library;
public class Rectangle {
private float x, y, width, height;
private Camera camera;
private Shader shader;
private VAO vao;
public Rectangle(Camera camera, float x, float y, float width, float height) {
this.camera = camera;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
shader = Library.getShader("shapes");
float[] vertices = {
0.0f, 0.0f, 1.0f, //TOP LEFT
0.0f, height, 1.0f, //BOTTOM LEFT
width, height, 1.0f, //BOTTOM RIGHT
width, 0.0f, 1.0f //TOP RIGHT
};
int[] indices = {
0, 1, 3,
1, 2, 3
};
float[] texCoords = {
0, 0,
0, 1,
1, 1,
1, 0
};
vao = new VAO(vertices, indices, texCoords);
}
public void render() {
shader.setUniformMat4f("projection", camera.getProjection().translate(x, y, 0));
shader.enable();
vao.render();
shader.disable();
}
}

View file

@ -0,0 +1,99 @@
package com.gnarly.game.objects;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import com.gnarly.engine.components.Animation;
import com.gnarly.engine.components.Shader;
import com.gnarly.engine.components.VAO;
import com.gnarly.engine.display.Camera;
import com.gnarly.engine.utils.Library;
import com.gnarly.engine.utils.RHitbox;
public class Stage {
private float width, height, floor;
private Vector3f center;
private VAO vao;
private Shader shader;
private Animation stage;
private RHitbox[] hitboxes;
private Camera camera;
public Stage(Camera camera, String stageName) {
this.camera = camera;
stage = new Animation("mountain", "png", 1, 10, true);
shader = Library.getShader("default");
width = stage.getWidth();
height = stage.getHeight();
try {
File hitboxFile = Library.getHitboxes(stageName + ".shb");
ObjectInputStream input = new ObjectInputStream(new FileInputStream(hitboxFile));
center = new Vector3f(input.readFloat(), input.readFloat(), 0);
hitboxes = new RHitbox[input.readInt()];
for (int i = 0; i < hitboxes.length; i++)
hitboxes[i] = new RHitbox(input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat());
input.close();
} catch(IOException e) {
e.printStackTrace();
}
floor = hitboxes[0].getY();
float[] vertices = {
0.0f, 0.0f, 0.0f, //TOP LEFT
0.0f, height, 0.0f, //BOTTOM LEFT
width, height, 0.0f, //BOTTOM RIGHT
width, 0.0f, 0.0f //TOP RIGHT
};
int[] indices = {
0, 1, 3,
1, 2, 3
};
float[] texCoords = {
0, 0,
0, 1,
1, 1,
1, 0
};
vao = new VAO(vertices, indices, texCoords);
}
public void update() {
stage.update();
}
public void render() {
shader.setUniformMat4f("projection", camera.getProjection());
stage.bind();
shader.enable();
vao.render();
shader.disable();
stage.unbind();
}
public boolean checkPlayer(RHitbox character) {
Vector3f translate = new Vector3f();
for (int i = 0; i < hitboxes.length && translate.x == 0 && translate.y == 0; i++)
translate = character.collisionAdjust(hitboxes[i]);
if(translate.x != 0 || translate.y != 0) {
character.translate(translate);
checkPlayer(character);
return true;
}
else
return false;
}
public float getFloor() {
return floor;
}
public Vector3f getCenter() {
return center;
}
}

View file

@ -0,0 +1,32 @@
package com.gnarly.game.panels;
import com.gnarly.engine.display.Camera;
import com.gnarly.engine.display.Window;
import com.gnarly.game.objects.Character;
import com.gnarly.game.objects.Stage;
public class PlayPanel {
private Stage stage;
private Camera camera;
private Character character;
public PlayPanel(Window window, Camera camera) {
this.camera = camera;
stage = new Stage(camera, "mountain");
character = new Character(window, camera, "blue stick", stage.getCenter().x, stage.getFloor());
camera.setCenterPosition(stage.getCenter());
}
public void update() {
stage.update();
character.update();
boolean hit = stage.checkPlayer(character.getRHitbox());
character.hitStage(hit);
}
public void render() {
stage.render();
character.render();
}
}