Entire project
This commit is contained in:
commit
e1c6c794d4
108 changed files with 2908 additions and 0 deletions
65
src/com/gnarly/engine/display/Camera.java
Normal file
65
src/com/gnarly/engine/display/Camera.java
Normal file
|
@ -0,0 +1,65 @@
|
|||
package com.gnarly.engine.display;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
public class Camera {
|
||||
|
||||
private float width, height;
|
||||
private Matrix4f projection;
|
||||
private Vector3f position;
|
||||
private float rotation;
|
||||
|
||||
public Camera(int width, int height) {
|
||||
position = new Vector3f();
|
||||
rotation = 0;
|
||||
projection = new Matrix4f();
|
||||
setDims(width, height);
|
||||
}
|
||||
|
||||
public void setDims(float width, float height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
projection.setOrtho(0, width, height, 0, 1, -1);
|
||||
}
|
||||
|
||||
public void translate(int x, int y) {
|
||||
position.sub(x, y, 0);
|
||||
}
|
||||
|
||||
public void translate(Vector3f vector) {
|
||||
position.sub(vector);
|
||||
}
|
||||
|
||||
public void setPosition(int x, int y) {
|
||||
position.set(x, y, 0);
|
||||
}
|
||||
|
||||
public void setPosition(Vector3f vector) {
|
||||
position.set(vector);
|
||||
}
|
||||
|
||||
public void rotate(float angle) {
|
||||
this.rotation -= angle;
|
||||
}
|
||||
|
||||
public void setRotation(float angle) {
|
||||
this.rotation = angle;
|
||||
}
|
||||
|
||||
public float getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public float getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public Matrix4f getProjection() {
|
||||
return projection;
|
||||
}
|
||||
|
||||
public Matrix4f getView() {
|
||||
return new Matrix4f().rotateZ(rotation).translate(position);
|
||||
}
|
||||
}
|
65
src/com/gnarly/engine/display/Framebuffer.java
Normal file
65
src/com/gnarly/engine/display/Framebuffer.java
Normal file
|
@ -0,0 +1,65 @@
|
|||
package com.gnarly.engine.display;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
import static org.lwjgl.opengl.GL30.*;
|
||||
import static org.lwjgl.opengl.GL32.*;
|
||||
|
||||
public class Framebuffer {
|
||||
|
||||
private int fbo;
|
||||
private int texture;
|
||||
private int depth;
|
||||
|
||||
private int width, height;
|
||||
|
||||
public Framebuffer(int width, int height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
fbo = createFrameBuffer();
|
||||
texture = createTextureAttachment();
|
||||
depth = createDepthBufferAttachment();
|
||||
}
|
||||
|
||||
public void cleanUp() {
|
||||
glDeleteFramebuffers(fbo);
|
||||
glDeleteTextures(texture);
|
||||
glDeleteRenderbuffers(depth);
|
||||
}
|
||||
|
||||
public void bind() {
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
public int getTexture() {
|
||||
return texture;
|
||||
}
|
||||
|
||||
private int createFrameBuffer() {
|
||||
int frameBuffer = glGenFramebuffers();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||
return frameBuffer;
|
||||
}
|
||||
|
||||
private int createTextureAttachment() {
|
||||
int texture = glGenTextures();
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, (ByteBuffer) null);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0);
|
||||
return texture;
|
||||
}
|
||||
|
||||
private int createDepthBufferAttachment() {
|
||||
int depthBuffer = glGenRenderbuffers();
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
|
||||
return depthBuffer;
|
||||
}
|
||||
}
|
279
src/com/gnarly/engine/display/Window.java
Normal file
279
src/com/gnarly/engine/display/Window.java
Normal file
|
@ -0,0 +1,279 @@
|
|||
package com.gnarly.engine.display;
|
||||
|
||||
import static org.lwjgl.glfw.GLFW.*;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MINOR;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_FALSE;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_CORE_PROFILE;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_PROFILE;
|
||||
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.glfwCreateWindow;
|
||||
import static org.lwjgl.glfw.GLFW.glfwGetCursorPos;
|
||||
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.glfwSetErrorCallback;
|
||||
import static org.lwjgl.glfw.GLFW.glfwSetScrollCallback;
|
||||
import static org.lwjgl.glfw.GLFW.glfwSetWindowPos;
|
||||
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.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.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.GL30.*;
|
||||
import static org.lwjgl.system.MemoryUtil.NULL;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
import org.lwjgl.glfw.GLFWCharCallback;
|
||||
import org.lwjgl.glfw.GLFWCharModsCallback;
|
||||
import org.lwjgl.glfw.GLFWErrorCallback;
|
||||
import org.lwjgl.glfw.GLFWKeyCallback;
|
||||
import org.lwjgl.glfw.GLFWScrollCallback;
|
||||
import org.lwjgl.glfw.GLFWVidMode;
|
||||
import org.lwjgl.glfw.GLFWWindowSizeCallback;
|
||||
|
||||
public class Window {
|
||||
|
||||
public static final byte
|
||||
UNPRESSED = 0,
|
||||
RELEASED = 1,
|
||||
PRESSED = 2,
|
||||
HELD = 3;
|
||||
|
||||
private long window;
|
||||
|
||||
private GLFWVidMode vidMode;
|
||||
|
||||
private int xOff, yOff, vWidth, vHeight;
|
||||
|
||||
private double scrollX, scrollY;
|
||||
|
||||
private StringBuilder input;
|
||||
|
||||
private boolean resized;
|
||||
|
||||
byte[] keys = new byte[GLFW_KEY_LAST];
|
||||
|
||||
public Window(int width, int height, boolean vSync, boolean resizable, String title) {
|
||||
init(width, height, vSync, resizable, title);
|
||||
}
|
||||
|
||||
public Window(boolean vSync) {
|
||||
init(0, 0, vSync, false, null);
|
||||
}
|
||||
|
||||
private void init(int width, int height, boolean vSync, boolean resizable, String title) {
|
||||
glfwSetErrorCallback(GLFWErrorCallback.createPrint(System.err));
|
||||
|
||||
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_RESIZABLE, resizable ? GLFW_TRUE : GLFW_FALSE);
|
||||
|
||||
vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
||||
if(width == 0 || height == 0 || width >= vidMode.width() || height >= vidMode.height()) {
|
||||
width = vidMode.width();
|
||||
height = vidMode.height();
|
||||
window = glfwCreateWindow(width, height, "", glfwGetPrimaryMonitor(), NULL);
|
||||
}
|
||||
else {
|
||||
window = glfwCreateWindow(width, height, title, NULL, NULL);
|
||||
glfwSetWindowPos(window, (vidMode.width() - width) / 2, (vidMode.height() - height) / 2);
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
createCapabilities();
|
||||
|
||||
glfwSwapInterval(vSync ? 1 : 0);
|
||||
|
||||
glfwSetWindowSizeCallback(window, new GLFWWindowSizeCallback() {
|
||||
public void invoke(long window, int width, int height) {
|
||||
resized = true;
|
||||
glViewport(0, 0, width, height);
|
||||
}
|
||||
});
|
||||
|
||||
glfwSetScrollCallback(window, new GLFWScrollCallback() {
|
||||
public void invoke(long window, double x, double y) {
|
||||
scrollX = x;
|
||||
scrollY = y;
|
||||
}
|
||||
});
|
||||
|
||||
input = new StringBuilder();
|
||||
glfwSetCharModsCallback(window, new GLFWCharModsCallback() {
|
||||
public void invoke(long window, int key, int mods) {
|
||||
input.append((char) key);
|
||||
}
|
||||
});
|
||||
glfwSetKeyCallback(window, new GLFWKeyCallback() {
|
||||
public void invoke(long window, int key, int scancode, int action, int mods) {
|
||||
if(action != GLFW_RELEASE) {
|
||||
if(glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) != GLFW_PRESS && glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) != GLFW_PRESS && glfwGetKey(window, GLFW_KEY_LEFT_ALT) != GLFW_PRESS && glfwGetKey(window, GLFW_KEY_RIGHT_ALT) != GLFW_PRESS) {
|
||||
switch (key) {
|
||||
case GLFW_KEY_ENTER:
|
||||
input.append((char) 10);
|
||||
break;
|
||||
case GLFW_KEY_BACKSPACE:
|
||||
input.append((char) 8);
|
||||
break;
|
||||
case GLFW_KEY_DELETE:
|
||||
input.append((char) 127);
|
||||
break;
|
||||
case GLFW_KEY_LEFT:
|
||||
input.append((char) 1);
|
||||
break;
|
||||
case GLFW_KEY_RIGHT:
|
||||
input.append((char) 2);
|
||||
break;
|
||||
case GLFW_KEY_UP:
|
||||
input.append((char) 3);
|
||||
break;
|
||||
case GLFW_KEY_DOWN:
|
||||
input.append((char) 4);
|
||||
break;
|
||||
case GLFW_KEY_TAB:
|
||||
input.append((char) 9);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(keys[key] < PRESSED)
|
||||
keys[key] = PRESSED;
|
||||
else
|
||||
keys[key] = HELD;
|
||||
}
|
||||
else {
|
||||
if(keys[key] > RELEASED)
|
||||
keys[key] = RELEASED;
|
||||
else
|
||||
keys[key] = UNPRESSED;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
float vWidth = 0, vHeight = 0;
|
||||
while(vWidth < vidMode.width() && vHeight < vidMode.height()) {
|
||||
vWidth += 1;
|
||||
vHeight += 9 /16f;
|
||||
}
|
||||
|
||||
xOff = (int) ((vidMode.width() - vWidth) / 2);
|
||||
yOff = (int) ((vidMode.height() - vHeight) / 2);
|
||||
this.vWidth = (int) vWidth;
|
||||
this.vHeight = (int) vHeight;
|
||||
bind();
|
||||
|
||||
glClearColor(0, 0, 0, 1);
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
if(keys[i] == PRESSED)
|
||||
++keys[i];
|
||||
else if(keys[i] == RELEASED)
|
||||
--keys[i];
|
||||
}
|
||||
scrollX = 0;
|
||||
scrollY = 0;
|
||||
resized = false;
|
||||
input.delete(0, input.length());
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
public void swap() {
|
||||
glfwSwapBuffers(window);
|
||||
}
|
||||
|
||||
public void setVSync(boolean vSync) {
|
||||
glfwSwapInterval(vSync ? 1 : 0);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
glfwSetWindowShouldClose(window, true);
|
||||
}
|
||||
|
||||
public boolean shouldClose() {
|
||||
return glfwWindowShouldClose(window);
|
||||
}
|
||||
|
||||
public String getInput() {
|
||||
return input.toString();
|
||||
}
|
||||
|
||||
public byte getKey(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] - xOff, (float) y[0] - yOff, 0);
|
||||
ret.mul(camera.getWidth() / vWidth, camera.getHeight() / vHeight, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public boolean mousePressed(int button) {
|
||||
return glfwGetMouseButton(window, button) == GLFW_PRESS;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return vWidth;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return vHeight;
|
||||
}
|
||||
|
||||
public boolean wasResized() {
|
||||
return resized;
|
||||
}
|
||||
|
||||
public float getScrollX() {
|
||||
return (float) scrollX;
|
||||
}
|
||||
|
||||
public float getScrollY() {
|
||||
return (float) scrollY;
|
||||
}
|
||||
|
||||
public void bind() {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glViewport(xOff, yOff, vWidth, vHeight);
|
||||
}
|
||||
}
|
68
src/com/gnarly/engine/model/Vao.java
Normal file
68
src/com/gnarly/engine/model/Vao.java
Normal file
|
@ -0,0 +1,68 @@
|
|||
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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Vao {
|
||||
|
||||
private int numAttribs = 0;
|
||||
|
||||
private int vao, ibo, count;
|
||||
|
||||
private ArrayList<Integer> vbos = new ArrayList<>();
|
||||
|
||||
public Vao(float[] vertices, int[] indices) {
|
||||
vao = glGenVertexArrays();
|
||||
glBindVertexArray(vao);
|
||||
addAttribute(vertices, 3);
|
||||
ibo = glGenBuffers();
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW);
|
||||
count = indices.length;
|
||||
}
|
||||
|
||||
public void addAttribute(float[] data, int size) {
|
||||
int vbo = glGenBuffers();
|
||||
vbos.add(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);
|
||||
}
|
||||
}
|
42
src/com/gnarly/engine/rects/ColRect.java
Normal file
42
src/com/gnarly/engine/rects/ColRect.java
Normal file
|
@ -0,0 +1,42 @@
|
|||
package com.gnarly.engine.rects;
|
||||
|
||||
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;
|
||||
|
||||
private float r, g, b, a;
|
||||
|
||||
public ColRect(Camera camera, float x, float y, float depth, float width, float height, float r, float g, float b, float a) {
|
||||
this.camera = camera;
|
||||
if(vao == null)
|
||||
initVao();
|
||||
position = new Vector3f(x, y, depth);
|
||||
rotation = 0;
|
||||
sx = width / dims.x;
|
||||
sy = height / dims.y;
|
||||
flipX = 1;
|
||||
flipY = 1;
|
||||
shader = Shader.SHADER2C;
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
public void render() {
|
||||
shader.enable();
|
||||
shader.setProjection(camera.getProjection());
|
||||
shader.setView(camera.getView());
|
||||
shader.setModel(new Matrix4f().translate(position).translate(dims.mul(0.5f * sx, 0.5f * sy, 1, new Vector3f())).rotateZ(rotation).scale(sx * flipX, sy * flipY, 1).translate(dims.mul(0.5f, new Vector3f()).negate()));
|
||||
shader.setColor(r, g, b, a);
|
||||
vao.render();
|
||||
shader.disable();
|
||||
}
|
||||
}
|
84
src/com/gnarly/engine/rects/Rect.java
Normal file
84
src/com/gnarly/engine/rects/Rect.java
Normal file
|
@ -0,0 +1,84 @@
|
|||
package com.gnarly.engine.rects;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.model.Vao;
|
||||
|
||||
public abstract class Rect {
|
||||
|
||||
protected static final Vector3f dims = new Vector3f(10, 10, 0);
|
||||
protected static Vao vao = null;
|
||||
|
||||
protected Camera camera;
|
||||
|
||||
protected Vector3f position;
|
||||
protected float rotation;
|
||||
protected float sx, sy;
|
||||
protected byte flipX, flipY;
|
||||
|
||||
protected void initVao() {
|
||||
float[] vertices = new float[] {
|
||||
0, 0, 0.0f,
|
||||
0, dims.y, 0.0f,
|
||||
dims.x, dims.y, 0.0f,
|
||||
dims.x, 0, 0.0f
|
||||
};
|
||||
int[] indices = new int[] {
|
||||
0, 1, 3,
|
||||
3, 1, 2
|
||||
};
|
||||
float[] texCoords = new float[] {
|
||||
0, 0,
|
||||
0, 1,
|
||||
1, 1,
|
||||
1, 0
|
||||
};
|
||||
vao = new Vao(vertices, indices);
|
||||
vao.addAttribute(texCoords, 2);
|
||||
}
|
||||
|
||||
public abstract void render();
|
||||
|
||||
public float getX() {
|
||||
return position.x;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return position.y;
|
||||
}
|
||||
|
||||
public float getWidth() {
|
||||
return sx * dims.x;
|
||||
}
|
||||
|
||||
public float getHeight() {
|
||||
return sy * dims.y;
|
||||
}
|
||||
|
||||
public void setRotation(float angle) {
|
||||
this.rotation = (angle * 3.1415926535f) / 180f;
|
||||
}
|
||||
|
||||
public void setPos(float x, float y) {
|
||||
this.position.x = x;
|
||||
this.position.y = y;
|
||||
}
|
||||
|
||||
public void setSize(float width, float height) {
|
||||
this.sx = width / dims.x;
|
||||
this.sy = height / dims.y;
|
||||
}
|
||||
|
||||
public void setFlip(int x, int y) {
|
||||
this.flipX = (byte) x;
|
||||
this.flipY = (byte) y;
|
||||
}
|
||||
|
||||
public void reset(float x, float y, float width, float height) {
|
||||
this.position.x = x;
|
||||
this.position.y = y;
|
||||
this.sx = width / dims.x;
|
||||
this.sy = height / dims.y;
|
||||
}
|
||||
}
|
94
src/com/gnarly/engine/rects/TexRect.java
Normal file
94
src/com/gnarly/engine/rects/TexRect.java
Normal file
|
@ -0,0 +1,94 @@
|
|||
package com.gnarly.engine.rects;
|
||||
|
||||
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.Shader2a;
|
||||
import com.gnarly.engine.texture.Anim;
|
||||
import com.gnarly.engine.texture.Texture;
|
||||
|
||||
public class TexRect extends Rect {
|
||||
|
||||
private Camera camera;
|
||||
private Texture texture;
|
||||
private Shader shader;
|
||||
|
||||
public TexRect(Camera camera, String texPath, float x, float y, float depth, float width, float height) {
|
||||
this.camera = camera;
|
||||
if(vao == null)
|
||||
initVao();
|
||||
position = new Vector3f(x, y, depth);
|
||||
rotation = 0;
|
||||
sx = width / dims.x;
|
||||
sy = height / dims.y;
|
||||
flipX = 1;
|
||||
flipY = 1;
|
||||
texture = new Texture(texPath);
|
||||
shader = Shader.SHADER2T;
|
||||
}
|
||||
|
||||
public TexRect(Camera camera, String texPath, int frames, int fps, float x, float y, float depth, float width, float height) {
|
||||
this.camera = camera;
|
||||
if(vao == null)
|
||||
initVao();
|
||||
position = new Vector3f(x, y, depth);
|
||||
rotation = 0;
|
||||
sx = width / dims.x;
|
||||
sy = height / dims.y;
|
||||
flipX = 1;
|
||||
flipY = 1;
|
||||
texture = new Anim(texPath, frames, fps);
|
||||
shader = Shader.SHADER2A;
|
||||
}
|
||||
|
||||
public TexRect(Camera camera, Texture texture, float x, float y, float depth, float width, float height) {
|
||||
this.camera = camera;
|
||||
if(vao == null)
|
||||
initVao();
|
||||
position = new Vector3f(x, y, depth);
|
||||
rotation = 0;
|
||||
sx = width / dims.x;
|
||||
sy = height / dims.y;
|
||||
flipX = 1;
|
||||
flipY = 1;
|
||||
this.texture = texture;
|
||||
shader = Shader.SHADER2T;
|
||||
}
|
||||
|
||||
public TexRect(Camera camera, Anim anim, float x, float y, float depth, float width, float height) {
|
||||
this.camera = camera;
|
||||
if(vao == null)
|
||||
initVao();
|
||||
position = new Vector3f(x, y, depth);
|
||||
rotation = 0;
|
||||
sx = width / dims.x;
|
||||
sy = height / dims.y;
|
||||
flipX = 1;
|
||||
flipY = 1;
|
||||
texture = anim;
|
||||
shader = Shader.SHADER2A;
|
||||
}
|
||||
|
||||
public void render() {
|
||||
texture.bind();
|
||||
shader.enable();
|
||||
shader.setProjection(camera.getProjection());
|
||||
shader.setView(camera.getView());
|
||||
shader.setModel(new Matrix4f().translate(position).translate(dims.mul(0.5f * sx, 0.5f * sy, 1, new Vector3f())).rotateZ(rotation).scale(sx * flipX, sy * flipY, 1).translate(dims.mul(0.5f, new Vector3f()).negate()));
|
||||
if(shader instanceof Shader2a)
|
||||
((Shader2a) shader).setAnim((Anim) texture);
|
||||
vao.render();
|
||||
shader.disable();
|
||||
texture.unbind();
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
((Anim) texture).pause();
|
||||
}
|
||||
|
||||
public void setFrame(int frame) {
|
||||
((Anim) texture).setFrame(frame);
|
||||
}
|
||||
}
|
131
src/com/gnarly/engine/shaders/Shader.java
Normal file
131
src/com/gnarly/engine/shaders/Shader.java
Normal file
|
@ -0,0 +1,131 @@
|
|||
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.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 static org.lwjgl.opengl.GL20.glValidateProgram;
|
||||
import static org.lwjgl.opengl.GL32.GL_GEOMETRY_SHADER;
|
||||
|
||||
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 final Shader2a SHADER2A = new Shader2a();
|
||||
public static final Shader2c SHADER2C = new Shader2c();
|
||||
public static final Shader2t SHADER2T = new Shader2t();
|
||||
public static final Shader2x SHADER2X = new Shader2x();
|
||||
|
||||
protected int program;
|
||||
|
||||
protected int projLoc, viewLoc, modelLoc;
|
||||
|
||||
protected Shader(String vertPath, String fragPath) {
|
||||
program = glCreateProgram();
|
||||
|
||||
int vert = load(vertPath, GL_VERTEX_SHADER);
|
||||
int frag = load(fragPath, GL_FRAGMENT_SHADER);
|
||||
|
||||
glAttachShader(program, vert);
|
||||
glAttachShader(program, frag);
|
||||
|
||||
glLinkProgram(program);
|
||||
glValidateProgram(program);
|
||||
|
||||
glDetachShader(program, vert);
|
||||
glDetachShader(program, frag);
|
||||
|
||||
glDeleteShader(vert);
|
||||
glDeleteShader(frag);
|
||||
|
||||
getUniformLocs();
|
||||
}
|
||||
|
||||
protected Shader(String vertPath, String fragPath, String geomPath) {
|
||||
program = glCreateProgram();
|
||||
|
||||
int vert = load(vertPath, GL_VERTEX_SHADER);
|
||||
int frag = load(fragPath, GL_FRAGMENT_SHADER);
|
||||
int geom = load(geomPath, GL_GEOMETRY_SHADER);
|
||||
|
||||
glAttachShader(program, vert);
|
||||
glAttachShader(program, frag);
|
||||
glAttachShader(program, geom);
|
||||
|
||||
glLinkProgram(program);
|
||||
glValidateProgram(program);
|
||||
|
||||
glDetachShader(program, vert);
|
||||
glDetachShader(program, frag);
|
||||
glDetachShader(program, geom);
|
||||
|
||||
glDeleteShader(vert);
|
||||
glDeleteShader(frag);
|
||||
glDeleteShader(geom);
|
||||
|
||||
getUniformLocs();
|
||||
}
|
||||
|
||||
private int load(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 void getUniformLocs() {
|
||||
projLoc = glGetUniformLocation(program, "projection");
|
||||
viewLoc = glGetUniformLocation(program, "view");
|
||||
modelLoc = glGetUniformLocation(program, "model");
|
||||
}
|
||||
|
||||
public void setProjection(Matrix4f projection) {
|
||||
glUniformMatrix4fv(projLoc, false, projection.get(new float[16]));
|
||||
}
|
||||
|
||||
public void setView(Matrix4f view) {
|
||||
glUniformMatrix4fv(viewLoc, false, view.get(new float[16]));
|
||||
}
|
||||
|
||||
public void setModel(Matrix4f model) {
|
||||
glUniformMatrix4fv(modelLoc, false, model.get(new float[16]));
|
||||
}
|
||||
|
||||
public void enable() {
|
||||
glUseProgram(program);
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
glUseProgram(0);
|
||||
}
|
||||
}
|
24
src/com/gnarly/engine/shaders/Shader2a.java
Normal file
24
src/com/gnarly/engine/shaders/Shader2a.java
Normal file
|
@ -0,0 +1,24 @@
|
|||
package com.gnarly.engine.shaders;
|
||||
|
||||
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
|
||||
import static org.lwjgl.opengl.GL20.glUniform2f;
|
||||
|
||||
import com.gnarly.engine.texture.Anim;
|
||||
|
||||
public class Shader2a extends Shader {
|
||||
|
||||
private int animLoc;
|
||||
|
||||
protected Shader2a() {
|
||||
super("res/shaders/s2a/vert.vs", "res/shaders/s2a/frag.fs");
|
||||
}
|
||||
|
||||
protected void getUniformLocs() {
|
||||
super.getUniformLocs();
|
||||
animLoc = glGetUniformLocation(program, "animProps");
|
||||
}
|
||||
|
||||
public void setAnim(Anim anim) {
|
||||
glUniform2f(animLoc, anim.getFrameWidth(), anim.getOffset());
|
||||
}
|
||||
}
|
22
src/com/gnarly/engine/shaders/Shader2c.java
Normal file
22
src/com/gnarly/engine/shaders/Shader2c.java
Normal file
|
@ -0,0 +1,22 @@
|
|||
package com.gnarly.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() {
|
||||
super("res/shaders/s2c/vert.vs", "res/shaders/s2c/frag.fs");
|
||||
}
|
||||
|
||||
protected void getUniformLocs() {
|
||||
super.getUniformLocs();
|
||||
colorLoc = glGetUniformLocation(program, "iColor");
|
||||
}
|
||||
|
||||
public void setColor(float r, float g, float b, float a) {
|
||||
glUniform4f(colorLoc, r, g, b, a);
|
||||
}
|
||||
}
|
8
src/com/gnarly/engine/shaders/Shader2t.java
Normal file
8
src/com/gnarly/engine/shaders/Shader2t.java
Normal file
|
@ -0,0 +1,8 @@
|
|||
package com.gnarly.engine.shaders;
|
||||
|
||||
public class Shader2t extends Shader {
|
||||
|
||||
protected Shader2t() {
|
||||
super("res/shaders/s2t/vert.vs", "res/shaders/s2t/frag.fs");
|
||||
}
|
||||
}
|
30
src/com/gnarly/engine/shaders/Shader2x.java
Normal file
30
src/com/gnarly/engine/shaders/Shader2x.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
package com.gnarly.engine.shaders;
|
||||
|
||||
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
|
||||
import static org.lwjgl.opengl.GL20.glUniform2f;
|
||||
import static org.lwjgl.opengl.GL20.glUniform4f;
|
||||
|
||||
public class Shader2x extends Shader {
|
||||
|
||||
private int charLoc;
|
||||
private int colorLoc;
|
||||
|
||||
protected Shader2x() {
|
||||
super("res/shaders/s2x/vert.vs", "res/shaders/s2x/frag.fs");
|
||||
}
|
||||
|
||||
protected void getUniformLocs() {
|
||||
super.getUniformLocs();
|
||||
colorLoc = glGetUniformLocation(program, "iColor");
|
||||
charLoc = glGetUniformLocation(program, "character");
|
||||
}
|
||||
|
||||
public void setColor(float r, float g, float b, float a) {
|
||||
glUniform4f(colorLoc, r, g, b, a);
|
||||
}
|
||||
|
||||
public void setChar(int character) {
|
||||
int column = character % 16, row = character / 16;
|
||||
glUniform2f(charLoc, (float) column / 16f, (float) row / 16f);
|
||||
}
|
||||
}
|
82
src/com/gnarly/engine/text/Font.java
Normal file
82
src/com/gnarly/engine/text/Font.java
Normal file
|
@ -0,0 +1,82 @@
|
|||
package com.gnarly.engine.text;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.model.Vao;
|
||||
import com.gnarly.engine.shaders.Shader;
|
||||
import com.gnarly.engine.shaders.Shader2x;
|
||||
import com.gnarly.engine.texture.Texture;
|
||||
|
||||
public class Font {
|
||||
|
||||
private final int
|
||||
WIDTH = 5,
|
||||
HEIGHT = 8;
|
||||
|
||||
private Camera camera;
|
||||
private Texture texture;
|
||||
private Shader2x shader;
|
||||
private Vao vao;
|
||||
|
||||
public Font(Camera camera, String fontPath) {
|
||||
this.camera = camera;
|
||||
texture = new Texture(fontPath);
|
||||
shader = Shader.SHADER2X;
|
||||
float[] vertices = new float[] {
|
||||
0, 0, 0,
|
||||
0, HEIGHT, 0,
|
||||
WIDTH, HEIGHT, 0,
|
||||
WIDTH, 0, 0
|
||||
};
|
||||
int[] indices = new int[] {
|
||||
0, 1, 3,
|
||||
3, 1, 2
|
||||
};
|
||||
float[] texCoords = new float[] {
|
||||
0, 0,
|
||||
0, 0.0625f,
|
||||
0.0625f, 0.0625f,
|
||||
0.0625f, 0
|
||||
};
|
||||
vao = new Vao(vertices, indices);
|
||||
vao.addAttribute(texCoords, 2);
|
||||
}
|
||||
|
||||
public void drawString(String string, float x, float y, float depth, float height, float r, float g, float b, float a) {
|
||||
float scale = height / (float) HEIGHT;
|
||||
texture.bind();
|
||||
shader.enable();
|
||||
shader.setProjection(camera.getProjection());
|
||||
shader.setView(camera.getView());
|
||||
shader.setColor(r, g, b, a);
|
||||
char[] chars = string.toCharArray();
|
||||
float lx = x;
|
||||
for (char c : chars) {
|
||||
if(c == '\n') {
|
||||
y += (float) (HEIGHT + 1) * scale;
|
||||
lx = x;
|
||||
}
|
||||
else {
|
||||
if(c != ' ') {
|
||||
shader.setModel(new Matrix4f().translate(lx, y, depth).scale(scale, scale, 0));
|
||||
shader.setChar(c);
|
||||
vao.render();
|
||||
}
|
||||
lx += (float) (WIDTH + 1) * scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float getWidth(float height) {
|
||||
return (height / (float) HEIGHT) * (WIDTH + 1);
|
||||
}
|
||||
|
||||
public float getCharWidth(float height) {
|
||||
return (height / (float) HEIGHT) * WIDTH;
|
||||
}
|
||||
|
||||
public float getHeight(float height) {
|
||||
return (height / (float) HEIGHT) * (HEIGHT + 1);
|
||||
}
|
||||
}
|
57
src/com/gnarly/engine/texture/Anim.java
Normal file
57
src/com/gnarly/engine/texture/Anim.java
Normal file
|
@ -0,0 +1,57 @@
|
|||
package com.gnarly.engine.texture;
|
||||
|
||||
public class Anim extends Texture {
|
||||
|
||||
private final float FRAME_WIDTH;
|
||||
private final long NANO_PER_FRAME;
|
||||
private final int NUM_FRAMES;
|
||||
|
||||
private int curFrame;
|
||||
private long startTime;
|
||||
private boolean playing;
|
||||
|
||||
public Anim(String path, int numFrames, int fps) {
|
||||
super(path);
|
||||
FRAME_WIDTH = 1f / (float) numFrames;
|
||||
NANO_PER_FRAME = 1000000000l / fps;
|
||||
this.curFrame = 0;
|
||||
this.NUM_FRAMES = numFrames;
|
||||
startTime = System.nanoTime();
|
||||
playing = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind() {
|
||||
super.bind();
|
||||
if(playing) {
|
||||
int frame = (int) ((System.nanoTime() - startTime) / NANO_PER_FRAME);
|
||||
curFrame = frame % NUM_FRAMES;
|
||||
}
|
||||
}
|
||||
|
||||
public void play() {
|
||||
startTime = System.nanoTime();
|
||||
playing = true;
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
playing = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return width / NUM_FRAMES;
|
||||
}
|
||||
|
||||
public float getFrameWidth() {
|
||||
return FRAME_WIDTH;
|
||||
}
|
||||
|
||||
public float getOffset() {
|
||||
return FRAME_WIDTH * curFrame;
|
||||
}
|
||||
|
||||
public void setFrame(int frame) {
|
||||
curFrame = frame;
|
||||
}
|
||||
}
|
83
src/com/gnarly/engine/texture/Texture.java
Normal file
83
src/com/gnarly/engine/texture/Texture.java
Normal file
|
@ -0,0 +1,83 @@
|
|||
package com.gnarly.engine.texture;
|
||||
|
||||
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 {
|
||||
|
||||
protected int id, width, height;
|
||||
|
||||
public Texture(String fileName) {
|
||||
try {
|
||||
BufferedImage bi = ImageIO.read(new File(fileName));
|
||||
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();
|
||||
|
||||
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 Texture(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
116
src/com/gnarly/game/GamePanel.java
Normal file
116
src/com/gnarly/game/GamePanel.java
Normal file
|
@ -0,0 +1,116 @@
|
|||
package com.gnarly.game;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.display.Window;
|
||||
import com.gnarly.engine.rects.ColRect;
|
||||
import com.gnarly.engine.rects.TexRect;
|
||||
import com.gnarly.engine.text.Font;
|
||||
import com.gnarly.game.board.Map;
|
||||
import com.gnarly.game.objs.Button;
|
||||
import com.gnarly.game.text.Console;
|
||||
import com.gnarly.game.text.EditorManager;
|
||||
import com.gnarly.game.text.TextBox;
|
||||
|
||||
public class GamePanel {
|
||||
|
||||
private Window window;
|
||||
private Camera camera;
|
||||
|
||||
private Map map;
|
||||
private EditorManager editor;
|
||||
private Button run, stop, menu;
|
||||
private TexRect header;
|
||||
|
||||
private TextBox background;
|
||||
private ColRect darkener;
|
||||
private Button next, smenu;
|
||||
private Font font;
|
||||
|
||||
private boolean success;
|
||||
private int level = 1;
|
||||
private int max;
|
||||
|
||||
private int state = 1;
|
||||
|
||||
public GamePanel(Window window, Camera camera) {
|
||||
max = new File("res/maps").list().length;
|
||||
this.window = window;
|
||||
this.camera = camera;
|
||||
|
||||
map = new Map(camera, "res/maps/level1.llm");
|
||||
editor = new EditorManager(window, camera);
|
||||
run = new Button(window, camera, "res/img/map/buttons/run/unpressed.png", "res/img/map/buttons/run/hovered.png", "res/img/map/buttons/run/pressed.png", 0, 324, 0, 75, 24);
|
||||
stop = new Button(window, camera, "res/img/map/buttons/stop/unpressed.png", "res/img/map/buttons/stop/hovered.png", "res/img/map/buttons/stop/pressed.png", 76, 324, 0, 76, 24);
|
||||
menu = new Button(window, camera, "res/img/map/buttons/menu/unpressed.png", "res/img/map/buttons/menu/hovered.png", "res/img/map/buttons/menu/pressed.png", 153, 324, 0, 75, 24);
|
||||
header = new TexRect(camera, "res/img/header.png", 0, 0, 0, 228, 32);
|
||||
|
||||
background = new TextBox(camera, "", 220, 100, -0.5f, 200, 100, 24);
|
||||
darkener = new ColRect(camera, 0, 0, -0.25f, 640, 360, 0, 0, 0, 0.5f);
|
||||
next = new Button(window, camera, "res/img/menu/next/unpressed.png", "res/img/menu/next/hovered.png", "res/img/menu/next/pressed.png", 362, 182, -0.75f, 16, 16);
|
||||
smenu = new Button(window, camera, "res/img/map/buttons/smenu/unpressed.png", "res/img/map/buttons/smenu/hovered.png", "res/img/map/buttons/smenu/pressed.png", 262, 182, -0.75f, 16, 16);
|
||||
font = new Font(camera, "res/img/fonts/default.png");
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if(!success) {
|
||||
editor.update();
|
||||
map.update();
|
||||
run.update();
|
||||
stop.update();
|
||||
menu.update();
|
||||
if(run.getState() == Button.RELEASED) {
|
||||
Console.error.clear();
|
||||
map.execute(editor.getCommands());
|
||||
}
|
||||
else if(stop.getState() == Button.RELEASED)
|
||||
map.fullStop();
|
||||
else if(menu.getState() == Button.RELEASED)
|
||||
state = 0;
|
||||
success = map.success();
|
||||
if(success) {
|
||||
++level;
|
||||
if(level > max)
|
||||
level = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
next.update();
|
||||
smenu.update();
|
||||
if(next.getState() == Button.RELEASED) {
|
||||
map = new Map(camera, "res/maps/level" + level + ".llm");
|
||||
editor = new EditorManager(window, camera);
|
||||
success = false;
|
||||
}
|
||||
else if(smenu.getState() == Button.RELEASED) {
|
||||
map = new Map(camera, "res/maps/level" + level + ".llm");
|
||||
editor = new EditorManager(window, camera);
|
||||
success = false;
|
||||
state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void render() {
|
||||
header.render();
|
||||
run.render();
|
||||
stop.render();
|
||||
menu.render();
|
||||
map.render();
|
||||
editor.render();
|
||||
if(success) {
|
||||
font.drawString("SUCCESS!", (640 - font.getWidth(24) * 7 - font.getCharWidth(24)) / 2, 106, -0.75f, 24, 1, 1, 1, 1);
|
||||
darkener.render();
|
||||
background.render();
|
||||
next.render();
|
||||
smenu.render();
|
||||
}
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
int temp = state;
|
||||
state = 1;
|
||||
return temp;
|
||||
}
|
||||
}
|
90
src/com/gnarly/game/Main.java
Normal file
90
src/com/gnarly/game/Main.java
Normal file
|
@ -0,0 +1,90 @@
|
|||
package com.gnarly.game;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.display.Window;
|
||||
|
||||
public class Main implements Runnable {
|
||||
|
||||
public static final int BIG_TICK = 8;
|
||||
|
||||
private final int TICK_RATE = 64;
|
||||
private final int FPS = 59;
|
||||
|
||||
public static int tick = 0;
|
||||
public static int fps = 0;
|
||||
|
||||
private int state;
|
||||
|
||||
private Window window;
|
||||
private Camera camera;
|
||||
private MenuPanel menu;
|
||||
private GamePanel panel;
|
||||
|
||||
public void start() {
|
||||
Thread gameLoop = new Thread(this, "OpenGL");
|
||||
gameLoop.start();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
long pastTime, curTime, npf = 1000000000 / FPS, pastSec, pastUTime, npt = 1000000000 / TICK_RATE;
|
||||
int frames = 0;
|
||||
init();
|
||||
pastTime = System.nanoTime();
|
||||
pastUTime = pastTime;
|
||||
pastSec = pastTime;
|
||||
while(!window.shouldClose()) {
|
||||
curTime = System.nanoTime();
|
||||
while(curTime - pastUTime >= npt) {
|
||||
update();
|
||||
pastUTime += npt;
|
||||
++tick;
|
||||
}
|
||||
curTime = System.nanoTime();
|
||||
if(curTime - pastTime > npf) {
|
||||
render();
|
||||
pastTime += npf;
|
||||
++frames;
|
||||
}
|
||||
if(curTime - pastSec >= 1000000000) {
|
||||
fps = frames;
|
||||
frames = 0;
|
||||
pastSec += 1000000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
state = 0;
|
||||
window = new Window(false);
|
||||
camera = new Camera(640, 360);
|
||||
menu = new MenuPanel(window, camera);
|
||||
panel = new GamePanel(window, camera);
|
||||
window.bind();
|
||||
}
|
||||
|
||||
private void update() {
|
||||
window.update();
|
||||
if(state == 0) {
|
||||
menu.update();
|
||||
state = menu.getState();
|
||||
}
|
||||
else {
|
||||
panel.update();
|
||||
state = panel.getState();
|
||||
}
|
||||
}
|
||||
|
||||
private void render() {
|
||||
window.clear();
|
||||
if(state == 0)
|
||||
menu.render();
|
||||
else
|
||||
panel.render();
|
||||
window.bind();
|
||||
window.swap();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
new Main().start();
|
||||
}
|
||||
}
|
104
src/com/gnarly/game/MenuPanel.java
Normal file
104
src/com/gnarly/game/MenuPanel.java
Normal file
|
@ -0,0 +1,104 @@
|
|||
package com.gnarly.game;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.display.Window;
|
||||
import com.gnarly.engine.rects.TexRect;
|
||||
import com.gnarly.engine.text.Font;
|
||||
import com.gnarly.game.objs.Button;
|
||||
|
||||
public class MenuPanel {
|
||||
|
||||
private Window window;
|
||||
private Camera camera;
|
||||
|
||||
private Font font;
|
||||
|
||||
private Button play, help, close, next, prev;
|
||||
|
||||
private TexRect background;
|
||||
private TexRect helpMenu;
|
||||
|
||||
private int state = 0, page = 0;
|
||||
private boolean showHelp = false;
|
||||
private String[] headers, content;
|
||||
|
||||
|
||||
public MenuPanel(Window window, Camera camera) {
|
||||
this.window = window;
|
||||
this.camera = camera;
|
||||
font = new Font(camera, "res/img/fonts/default.png");
|
||||
background = new TexRect(camera, "res/img/menu/background.png", 0, 0, 0, 640, 360);
|
||||
play = new Button(window, camera, "res/img/menu/play/unpressed.png", "res/img/menu/play/hovered.png", "res/img/menu/play/pressed.png", 260, 160, 0, 120, 32);
|
||||
help = new Button(window, camera, "res/img/menu/help/unpressed.png", "res/img/menu/help/hovered.png", "res/img/menu/help/pressed.png", 260, 200, 0, 120, 32);
|
||||
close = new Button(window, camera, "res/img/menu/close/unpressed.png", "res/img/menu/close/hovered.png", "res/img/menu/close/pressed.png", 384, 110, 0, 16, 16);
|
||||
next = new Button(window, camera, "res/img/menu/next/unpressed.png", "res/img/menu/next/hovered.png", "res/img/menu/next/pressed.png", 384, 264, 0, 16, 16);
|
||||
prev = new Button(window, camera, "res/img/menu/prev/unpressed.png", "res/img/menu/prev/hovered.png", "res/img/menu/prev/pressed.png", 240, 264, 0, 16, 16);
|
||||
helpMenu = new TexRect(camera, "res/img/menu/help/helpMenu.png", 240, 110, 0, 160, 170);
|
||||
headers = new String[8];
|
||||
headers[0] = "OVERVIEW";
|
||||
headers[1] = "GOAL";
|
||||
headers[2] = "PROGRAMMING";
|
||||
headers[3] = "FIRE";
|
||||
headers[4] = "ROTATE";
|
||||
headers[5] = "WAIT";
|
||||
headers[6] = "THREADS";
|
||||
headers[7] = "TIMING";
|
||||
content = new String[8];
|
||||
content[0] = "SO WHAT THE HECK IS THIS GAME?\n\nWELL BASICALLY ITS A PROGRAMMING\nGAME IN WHICH THE PLAYER CONTROLS\nMIRRORS IN ORDER TO DIRECT A LASER TO\nA TRIGGER.";
|
||||
content[1] = "THE GOAL OF THE GAME IS TO BEAT\nALL THE LEVELS. THE EXACT GOAL\nOF EACH LEVEL VARIES BUT THE GOAL\nIS ALWAYS ABOUT TRIGGERING A TRIGGER\nWITH A LASER. WHICH TRIGGER AND AT\nWHAT TIMES ARE LEVEL SPECIFIC.\nTHE BOX AT THE TOP WILL TELL\nYOU THE GOAL FOR THAT LEVEL";
|
||||
content[2] = "TO CONTROL THE GAME BOARD YOU USE THE\nPROGRAMMING INTRFACE ON THE LEFT.\n\nTHERE ARE THREE COMMANDS YOU CAN USE.\n\n- FIRE\n- ROTATE\n- WAIT";
|
||||
content[3] = "THE FIRE COMMAND DOES EXACTLY WHAT\nIT SAYS. IT FIRES A LASER.\n\nUSAGE:\n\nFIRE X\n\n - X IS THE X COMPONENT OF\n THE LOCATION OF THE\n CANNON YOU WANT TO FIRE.";
|
||||
content[4] = "THE ROTATE COMMAND ROTATES A MIRROR\n90 DEGREES.\n\nUSAGE:\n\nROTATE X Y\n\n - X IS THE X COMPONENT OF\n THE LOCATION OF THE\n THE MIRROR YOU WANT ROTATED\n\n - Y IS THE Y COMPONENT OF\n THE LOCATION OF THE\n THE MIRROR YOU WANT ROTATED";
|
||||
content[5] = "THE WAIT COMMAND PAUSES THE CURRENT\nTHREAD FOR A CERTAIN NUMBER FO TICKS.\n\nUSAGE:\n\nWAIT X\n\n - X IS THE NUMBER OF TICKS\n YOU WANT THE THREAD TO PAUSE";
|
||||
content[6] = "YOU HAVE FOUR THREADS AT YOUR DISPOAL.\nEACH THREAD CAN ONLY HOUSE A\nCERTAIN NUMBER OF COMMANDS.\nTHE MAIN ADVANTAGE OF MUTIPLE THREADS\nIS IT ALLOWS YOU TO RUN MUTIPLE\nCOMMANDS SIMULTANEOUSLY.";
|
||||
content[7] = "THE WHOLE GAME RUNS ON A SYSTEM\nOF TICKS. EACH TICK IS 1/16TH\nOF A SECOND. DURING ONE TICK\nONE COMMAND FROM EACH THREAD\nIS EXECUTED.";
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if(!showHelp) {
|
||||
play.update();
|
||||
help.update();
|
||||
if(play.getState() == Button.RELEASED)
|
||||
state = 1;
|
||||
else if(help.getState() == Button.RELEASED)
|
||||
showHelp = true;
|
||||
}
|
||||
else {
|
||||
close.update();
|
||||
next.update();
|
||||
prev.update();
|
||||
if(close.getState() == Button.RELEASED) {
|
||||
page = 0;
|
||||
showHelp = false;
|
||||
}
|
||||
else if(next.getState() == Button.RELEASED && page < headers.length - 1)
|
||||
++page;
|
||||
else if(prev.getState() == Button.RELEASED && page > 0)
|
||||
--page;
|
||||
}
|
||||
}
|
||||
|
||||
public void render() {
|
||||
if(!showHelp) {
|
||||
play.render();
|
||||
help.render();
|
||||
}
|
||||
else {
|
||||
close.render();
|
||||
next.render();
|
||||
prev.render();
|
||||
String pageString = "[" + (page + 1) + "/" + headers.length + "]";
|
||||
font.drawString(pageString, (640 - (pageString.length() * 5 + pageString.length() - 1)) / 2, 269, 0, 8, 1, 1, 1, 1);
|
||||
font.drawString(headers[page], 243, 113, 0, 16, 1, 1, 1, 1);
|
||||
font.drawString(content[page], 243, 136, 0, 5.3333333333f, 1, 1, 1, 1);
|
||||
helpMenu.render();
|
||||
}
|
||||
background.render();
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
int temp = state;
|
||||
state = 0;
|
||||
return temp;
|
||||
}
|
||||
}
|
308
src/com/gnarly/game/board/Map.java
Normal file
308
src/com/gnarly/game/board/Map.java
Normal file
|
@ -0,0 +1,308 @@
|
|||
package com.gnarly.game.board;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Scanner;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.rects.TexRect;
|
||||
import com.gnarly.game.Main;
|
||||
import com.gnarly.game.board.laser.Cannon;
|
||||
import com.gnarly.game.board.laser.Laser;
|
||||
import com.gnarly.game.board.laser.Trigger;
|
||||
import com.gnarly.game.commands.Command;
|
||||
import com.gnarly.game.commands.Fire;
|
||||
import com.gnarly.game.commands.Rotate;
|
||||
import com.gnarly.game.commands.Wait;
|
||||
import com.gnarly.game.text.Console;
|
||||
import com.gnarly.game.text.TextBox;
|
||||
|
||||
public class Map {
|
||||
|
||||
public static final int
|
||||
EMPTY = 0,
|
||||
M45 = 1,
|
||||
M135 = 2,
|
||||
CANNON = 3,
|
||||
TRIGGER = 4;
|
||||
|
||||
private static final int
|
||||
OFFSET = 14,
|
||||
WIDTH = 32,
|
||||
HEIGHT = 32,
|
||||
COLUMNS = 12,
|
||||
ROWS = 10;
|
||||
|
||||
private String mapPath;
|
||||
|
||||
private Console console;
|
||||
|
||||
private Camera camera;
|
||||
private TexRect[] states;
|
||||
private int map[][];
|
||||
|
||||
private TexRect topbar, leftbar;
|
||||
private TexRect[] corners, nums;
|
||||
|
||||
private float x, y;
|
||||
|
||||
private TextBox ghead, goals;
|
||||
|
||||
private ArrayList<Laser> lasers;
|
||||
private ArrayList<Cannon> cannons;
|
||||
private ArrayList<Trigger> triggers;
|
||||
|
||||
private boolean execute, lastRan;
|
||||
private ArrayList<Command>[] commands;
|
||||
|
||||
private boolean success = false;
|
||||
|
||||
public Map(Camera camera, String mapPath) {
|
||||
this.mapPath = mapPath;
|
||||
this.camera = camera;
|
||||
this.x = camera.getWidth() - getWidth();
|
||||
this.y = 0;
|
||||
ghead = new TextBox(camera, "GOALS\nTRIG |TICK", 182, 33, 0, 46, 15, 5.3333333f);
|
||||
goals = new TextBox(camera, "", 182, 49, 0, 46, 185, 5.3333333f);
|
||||
map = new int[COLUMNS][ROWS];
|
||||
states = new TexRect[5];
|
||||
states[EMPTY] = new TexRect(camera, "res/img/map/empty.png", 0, 0, 0, 32, 32);
|
||||
states[M45] = new TexRect(camera, "res/img/map/mirror45.png", 0, 0, 0, 32, 32);
|
||||
states[M135] = new TexRect(camera, "res/img/map/mirror135.png", 0, 0, 0, 32, 32);
|
||||
states[CANNON] = new TexRect(camera, "res/img/map/cannon.png", 10, 8, 0, 0, 0, 32, 32);
|
||||
states[TRIGGER] = new TexRect(camera, "res/img/map/trigger.png", 32, 32, 0, 0, 0, 32, 32);
|
||||
states[TRIGGER].pause();
|
||||
corners = new TexRect[4];
|
||||
corners[0] = new TexRect(camera, "res/img/bars/tlcorner.png", x, y, 0, OFFSET, OFFSET);
|
||||
corners[1] = new TexRect(camera, "res/img/bars/blcorner.png", x, y + getHeight() - OFFSET, 0, OFFSET, OFFSET);
|
||||
corners[2] = new TexRect(camera, "res/img/bars/brcorner.png", x + getWidth()- OFFSET, y + getHeight() - OFFSET, 0, OFFSET, OFFSET);
|
||||
corners[3] = new TexRect(camera, "res/img/bars/trcorner.png", x + getWidth()- OFFSET, y, 0, OFFSET, OFFSET);
|
||||
topbar = new TexRect(camera, "res/img/bars/topbar.png", 0, 0, 0, WIDTH, OFFSET);
|
||||
leftbar = new TexRect(camera, "res/img/bars/leftbar.png", 0, 0, 0, OFFSET, HEIGHT);
|
||||
lasers = new ArrayList<>();
|
||||
cannons = new ArrayList<>();
|
||||
triggers = new ArrayList<>();
|
||||
nums = new TexRect[12];
|
||||
for (int i = 0; i < nums.length; i++)
|
||||
nums[i] = new TexRect(camera, "res/img/bars/numbers/" + i + ".png", 0, 0, 0, 8, 8);
|
||||
loadMap();
|
||||
console = new Console(camera);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if(Main.tick % Main.BIG_TICK == 0) {
|
||||
boolean ran = false;
|
||||
if(execute || lasers.size() > 0) {
|
||||
ran = true;
|
||||
if(commands != null) {
|
||||
String[] commandStrings = new String[4];
|
||||
for (int i = 0; i < commandStrings.length; i++)
|
||||
commandStrings[i] = new String();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if(commands[i].size() > 0) {
|
||||
commandStrings[i] = commands[i].get(0).getCommand();
|
||||
Command command = commands[i].get(0);
|
||||
if(command instanceof Wait) {
|
||||
Wait wait = (Wait) command;
|
||||
wait.decrement();
|
||||
if(wait.getTicks() == 0)
|
||||
commands[i].remove(0);
|
||||
}
|
||||
else if(command instanceof Rotate) {
|
||||
Rotate rotate = (Rotate) command;
|
||||
int x = rotate.getX();
|
||||
int y = rotate.getY() + 1;
|
||||
if(map[x][y] == M45)
|
||||
map[x][y] = M135;
|
||||
else if(map[x][y] == M135)
|
||||
map[x][y] = M45;
|
||||
else {
|
||||
Console.error.add("LOCATION " + x + " " + y + " IS NOT A MIRROR");
|
||||
execute = false;
|
||||
}
|
||||
commands[i].remove(0);
|
||||
}
|
||||
else if(command instanceof Fire) {
|
||||
Fire fire = (Fire) command;
|
||||
fire(fire.getCannon());
|
||||
commands[i].remove(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
int num = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
if(commands[i].size() > 0)
|
||||
++num;
|
||||
if(num == 0) {
|
||||
commands = null;
|
||||
execute = false;
|
||||
}
|
||||
console.printCommands(commandStrings);
|
||||
}
|
||||
}
|
||||
if(!ran && lastRan) {
|
||||
for (int i = 0; i < triggers.size(); i++) {
|
||||
triggers.get(i).update();
|
||||
if(!triggers.get(i).success())
|
||||
Console.error.add("FAILED TO MEET ALL TRIGGER CONDITIONS!");
|
||||
}
|
||||
if(Console.error.size() == 0)
|
||||
success = true;
|
||||
for (int i = 0; i < triggers.size(); i++)
|
||||
triggers.get(i).reset();
|
||||
fullStop();
|
||||
}
|
||||
lastRan = ran;
|
||||
}
|
||||
for (int i = 0; i < lasers.size(); i++)
|
||||
lasers.get(i).update();
|
||||
for (int i = 0; i < lasers.size(); i++)
|
||||
if(lasers.get(i).done())
|
||||
lasers.remove(i);
|
||||
if(execute || lasers.size() > 0)
|
||||
for (int i = 0; i < triggers.size(); i++)
|
||||
triggers.get(i).update();
|
||||
}
|
||||
|
||||
public void render() {
|
||||
ghead.render();
|
||||
goals.render();
|
||||
console.render();
|
||||
for (int i = 0; i < lasers.size(); i++)
|
||||
lasers.get(i).render();
|
||||
for (int i = 0; i < corners.length; i++)
|
||||
corners[i].render();
|
||||
for (int i = 0; i < map.length; i++) {
|
||||
nums[i].setPos(x + i * WIDTH + OFFSET + 12, y + 3);
|
||||
nums[i].render();
|
||||
topbar.setPos(x + i * WIDTH + OFFSET, y);
|
||||
topbar.render();
|
||||
nums[i].setPos(x + i * WIDTH + OFFSET + 12, y + getHeight() - OFFSET + 3);
|
||||
nums[i].render();
|
||||
topbar.setPos(x + i * WIDTH + OFFSET, y + getHeight() - OFFSET);
|
||||
topbar.render();
|
||||
}
|
||||
for (int i = 0; i < map[0].length; i++) {
|
||||
if (i > 0 && i < map[0].length - 1) {
|
||||
nums[i - 1].setPos(x + 3, y + i * HEIGHT + OFFSET + 12);
|
||||
nums[i - 1].render();
|
||||
nums[i - 1].setPos(x + getWidth() - OFFSET + 3, y + i * HEIGHT + OFFSET + 12);
|
||||
nums[i - 1].render();
|
||||
}
|
||||
leftbar.setPos(x, y + i * HEIGHT + OFFSET);
|
||||
leftbar.render();
|
||||
leftbar.setPos(x + getWidth() - OFFSET, y + i * HEIGHT + OFFSET);
|
||||
leftbar.render();
|
||||
}
|
||||
for (int i = 0; i < map.length; i++) {
|
||||
for (int j = 0; j < map[0].length; j++) {
|
||||
int state = map[i][j];
|
||||
if(state != TRIGGER) {
|
||||
states[state].setPos(x + i * WIDTH + OFFSET, y + j * HEIGHT + OFFSET);
|
||||
states[state].render();
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < triggers.size(); i++) {
|
||||
Trigger trigger = triggers.get(i);
|
||||
states[TRIGGER].setFrame(trigger.getFrame());
|
||||
states[TRIGGER].setPos(x + trigger.getX() * WIDTH + OFFSET, y + trigger.getY() * HEIGHT + OFFSET);
|
||||
states[TRIGGER].render();
|
||||
}
|
||||
}
|
||||
|
||||
public static float getWidth() {
|
||||
return WIDTH * COLUMNS + OFFSET * 2;
|
||||
}
|
||||
|
||||
public static float getHeight() {
|
||||
return HEIGHT * ROWS + OFFSET * 2;
|
||||
}
|
||||
|
||||
private void fire(int cannonNum) {
|
||||
Cannon cannon = null;
|
||||
for (int i = 0; i < cannons.size() && cannon == null; i++) {
|
||||
if(cannons.get(i).getX() == cannonNum)
|
||||
cannon = cannons.get(i);
|
||||
}
|
||||
if(cannon == null)
|
||||
Console.error.add("NO CANNON AT POSITION " + cannonNum + "!");
|
||||
else {
|
||||
int x = cannon.getX();
|
||||
int y = cannon.getY();
|
||||
Vector3f dir = cannon.getDir();
|
||||
x += dir.x;
|
||||
y += dir.y;
|
||||
lasers.add(new Laser(camera, dir, this.x + OFFSET, this.y + OFFSET, x, y, map, triggers));
|
||||
}
|
||||
}
|
||||
|
||||
private void loadMap() {
|
||||
Scanner scanner = null;
|
||||
try {
|
||||
triggers.clear();
|
||||
cannons.clear();
|
||||
scanner = new Scanner(new File(mapPath));
|
||||
for (int j = 0; j < this.map[0].length; j++) {
|
||||
for (int i = 0; i < this.map.length; i++) {
|
||||
this.map[i][j] = scanner.nextInt();
|
||||
if(this.map[i][j] == CANNON)
|
||||
cannons.add(new Cannon(i, j, Laser.UP));
|
||||
if(this.map[i][j] == TRIGGER)
|
||||
triggers.add(new Trigger(i, j));
|
||||
}
|
||||
}
|
||||
int numGoals = scanner.nextInt();
|
||||
String goals = new String();
|
||||
for (int i = 0; i < numGoals; i++) {
|
||||
String curGoal = new String();
|
||||
int trigger = scanner.nextInt();
|
||||
int tickNum = scanner.nextInt();
|
||||
curGoal += triggers.get(trigger).getX();
|
||||
while(curGoal.length() < 4)
|
||||
curGoal += ' ';
|
||||
curGoal += " |";
|
||||
curGoal += tickNum + "\n";
|
||||
goals += curGoal;
|
||||
triggers.get(trigger).addCondition(tickNum);
|
||||
}
|
||||
this.goals.setText(goals);
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
scanner.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void execute(ArrayList<Command>[] commands) {
|
||||
if(Console.error.size() == 0) {
|
||||
lasers.clear();
|
||||
console.clear();
|
||||
execute = true;
|
||||
this.commands = commands;
|
||||
}
|
||||
}
|
||||
|
||||
public void fullStop() {
|
||||
loadMap();
|
||||
lasers.clear();
|
||||
execute = false;
|
||||
commands = null;
|
||||
}
|
||||
|
||||
public void setMap(String mapPath) {
|
||||
this.mapPath = mapPath;
|
||||
loadMap();
|
||||
}
|
||||
|
||||
public int[][] getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
public boolean success() {
|
||||
return success;
|
||||
}
|
||||
}
|
27
src/com/gnarly/game/board/laser/Cannon.java
Normal file
27
src/com/gnarly/game/board/laser/Cannon.java
Normal file
|
@ -0,0 +1,27 @@
|
|||
package com.gnarly.game.board.laser;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
public class Cannon {
|
||||
|
||||
int x, y;
|
||||
Vector3f dir;
|
||||
|
||||
public Cannon(int x, int y, Vector3f dir) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.dir = dir;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public Vector3f getDir() {
|
||||
return dir;
|
||||
}
|
||||
}
|
182
src/com/gnarly/game/board/laser/Laser.java
Normal file
182
src/com/gnarly/game/board/laser/Laser.java
Normal file
|
@ -0,0 +1,182 @@
|
|||
package com.gnarly.game.board.laser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.rects.TexRect;
|
||||
import com.gnarly.engine.texture.Anim;
|
||||
import com.gnarly.game.Main;
|
||||
import com.gnarly.game.board.Map;
|
||||
|
||||
public class Laser {
|
||||
|
||||
public static final Vector3f
|
||||
UP = new Vector3f(0, -1, 0),
|
||||
DOWN = new Vector3f(0, 1, 0),
|
||||
LEFT = new Vector3f(-1, 0, 0),
|
||||
RIGHT = new Vector3f(1, 0, 0);
|
||||
|
||||
private final int
|
||||
STRAIGHT = 0,
|
||||
BEND = 1,
|
||||
TRIGGER = 2,
|
||||
SOLID = 3;
|
||||
|
||||
private Anim[] fanims;
|
||||
private TexRect[] frects;
|
||||
private Anim[] banims;
|
||||
private TexRect[] brects;
|
||||
|
||||
private float startX, startY;
|
||||
|
||||
private int fx, fy, ftype, frame;
|
||||
private int[] props;
|
||||
private Vector3f fdir;
|
||||
|
||||
private int bx, by, btype;
|
||||
|
||||
private boolean renderFront, renderBack;
|
||||
|
||||
private ArrayList<Trigger> triggers;
|
||||
private int[][] map;
|
||||
|
||||
public Laser(Camera camera, Vector3f dir, float startX, float startY, int x, int y, int[][] map, ArrayList<Trigger> triggers) {
|
||||
this.startX = startX;
|
||||
this.startY = startY;
|
||||
bx = 0;
|
||||
by = 0;
|
||||
fx = x;
|
||||
fy = y;
|
||||
fdir = dir;
|
||||
this.map = map;
|
||||
this.triggers = triggers;
|
||||
renderFront = true;
|
||||
renderBack = false;
|
||||
initAnims(camera);
|
||||
}
|
||||
|
||||
private void initAnims(Camera camera) {
|
||||
banims = new Anim[2];
|
||||
banims[0] = new Anim("res/img/map/laser/laserStraightBack.png", 32, 64);
|
||||
banims[1] = new Anim("res/img/map/laser/laserBendBack.png", 32, 64);
|
||||
brects = new TexRect[2];
|
||||
brects[STRAIGHT] = new TexRect(camera, banims[0], 0, 0, 0, 32, 32);
|
||||
brects[BEND] = new TexRect(camera, banims[1], 0, 0, 0, 32, 32);
|
||||
for (int i = 0; i < banims.length; i++)
|
||||
banims[i].pause();
|
||||
fanims = new Anim[2];
|
||||
fanims[0] = new Anim("res/img/map/laser/laserStraight.png", 32, 64);
|
||||
fanims[1] = new Anim("res/img/map/laser/laserBend.png", 32, 64);
|
||||
frects = new TexRect[2];
|
||||
frects[STRAIGHT] = new TexRect(camera, fanims[0], 0, 0, 0, 32, 32);
|
||||
frects[BEND] = new TexRect(camera, fanims[1], 0, 0, 0, 32, 32);
|
||||
for (int i = 0; i < fanims.length; i++)
|
||||
fanims[i].pause();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
frame = Main.tick % Main.BIG_TICK * (32 / Main.BIG_TICK);
|
||||
if(frame == 0) {
|
||||
if(bx < 0 || by < 0 || bx >= map.length || by >= map[0].length || getType(bx, by) >= TRIGGER)
|
||||
renderBack = false;
|
||||
else if(props != null) {
|
||||
btype = ftype;
|
||||
brects[btype].setPos(startX + bx * 32, startY + by * 32);
|
||||
brects[btype].setRotation(props[0]);
|
||||
brects[btype].setFlip(1, props[1]);
|
||||
renderBack = true;
|
||||
}
|
||||
if(fx < 0 || fy < 0 || fx >= map.length || fy >= map[0].length || getType(fx, fy) == SOLID)
|
||||
renderFront = false;
|
||||
else if(getType(fx, fy) == TRIGGER) {
|
||||
for (int i = 0; i < triggers.size(); i++) {
|
||||
if(triggers.get(i).getX() == fx && triggers.get(i).getY() == fy)
|
||||
triggers.get(i).trigger();
|
||||
}
|
||||
renderFront = false;
|
||||
}
|
||||
else {
|
||||
ftype = getType(fx, fy);
|
||||
props = getProps(fx, fy, fdir);
|
||||
frects[ftype].setPos(startX + fx * 32, startY + fy * 32);
|
||||
frects[ftype].setRotation(props[0]);
|
||||
frects[ftype].setFlip(1, props[1]);
|
||||
fdir = getDir(fx, fy, fdir);
|
||||
}
|
||||
bx = fx;
|
||||
by = fy;
|
||||
fx += fdir.x;
|
||||
fy += fdir.y;
|
||||
}
|
||||
}
|
||||
|
||||
private int getType(int x, int y) {
|
||||
if(map[x][y] == 0)
|
||||
return STRAIGHT;
|
||||
else if(map[x][y] >= 1 && map[x][y] <= 2)
|
||||
return BEND;
|
||||
else if(map[x][y] == 4)
|
||||
return TRIGGER;
|
||||
else
|
||||
return SOLID;
|
||||
}
|
||||
|
||||
private int[] getProps(int x, int y, Vector3f dir) {
|
||||
if((dir.x == 1 && dir.y == 0 && map[x][y] == Map.M45))
|
||||
return new int[] {0, 1};
|
||||
else if((dir.x == 1 && dir.y == 0 && map[x][y] == Map.M135))
|
||||
return new int[] {0, -1};
|
||||
else if((dir.x == 1 && dir.y == 0 && map[x][y] == Map.EMPTY))
|
||||
return new int[] {90, 1};
|
||||
else if((dir.x == -1 && dir.y == 0 && map[x][y] == Map.M45))
|
||||
return new int[] {180, 1};
|
||||
else if((dir.x == -1 && dir.y == 0 && map[x][y] == Map.M135))
|
||||
return new int[] {180, -1};
|
||||
else if((dir.x == -1 && dir.y == 0 && map[x][y] == Map.EMPTY))
|
||||
return new int[] {90, -1};
|
||||
else if((dir.x == 0 && dir.y == 1 && map[x][y] == Map.M45))
|
||||
return new int[] {90, -1};
|
||||
else if((dir.x == 0 && dir.y == 1 && map[x][y] == Map.M135))
|
||||
return new int[] {90, 1};
|
||||
else if((dir.x == 0 && dir.y == 1 && map[x][y] == Map.EMPTY))
|
||||
return new int[] {0, -1};
|
||||
else if((dir.x == 0 && dir.y == -1 && map[x][y] == Map.M45))
|
||||
return new int[] {270, -1};
|
||||
else if((dir.x == 0 && dir.y == -1 && map[x][y] == Map.M135))
|
||||
return new int[] {270, 1};
|
||||
else if((dir.x == 0 && dir.y == -1 && map[x][y] == Map.EMPTY))
|
||||
return new int[] {0, 1};
|
||||
return null;
|
||||
}
|
||||
|
||||
private Vector3f getDir(int x, int y, Vector3f dir) {
|
||||
if((dir.x == 0 && dir.y == 1 && map[x][y] == Map.M45) || (dir.x == 0 && dir.y == -1 && map[x][y] == Map.M135))
|
||||
return LEFT;
|
||||
else if((dir.x == 0 && dir.y == 1 && map[x][y] == Map.M135) || (dir.x == 0 && dir.y == -1 && map[x][y] == Map.M45))
|
||||
return RIGHT;
|
||||
else if((dir.x == -1 && dir.y == 0 && map[x][y] == Map.M135) || (dir.x == 1 && dir.y == 0 && map[x][y] == Map.M45))
|
||||
return UP;
|
||||
else if((dir.x == -1 && dir.y == 0 && map[x][y] == Map.M45) || (dir.x == 1 && dir.y == 0 && map[x][y] == Map.M135))
|
||||
return DOWN;
|
||||
else if(map[x][y] == Map.EMPTY)
|
||||
return dir;
|
||||
return null;
|
||||
}
|
||||
|
||||
public void render() {
|
||||
if(renderBack) {
|
||||
banims[btype].setFrame(frame);
|
||||
brects[btype].render();
|
||||
}
|
||||
if(renderFront) {
|
||||
fanims[ftype].setFrame(frame);
|
||||
frects[ftype].render();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean done() {
|
||||
return !renderBack && !renderFront;
|
||||
}
|
||||
}
|
79
src/com/gnarly/game/board/laser/Trigger.java
Normal file
79
src/com/gnarly/game/board/laser/Trigger.java
Normal file
|
@ -0,0 +1,79 @@
|
|||
package com.gnarly.game.board.laser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.gnarly.game.Main;
|
||||
import com.gnarly.game.text.Console;
|
||||
|
||||
public class Trigger {
|
||||
|
||||
private int tick = 0;
|
||||
private int frame = 0;
|
||||
private int triggered = 0;
|
||||
|
||||
private int x, y, met;
|
||||
|
||||
private ArrayList<Integer> conditions;
|
||||
|
||||
public Trigger(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
conditions = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if(triggered == 2) {
|
||||
frame = Main.tick % Main.BIG_TICK * (32 / Main.BIG_TICK);
|
||||
if(Main.tick % Main.BIG_TICK == Main.BIG_TICK - 1)
|
||||
--triggered;
|
||||
}
|
||||
else
|
||||
frame = 0;
|
||||
if(Main.tick % Main.BIG_TICK == 0) {
|
||||
boolean check = false;
|
||||
for (int i = 0; i < conditions.size(); i++) {
|
||||
if(conditions.get(i).intValue() == tick) {
|
||||
check = true;
|
||||
if(triggered == 0)
|
||||
Console.error.add("TRIGGER FAILED TO BE TRIGGERED AT PROPER TIME!");
|
||||
else
|
||||
++met; }
|
||||
}
|
||||
if(!check && triggered == 2) {
|
||||
--met;
|
||||
Console.error.add("TRIGGER WAS TRIGGERED AT AN UNEXPECTED TIME!");
|
||||
}
|
||||
++tick;
|
||||
}
|
||||
}
|
||||
|
||||
public void trigger() {
|
||||
triggered = 2;
|
||||
}
|
||||
|
||||
public int getFrame() {
|
||||
return frame;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void addCondition(int condition) {
|
||||
conditions.add(condition);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
conditions.clear();
|
||||
tick = 0;
|
||||
met = 0;
|
||||
}
|
||||
|
||||
public boolean success() {
|
||||
return met == conditions.size();
|
||||
}
|
||||
}
|
5
src/com/gnarly/game/commands/Command.java
Normal file
5
src/com/gnarly/game/commands/Command.java
Normal file
|
@ -0,0 +1,5 @@
|
|||
package com.gnarly.game.commands;
|
||||
|
||||
public interface Command {
|
||||
public String getCommand();
|
||||
}
|
18
src/com/gnarly/game/commands/Fire.java
Normal file
18
src/com/gnarly/game/commands/Fire.java
Normal file
|
@ -0,0 +1,18 @@
|
|||
package com.gnarly.game.commands;
|
||||
|
||||
public class Fire implements Command {
|
||||
|
||||
private int cannon;
|
||||
|
||||
public Fire(int cannon) {
|
||||
this.cannon = cannon;
|
||||
}
|
||||
|
||||
public int getCannon() {
|
||||
return cannon;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
return "FIRE " + cannon;
|
||||
}
|
||||
}
|
23
src/com/gnarly/game/commands/Rotate.java
Normal file
23
src/com/gnarly/game/commands/Rotate.java
Normal file
|
@ -0,0 +1,23 @@
|
|||
package com.gnarly.game.commands;
|
||||
|
||||
public class Rotate implements Command {
|
||||
|
||||
private int x, y;
|
||||
|
||||
public Rotate(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
return "ROTATE " + x + " " + y;
|
||||
}
|
||||
}
|
22
src/com/gnarly/game/commands/Wait.java
Normal file
22
src/com/gnarly/game/commands/Wait.java
Normal file
|
@ -0,0 +1,22 @@
|
|||
package com.gnarly.game.commands;
|
||||
|
||||
public class Wait implements Command {
|
||||
|
||||
private int ticks;
|
||||
|
||||
public Wait(int ticks) {
|
||||
this.ticks = ticks;
|
||||
}
|
||||
|
||||
public int getTicks() {
|
||||
return ticks;
|
||||
}
|
||||
|
||||
public void decrement() {
|
||||
--ticks;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
return "WAIT " + ticks;
|
||||
}
|
||||
}
|
77
src/com/gnarly/game/objs/Button.java
Normal file
77
src/com/gnarly/game/objs/Button.java
Normal file
|
@ -0,0 +1,77 @@
|
|||
package com.gnarly.game.objs;
|
||||
|
||||
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.rects.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) {
|
||||
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);
|
||||
states[1] = new TexRect(camera, tex2, x, y, depth, width, height);
|
||||
states[2] = new TexRect(camera, tex3, x, y, depth, width, height);
|
||||
tex = 0;
|
||||
state = 0;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if(contains(window.getMouseCoords(camera))) {
|
||||
if(window.mousePressed(GLFW_MOUSE_BUTTON_1)) {
|
||||
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;
|
||||
}
|
||||
}
|
79
src/com/gnarly/game/text/Console.java
Normal file
79
src/com/gnarly/game/text/Console.java
Normal file
|
@ -0,0 +1,79 @@
|
|||
package com.gnarly.game.text;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.rects.ColRect;
|
||||
import com.gnarly.engine.text.Font;
|
||||
|
||||
public class Console {
|
||||
|
||||
public static ArrayList<String> error = new ArrayList<>();
|
||||
|
||||
private Camera camera;
|
||||
|
||||
private ColRect background;
|
||||
private ColRect body;
|
||||
|
||||
private Font font;
|
||||
|
||||
private float x, y, width, height;
|
||||
|
||||
ArrayList<String> console;
|
||||
|
||||
private int maxLength;
|
||||
private int maxHeight;
|
||||
private int viewY;
|
||||
|
||||
public Console(Camera camera) {
|
||||
this.camera = camera;
|
||||
x = 0;
|
||||
y = 235;
|
||||
width = 228;
|
||||
height = 88;
|
||||
viewY = 0;
|
||||
background = new ColRect(camera, x, y, 0, width, height, 1, 1, 1, 1);
|
||||
body = new ColRect(camera, x + 1, y + 1, 0, width - 2, height - 2, 0, 0, 0, 1);
|
||||
font = new Font(camera, "res/img/fonts/default.png");
|
||||
console = new ArrayList<String>();
|
||||
maxLength = (int) ((width - 2) / font.getWidth(4));
|
||||
maxHeight = (int) ((height - 2) / 5);
|
||||
}
|
||||
|
||||
public void render() {
|
||||
if(error.size() > 0)
|
||||
for (int i = 0; i < error.size(); i++)
|
||||
font.drawString(error.get(i), x + 3, y + i * 5 + 3, 0, 4, 1, 0, 0, 1);
|
||||
else
|
||||
for (int i = viewY; i < console.size() && i < viewY + maxHeight; i++)
|
||||
font.drawString(console.get(i), x + 3, y + (i - viewY) * 5 + 3, 0, 4, 1, 1, 1, 1);
|
||||
body.render();
|
||||
background.render();
|
||||
}
|
||||
|
||||
public void printCommands(String[] commands) {
|
||||
int perCommand = (int) Math.floor((maxLength - 6) / 4);
|
||||
String line = new String();
|
||||
for (int i = 0; i < commands.length; i++) {
|
||||
String command = commands[i];
|
||||
while(command.length() < perCommand)
|
||||
command += ' ';
|
||||
if(i != 3)
|
||||
command += "| ";
|
||||
line += command;
|
||||
}
|
||||
println(line);
|
||||
}
|
||||
|
||||
public void println(String line) {
|
||||
console.add(line);
|
||||
if(console.size() > maxHeight && viewY + maxHeight + 1 == console.size())
|
||||
++viewY;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
viewY = 0;
|
||||
error.clear();
|
||||
console.clear();
|
||||
}
|
||||
}
|
85
src/com/gnarly/game/text/EditorManager.java
Normal file
85
src/com/gnarly/game/text/EditorManager.java
Normal file
|
@ -0,0 +1,85 @@
|
|||
package com.gnarly.game.text;
|
||||
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT_CONTROL;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_KEY_RIGHT_CONTROL;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_KEY_TAB;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_1;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.display.Window;
|
||||
import com.gnarly.engine.text.Font;
|
||||
import com.gnarly.game.board.Map;
|
||||
import com.gnarly.game.commands.Command;
|
||||
|
||||
public class EditorManager {
|
||||
|
||||
private Window window;
|
||||
private Camera camera;
|
||||
|
||||
private Font font;
|
||||
private StringBuilder input;
|
||||
private TextEditor[] boxes;
|
||||
|
||||
private int focus;
|
||||
|
||||
public EditorManager(Window window, Camera camera) {
|
||||
this.window = window;
|
||||
this.camera = camera;
|
||||
float x = 0, y = 33, width = 180, height = 200;
|
||||
font = new Font(camera, "res/img/fonts/default.png");
|
||||
input = new StringBuilder();
|
||||
focus = 0;
|
||||
boxes = new TextEditor[4];
|
||||
boxes[0] = new TextEditor(window, camera, font, "THREAD 1", x, y, 0, width / 2f, height / 2f);
|
||||
boxes[1] = new TextEditor(window, camera, font, "THREAD 2", x + width / 2 + 1, y, 0, width / 2f, height / 2f);
|
||||
boxes[2] = new TextEditor(window, camera, font, "THREAD 3", x, y + height / 2 + 1, 0, width / 2f, height / 2f);
|
||||
boxes[3] = new TextEditor(window, camera, font, "THREAD 4", x + width / 2 + 1, y + height / 2 + 1, 0, width / 2f, height / 2f);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if((window.getKey(GLFW_KEY_LEFT_CONTROL) >= Window.PRESSED || window.getKey(GLFW_KEY_RIGHT_CONTROL) >= Window.PRESSED) && window.getKey(GLFW_KEY_TAB) == Window.PRESSED && focus != -1) {
|
||||
++focus;
|
||||
if(focus == 4)
|
||||
focus = 0;
|
||||
for (int i = 0; i < boxes.length; i++) {
|
||||
if(i == focus)
|
||||
boxes[i].setActive(new Vector3f(0, 0, 0));
|
||||
else
|
||||
boxes[i].hideCursor();
|
||||
}
|
||||
}
|
||||
if(window.mousePressed(GLFW_MOUSE_BUTTON_1)) {
|
||||
boolean contained = false;
|
||||
Vector3f mouse = window.getMouseCoords(camera);
|
||||
for (int i = 0; i < boxes.length; i++) {
|
||||
if(boxes[i].contains(mouse)) {
|
||||
boxes[i].setActive(mouse);
|
||||
focus = i;
|
||||
contained = true;
|
||||
}
|
||||
else
|
||||
boxes[i].hideCursor();
|
||||
}
|
||||
if(!contained)
|
||||
focus = -1;
|
||||
}
|
||||
if(focus > -1)
|
||||
boxes[focus].update();
|
||||
}
|
||||
|
||||
public void render() {
|
||||
for (int i = 0; i < boxes.length; i++)
|
||||
boxes[i].render();
|
||||
}
|
||||
|
||||
public ArrayList<Command>[] getCommands() {
|
||||
ArrayList<Command>[] commands = (ArrayList<Command>[])new ArrayList[4];
|
||||
for (int i = 0; i < commands.length; i++)
|
||||
commands[i] = boxes[i].getCommands(i + 1);
|
||||
return commands;
|
||||
}
|
||||
}
|
42
src/com/gnarly/game/text/TextBox.java
Normal file
42
src/com/gnarly/game/text/TextBox.java
Normal file
|
@ -0,0 +1,42 @@
|
|||
package com.gnarly.game.text;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.rects.ColRect;
|
||||
import com.gnarly.engine.text.Font;
|
||||
|
||||
public class TextBox {
|
||||
|
||||
private static Font font;
|
||||
|
||||
private Camera camera;
|
||||
private String text;
|
||||
|
||||
private ColRect back, body;
|
||||
|
||||
private float x, y, depth, width, height, textSize;
|
||||
|
||||
public TextBox(Camera camera, String text, float x, float y, float depth, float width, float height, float textSize) {
|
||||
this.camera = camera;
|
||||
this.text = text;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.depth = depth;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.textSize = textSize;
|
||||
back = new ColRect(camera, x, y, depth, width, height, 1, 1, 1, 1);
|
||||
body = new ColRect(camera, x + 1, y + 1, depth, width - 2, height - 2, 0, 0, 0, 1);
|
||||
if(font == null)
|
||||
font = new Font(camera, "res/img/fonts/default.png");
|
||||
}
|
||||
|
||||
public void render() {
|
||||
font.drawString(text, x + 2, y + 2, depth, textSize, 1, 1, 1, 1);
|
||||
body.render();
|
||||
back.render();
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
}
|
313
src/com/gnarly/game/text/TextEditor.java
Normal file
313
src/com/gnarly/game/text/TextEditor.java
Normal file
|
@ -0,0 +1,313 @@
|
|||
package com.gnarly.game.text;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.display.Window;
|
||||
import com.gnarly.engine.rects.ColRect;
|
||||
import com.gnarly.engine.text.Font;
|
||||
import com.gnarly.game.commands.Command;
|
||||
import com.gnarly.game.commands.Fire;
|
||||
import com.gnarly.game.commands.Rotate;
|
||||
import com.gnarly.game.commands.Wait;
|
||||
|
||||
public class TextEditor {
|
||||
|
||||
private static final float
|
||||
HEADER_HEIGHT = 10.666666666f,
|
||||
TEXT_HEIGHT = 5.333333333f;
|
||||
|
||||
private Window window;
|
||||
private Camera camera;
|
||||
private Font font;
|
||||
private String name;
|
||||
|
||||
private ColRect background;
|
||||
private ColRect header;
|
||||
private ColRect body;
|
||||
|
||||
private float x, y, depth, width, height;
|
||||
|
||||
private int maxLength;
|
||||
private StringBuilder[] contents;
|
||||
|
||||
private ColRect cursor;
|
||||
private int cx, cy;
|
||||
private boolean showing;
|
||||
private float lastTime, blinkRate;
|
||||
|
||||
public TextEditor(Window window, Camera camera, Font font, String name, float x, float y, float depth, float width, float height) {
|
||||
this.window = window;
|
||||
this.camera = camera;
|
||||
this.font = font;
|
||||
this.name = name;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.depth = depth;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
background = new ColRect(camera, x, y, depth, width, height, 1, 1, 1, 1);
|
||||
header = new ColRect(camera, x + 1, y + 1, depth, width - 2, HEADER_HEIGHT, 0, 0, 0, 1);
|
||||
body = new ColRect(camera, x + 1, y + HEADER_HEIGHT + 2, depth, width - 2, height - HEADER_HEIGHT - 3, 0, 0, 0, 1);
|
||||
maxLength = (int) ((body.getWidth() - 2) / font.getWidth(TEXT_HEIGHT));
|
||||
contents = new StringBuilder[(int) ((body.getHeight() - 1) / (TEXT_HEIGHT + 1))];
|
||||
for (int i = 0; i < contents.length; i++)
|
||||
contents[i] = new StringBuilder();
|
||||
cursor = new ColRect(camera, body.getX() + 1, body.getY() + 1, depth, font.getCharWidth(TEXT_HEIGHT), TEXT_HEIGHT, 1, 1, 1, 1);
|
||||
cx = 0;
|
||||
cy = 0;
|
||||
showing = false;
|
||||
lastTime = System.nanoTime() / 1000000f;
|
||||
blinkRate = 500;
|
||||
}
|
||||
|
||||
public void render() {
|
||||
if(showing)
|
||||
cursor.render();
|
||||
font.drawString(name, x + 2, y + 2, depth, HEADER_HEIGHT - 2, 1, 1, 1, 1);
|
||||
for (int i = 0; i < contents.length; i++)
|
||||
font.drawString(contents[i].toString(), body.getX() + 1, body.getY() + i * (TEXT_HEIGHT + 1) + 1, depth, TEXT_HEIGHT, 1, 1, 1, 1);
|
||||
header.render();
|
||||
body.render();
|
||||
background.render();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
input();
|
||||
cursor();
|
||||
}
|
||||
|
||||
private void input() {
|
||||
StringBuilder in = new StringBuilder(window.getInput().toUpperCase());
|
||||
if(in.length() > 0) {
|
||||
showing = true;
|
||||
lastTime = System.nanoTime() / 1000000f;
|
||||
}
|
||||
for (int i = 0; i < in.length(); i++) {
|
||||
char c = in.charAt(i);
|
||||
if(c == 10 && cy < contents.length - 1) { // New line
|
||||
if(cx == contents[cy].length()) {
|
||||
++cy;
|
||||
cx = 0;
|
||||
}
|
||||
else if(contents[contents.length - 1].length() == 0) {
|
||||
for (int j = contents.length - 1; j > cy + 1; --j) {
|
||||
contents[j].delete(0, contents[j].length());
|
||||
contents[j].append(contents[j - 1]);
|
||||
}
|
||||
contents[cy + 1].delete(0, contents[cy + 1].length());
|
||||
contents[cy + 1].append(contents[cy].substring(cx, contents[cy].length()));
|
||||
contents[cy].delete(cx, contents[cy].length());
|
||||
++cy;
|
||||
cx = 0;
|
||||
}
|
||||
}
|
||||
else if(c == 9) {
|
||||
--cx;
|
||||
for (int j = 0; j < 4 && cx + j <= maxLength; j++)
|
||||
contents[cy].insert(++cx, (char) 32);
|
||||
}
|
||||
else if(c == 8) { // Backspace
|
||||
if(cx > 0) { // Mid-line
|
||||
contents[cy].deleteCharAt(cx - 1);
|
||||
--cx;
|
||||
}
|
||||
else if(cy > 0) { // Beginning of line
|
||||
if(contents[cy - 1].length() + contents[cy].length() <= maxLength) {
|
||||
contents[cy - 1].append(contents[cy]);
|
||||
for (int j = cy; j < contents.length; j++) {
|
||||
contents[j].setLength(0);
|
||||
if(j < contents.length - 1)
|
||||
contents[j].append(contents[j + 1]);
|
||||
}
|
||||
}
|
||||
--cy;
|
||||
cx = contents[cy].length();
|
||||
}
|
||||
}
|
||||
else if(c == 127) { // Delete
|
||||
if(cx < contents[cy].length()) // Mid-line
|
||||
contents[cy].deleteCharAt(cx);
|
||||
else if(cy < contents.length - 1 && contents[cy].length() + contents[cy + 1].length() <= maxLength) { // End of line
|
||||
contents[cy].append(contents[cy + 1]);
|
||||
for (int j = cy + 1; j < contents.length; j++) {
|
||||
contents[j].setLength(0);
|
||||
if(j < contents.length - 1)
|
||||
contents[j].append(contents[j + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(c == 1) { // Left arrow
|
||||
--cx;
|
||||
if(cx == -1) {
|
||||
if(cy == 0)
|
||||
++cx;
|
||||
else {
|
||||
--cy;
|
||||
cx = contents[cy].length();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(c == 2) { // Right arrow
|
||||
++cx;
|
||||
if(cx > contents[cy].length()) {
|
||||
if(cy == contents.length - 1)
|
||||
--cx;
|
||||
else {
|
||||
++cy;
|
||||
cx = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(c == 3 && cy > 0) { // Up arrow
|
||||
--cy;
|
||||
if(cx > contents[cy].length())
|
||||
cx = contents[cy].length();
|
||||
}
|
||||
else if(c == 4 && cy < contents.length - 1) { // Down arrow
|
||||
++cy;
|
||||
if(cx > contents[cy].length())
|
||||
cx = contents[cy].length();
|
||||
}
|
||||
else if((range(c, 48, 57) || range(c, 65, 90) || c == 32) && cx < maxLength) {
|
||||
contents[cy].insert(cx, c);
|
||||
++cx;
|
||||
}
|
||||
}
|
||||
if(contents[cy].length() > maxLength)
|
||||
contents[cy].setLength(maxLength);
|
||||
}
|
||||
|
||||
private void cursor() {
|
||||
if(System.nanoTime() / 1000000f - lastTime > blinkRate) {
|
||||
showing = !showing;
|
||||
lastTime += blinkRate;
|
||||
}
|
||||
cursor.setPos(body.getX() + cx * font.getWidth(TEXT_HEIGHT) + 1, body.getY() + cy * (TEXT_HEIGHT + 1) + 1);
|
||||
}
|
||||
|
||||
public boolean contains(Vector3f vector) {
|
||||
return vector.x >= this.x && vector.y >= this.y && vector.x < this.x + width && vector.y < this.y + height;
|
||||
}
|
||||
|
||||
public void setActive(Vector3f coords) {
|
||||
int tempY = clampY((int) ((coords.y - body.getY()) / (TEXT_HEIGHT + 1)));
|
||||
int tempX = clampX((int) ((coords.x - body.getX()) / font.getWidth(TEXT_HEIGHT)));
|
||||
if(tempX > -1 && tempY > -1 && tempX <= maxLength && tempY <= contents.length) {
|
||||
cx = tempX;
|
||||
cy = tempY + 1;
|
||||
while(cy > 0 && contents[--cy].length() == 0);
|
||||
if(cx > contents[cy].length())
|
||||
cx = contents[cy].length();
|
||||
}
|
||||
showing = true;
|
||||
lastTime = System.nanoTime() / 1000000f;
|
||||
}
|
||||
|
||||
private int clampX(int x) {
|
||||
if(x < 0)
|
||||
x = 0;
|
||||
else if(x > contents[cy].length())
|
||||
x = contents[cy].length();
|
||||
return x;
|
||||
}
|
||||
|
||||
private int clampY(int y) {
|
||||
if(y < 0)
|
||||
y = 0;
|
||||
else if(y > contents.length - 1)
|
||||
y = contents.length - 1;
|
||||
return y;
|
||||
}
|
||||
|
||||
public void hideCursor() {
|
||||
showing = false;
|
||||
}
|
||||
|
||||
private boolean range(char c, int start, int end) {
|
||||
return c >= start && c <= end;
|
||||
}
|
||||
|
||||
public ArrayList<Command> getCommands(int thread) {
|
||||
ArrayList<Command> commands = new ArrayList<>();
|
||||
for (int i = 0; i < contents.length; i++) {
|
||||
if(contents[i].length() > 0) {
|
||||
if(contents[i].length() >= 6 && contents[i].substring(0, 6).equals("ROTATE")) {
|
||||
int x = 0, y = 0;
|
||||
String[] split = contents[i].toString().split(" ");
|
||||
if(split.length == 3) {
|
||||
for (int j = 0; j < split[1].length(); j++) {
|
||||
char c = split[1].charAt(j);
|
||||
if(c >= 48 && c <= 57) {
|
||||
x *= 10;
|
||||
x += c - 48;
|
||||
}
|
||||
else {
|
||||
Console.error.add("ROTATE REQUIRES EXACTLY 2 SPACE SEPERATED INTEGERS - THREAD: " + thread + " - LINE " + (i + 1));
|
||||
j = contents[i].length();
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < split[2].length(); j++) {
|
||||
char c = split[2].charAt(j);
|
||||
if(c >= 48 && c <= 57) {
|
||||
y *= 10;
|
||||
y += c - 48;
|
||||
}
|
||||
else {
|
||||
Console.error.add("ROTATE REQUIRES EXACTLY 2 SPACE SEPERATED INTEGERS - THREAD: " + thread + " - LINE " + (i + 1));
|
||||
j = contents[i].length();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Console.error.add("ROTATE REQUIRES EXACTLY 2 SPACE SEPERATED INTEGERS - THREAD: " + thread + " - LINE " + (i + 1));
|
||||
}
|
||||
if(x > 11 || y > 7)
|
||||
Console.error.add("CANNOT EXCEED MAP LIMITS OF 12X8 - THREAD: " + thread + " - LINE " + (i + 1));
|
||||
else
|
||||
commands.add(new Rotate(x, y));
|
||||
}
|
||||
else if(contents[i].length() >= 4 && contents[i].substring(0, 4).equals("WAIT")) {
|
||||
int num = 0;
|
||||
for (int j = 5; j < contents[i].length(); ++j) {
|
||||
char c = contents[i].charAt(j);
|
||||
if(c >= 48 && c <= 57) {
|
||||
num *= 10;
|
||||
num += c - 48;
|
||||
}
|
||||
else if(c != 32) {
|
||||
Console.error.add("WAIT CANNOT BE FOLLOWED BY NON-NUMERIC CHARACTERS - THREAD: " + thread + " - LINE " + (i + 1));
|
||||
j = contents[i].length();
|
||||
}
|
||||
}
|
||||
if(num == 0)
|
||||
num = 1;
|
||||
commands.add(new Wait(num));
|
||||
}
|
||||
else if(contents[i].length() >= 6 && contents[i].substring(0, 4).equals("FIRE")) {
|
||||
int num = 0;
|
||||
for (int j = 5; j < contents[i].length(); ++j) {
|
||||
char c = contents[i].charAt(j);
|
||||
if(c >= 48 && c <= 57) {
|
||||
num *= 10;
|
||||
num += c - 48;
|
||||
}
|
||||
else if(c != 32) {
|
||||
Console.error.add("FIRE MUST BE FOLLWED BY NUMBER - THREAD: " + thread + " - LINE: " + (i + 1));
|
||||
j = contents[i].length();
|
||||
}
|
||||
}
|
||||
if(num > 99)
|
||||
Console.error.add("NUMBER " + num + " IS NOT A VALID NUMBER FOR FIRE - THREAD: " + thread + " - LINE: " + (i + 1));
|
||||
else
|
||||
commands.add(new Fire(num));
|
||||
}
|
||||
else
|
||||
Console.error.add("UNRECOGNIZED COMMAND: " + (contents[i].toString().length() > 25 ? (contents[i].toString().substring(0, 23) + "...") : contents[i].toString()) + " - THREAD: " + thread + " - LINE: " + (i + 1));
|
||||
}
|
||||
}
|
||||
return commands;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue