Compare commits
8 Commits
d2c33b529a
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| d3dc397353 | |||
| ad56624b51 | |||
| bb24efb856 | |||
| 6f731c2885 | |||
| dc50ee48c2 | |||
| 0e66f20423 | |||
| 2ed1763b83 | |||
| abd4597f69 |
10
assets/shaders/fader.frag.glsl
Normal file
10
assets/shaders/fader.frag.glsl
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#version 330 core
|
||||||
|
|
||||||
|
in vec4 fColour;
|
||||||
|
out vec4 colour;
|
||||||
|
|
||||||
|
uniform float u_alpha;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
colour = vec4(fColour.xyz, 1.0 - u_alpha);
|
||||||
|
}
|
||||||
19
assets/shaders/texture.frag.glsl
Normal file
19
assets/shaders/texture.frag.glsl
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#version 330 core
|
||||||
|
out vec4 FragColour;
|
||||||
|
|
||||||
|
in vec4 ourColour;
|
||||||
|
in vec2 TexCoord;
|
||||||
|
|
||||||
|
uniform sampler2D texture1;
|
||||||
|
uniform sampler2D texture2;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 tex1Color = texture(texture1, TexCoord);
|
||||||
|
vec4 tex2Color = texture(texture2, TexCoord);
|
||||||
|
|
||||||
|
if (tex2Color.a < 0.1)
|
||||||
|
tex2Color = tex1Color;
|
||||||
|
|
||||||
|
FragColour = mix(tex1Color, tex2Color, 0.4f);
|
||||||
|
}
|
||||||
15
assets/shaders/texture.vert.glsl
Normal file
15
assets/shaders/texture.vert.glsl
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#version 330 core
|
||||||
|
|
||||||
|
layout (location = 0) in vec3 aPos;
|
||||||
|
layout (location = 1) in vec4 aColour;
|
||||||
|
layout (location = 2) in vec2 aTexCoord;
|
||||||
|
|
||||||
|
out vec4 ourColour;
|
||||||
|
out vec2 TexCoord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = vec4(aPos, 1.0);
|
||||||
|
ourColour = aColour;
|
||||||
|
TexCoord = aTexCoord;
|
||||||
|
}
|
||||||
BIN
assets/textures/flames.png
Normal file
BIN
assets/textures/flames.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
BIN
assets/textures/plink.jpg
Normal file
BIN
assets/textures/plink.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
BIN
assets/textures/plink.png
Normal file
BIN
assets/textures/plink.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
1
pom.xml
1
pom.xml
@@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
<name>game</name>
|
<name>game</name>
|
||||||
<description>A simple game.</description>
|
<description>A simple game.</description>
|
||||||
<!-- FIXME change it to the project's website -->
|
|
||||||
<url>http://www.hirw.org</url>
|
<url>http://www.hirw.org</url>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
|||||||
58
src/main/java/org/hirw/game/FaderShader.java
Normal file
58
src/main/java/org/hirw/game/FaderShader.java
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package org.hirw.game;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL20.*;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.hirw.game.util.Log;
|
||||||
|
import org.hirw.game.util.Time;
|
||||||
|
|
||||||
|
public class FaderShader extends Shader {
|
||||||
|
private static final String FADER_SHADER_FRAG_PATH = "assets/shaders/fader.frag.glsl";
|
||||||
|
private static final float DEFAULT_ALPHA_INCREASE_STEP = 1.0f / 3;
|
||||||
|
private final float INITIAL_ALPHA = 0.0f;
|
||||||
|
|
||||||
|
@Getter private final float alphaIncreaseStep;
|
||||||
|
@Getter @Setter private float alpha;
|
||||||
|
@Getter @Setter private int alphaUniformLocation;
|
||||||
|
|
||||||
|
public FaderShader(float alphaIncreaseStep) {
|
||||||
|
super(FADER_SHADER_FRAG_PATH, DEFAULT_VERT_PATH);
|
||||||
|
this.alpha = INITIAL_ALPHA;
|
||||||
|
this.alphaIncreaseStep = alphaIncreaseStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FaderShader() {
|
||||||
|
this(DEFAULT_ALPHA_INCREASE_STEP);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
super.init();
|
||||||
|
findAlphaUniformLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update() {
|
||||||
|
super.update();
|
||||||
|
increaseAlpha();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findAlphaUniformLocation() {
|
||||||
|
int location = glGetUniformLocation(getShaderProgramID(), "u_alpha");
|
||||||
|
if (location == -1) {
|
||||||
|
Log.warning("FaderShader", "Failed to get 'u_alpha' uniform location, trying to continue...");
|
||||||
|
} else {
|
||||||
|
setAlphaUniformLocation(location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void increaseAlpha() {
|
||||||
|
if (getAlphaUniformLocation() == -1) return;
|
||||||
|
if (getAlpha() >= 1.0f) return;
|
||||||
|
|
||||||
|
setAlpha(getAlpha() + (getAlphaIncreaseStep() * Time.deltaTime()));
|
||||||
|
|
||||||
|
glUseProgram(getShaderProgramID());
|
||||||
|
glUniform1f(getAlphaUniformLocation(), getAlpha());
|
||||||
|
glUseProgram(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,18 +12,22 @@ import org.lwjgl.BufferUtils;
|
|||||||
|
|
||||||
public class Mesh {
|
public class Mesh {
|
||||||
@Getter @Setter private int vaoID, vboID, eboID;
|
@Getter @Setter private int vaoID, vboID, eboID;
|
||||||
@Getter private Shader shader;
|
@Getter protected Shader shader;
|
||||||
@Getter float[] vertices;
|
@Getter float[] vertices;
|
||||||
@Getter int[] elements;
|
@Getter int[] elements;
|
||||||
|
|
||||||
private static final float[] defaultVertexArray = {
|
protected final int POSITION_SIZE = 3;
|
||||||
|
protected final int RGBA_SIZE = 4;
|
||||||
|
protected final int FLOAT_SIZE_IN_BYTES = Float.SIZE / Byte.SIZE;
|
||||||
|
|
||||||
|
protected static final float[] DEFAULT_VERTEX_ARRAY = {
|
||||||
0.5f, -0.5f, 0.0f, /* */ 1.0f, 0.0f, 0.0f, 1.0f,
|
0.5f, -0.5f, 0.0f, /* */ 1.0f, 0.0f, 0.0f, 1.0f,
|
||||||
-0.5f, 0.5f, 0.0f, /* */ 0.0f, 1.0f, 0.0f, 1.0f,
|
-0.5f, 0.5f, 0.0f, /* */ 0.0f, 1.0f, 0.0f, 1.0f,
|
||||||
0.5f, 0.5f, 0.0f, /* */ 0.0f, 0.0f, 1.0f, 1.0f,
|
0.5f, 0.5f, 0.0f, /* */ 0.0f, 0.0f, 1.0f, 1.0f,
|
||||||
-0.5f, -0.5f, 0.0f, /* */ 1.0f, 1.0f, 0.0f, 1.0f,
|
-0.5f, -0.5f, 0.0f, /* */ 1.0f, 1.0f, 0.0f, 1.0f,
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final int[] defaultElementArray = {
|
protected static final int[] DEFAULT_ELEMENT_ARRAY = {
|
||||||
2, 1, 0,
|
2, 1, 0,
|
||||||
0, 1, 3
|
0, 1, 3
|
||||||
};
|
};
|
||||||
@@ -38,7 +42,7 @@ public class Mesh {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Mesh(Shader shader) {
|
public Mesh(Shader shader) {
|
||||||
this(shader, defaultVertexArray, defaultElementArray);
|
this(shader, DEFAULT_VERTEX_ARRAY, DEFAULT_ELEMENT_ARRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
@@ -61,7 +65,7 @@ public class Mesh {
|
|||||||
getEboID(), getVboID(), getEboID(), getShader().getShaderProgramID());
|
getEboID(), getVboID(), getEboID(), getShader().getShaderProgramID());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void glDraw() {
|
protected void glDraw() {
|
||||||
glBindVertexArray(this.vaoID);
|
glBindVertexArray(this.vaoID);
|
||||||
glDrawElements(GL_TRIANGLES, getElements().length, GL_UNSIGNED_INT, 0);
|
glDrawElements(GL_TRIANGLES, getElements().length, GL_UNSIGNED_INT, 0);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
@@ -74,16 +78,24 @@ public class Mesh {
|
|||||||
initialiseVertexBufferObject();
|
initialiseVertexBufferObject();
|
||||||
initialiseElementBufferObject();
|
initialiseElementBufferObject();
|
||||||
|
|
||||||
int positionsSize = 3;
|
initialiseAttribPointers();
|
||||||
int colourSize = 4;
|
}
|
||||||
int floatSizeBytes = 4;
|
|
||||||
int vertexSizeBytes = (positionsSize + colourSize) * floatSizeBytes;
|
protected int initialiseAttribPointers() {
|
||||||
glVertexAttribPointer(0, positionsSize, GL_FLOAT, false, vertexSizeBytes, 0);
|
int vertexSizeInBytes = calculateVertexSizeInBytes();
|
||||||
|
|
||||||
|
glVertexAttribPointer(0, POSITION_SIZE, GL_FLOAT, false, vertexSizeInBytes, 0);
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
glVertexAttribPointer(
|
glVertexAttribPointer(
|
||||||
1, colourSize, GL_FLOAT, false, vertexSizeBytes, positionsSize * floatSizeBytes);
|
1, RGBA_SIZE, GL_FLOAT, false, vertexSizeInBytes, POSITION_SIZE * FLOAT_SIZE_IN_BYTES);
|
||||||
glEnableVertexAttribArray(1);
|
glEnableVertexAttribArray(1);
|
||||||
|
|
||||||
|
return vertexSizeInBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int calculateVertexSizeInBytes() {
|
||||||
|
return (POSITION_SIZE + RGBA_SIZE) * FLOAT_SIZE_IN_BYTES;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialiseVertexBufferObject() {
|
private void initialiseVertexBufferObject() {
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
package org.hirw.game;
|
package org.hirw.game;
|
||||||
|
|
||||||
public abstract class Scene {
|
import lombok.Getter;
|
||||||
public final SceneType SCENE_TYPE = SceneType.UNDEFINED;
|
|
||||||
|
|
||||||
public Scene() {}
|
public abstract class Scene {
|
||||||
|
@Getter private final SceneType sceneType;
|
||||||
|
|
||||||
|
public Scene(SceneType sceneType) {
|
||||||
|
this.sceneType = sceneType;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract void init();
|
public abstract void init();
|
||||||
|
|
||||||
public abstract void update();
|
public abstract void update();
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return SCENE_TYPE.toString();
|
return getSceneType().toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,32 +15,42 @@ public final class SceneManager {
|
|||||||
SceneType.MENU, new SplashScene(),
|
SceneType.MENU, new SplashScene(),
|
||||||
SceneType.GAME, new SplashScene()));
|
SceneType.GAME, new SplashScene()));
|
||||||
|
|
||||||
@Getter private static Scene scene = SCENES.get(DEFAULT_SCENE_TYPE);
|
@Getter private static Scene scene;
|
||||||
|
|
||||||
public static void init() {
|
public static void init() {
|
||||||
setScene(DEFAULT_SCENE_TYPE);
|
setScene(DEFAULT_SCENE_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setScene(SceneType sceneType) {
|
public static void setScene(SceneType sceneType) {
|
||||||
scene = SCENES.get(sceneType);
|
Scene newScene = SCENES.get(sceneType);
|
||||||
|
|
||||||
|
if (scene == newScene) {
|
||||||
|
Log.warning("SceneManager", sameSceneWarningString());
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
scene = newScene;
|
||||||
|
}
|
||||||
|
|
||||||
scene.init();
|
scene.init();
|
||||||
logSceneChange();
|
logSceneChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void update() {
|
public static void update() {
|
||||||
if (scene.SCENE_TYPE == SceneType.UNDEFINED) return;
|
if (scene.getSceneType() == null) return;
|
||||||
|
|
||||||
getScene().update();
|
getScene().update();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void logSceneChange() {
|
private static void logSceneChange() {
|
||||||
SceneType newSceneType = getScene().SCENE_TYPE;
|
SceneType newSceneType = getScene().getSceneType();
|
||||||
String loadedSceneMessage = String.format("Changed to scene '%s'", newSceneType.toString());
|
String loadedSceneMessage = String.format("Changed to scene '%s'", newSceneType.toString());
|
||||||
|
|
||||||
if (newSceneType == SceneType.UNDEFINED) {
|
|
||||||
Log.warning("SceneManager", loadedSceneMessage);
|
|
||||||
} else {
|
|
||||||
Log.success("SceneManager", loadedSceneMessage);
|
Log.success("SceneManager", loadedSceneMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String sameSceneWarningString() {
|
||||||
|
return String.format(
|
||||||
|
"Tried to switch to scene '%s' but that scene is already loaded",
|
||||||
|
scene.getSceneType().toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.hirw.game;
|
package org.hirw.game;
|
||||||
|
|
||||||
public enum SceneType {
|
public enum SceneType {
|
||||||
UNDEFINED,
|
|
||||||
SPLASH,
|
SPLASH,
|
||||||
MENU,
|
MENU,
|
||||||
GAME,
|
GAME,
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ public class Shader {
|
|||||||
ShaderType.FRAG, GL_FRAGMENT_SHADER,
|
ShaderType.FRAG, GL_FRAGMENT_SHADER,
|
||||||
ShaderType.VERT, GL_VERTEX_SHADER));
|
ShaderType.VERT, GL_VERTEX_SHADER));
|
||||||
|
|
||||||
private static final String DEFAULT_FRAG_PATH = "assets/shaders/default.frag.glsl";
|
protected static final String DEFAULT_FRAG_PATH = "assets/shaders/default.frag.glsl";
|
||||||
private static final String DEFAULT_VERT_PATH = "assets/shaders/default.vert.glsl";
|
protected static final String DEFAULT_VERT_PATH = "assets/shaders/default.vert.glsl";
|
||||||
|
|
||||||
@Getter private String vertexSource;
|
@Getter private String vertexSource;
|
||||||
@Getter private String fragmentSource;
|
@Getter private String fragmentSource;
|
||||||
@@ -40,6 +40,10 @@ public class Shader {
|
|||||||
this.vertexSource = readFromFile(vertPath);
|
this.vertexSource = readFromFile(vertPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Shader(String path) {
|
||||||
|
this(path + ".frag.glsl", path + ".vert.glsl");
|
||||||
|
}
|
||||||
|
|
||||||
public Shader() {
|
public Shader() {
|
||||||
this(DEFAULT_FRAG_PATH, DEFAULT_VERT_PATH);
|
this(DEFAULT_FRAG_PATH, DEFAULT_VERT_PATH);
|
||||||
}
|
}
|
||||||
@@ -58,6 +62,8 @@ public class Shader {
|
|||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void update() {}
|
||||||
|
|
||||||
private void compileShader(ShaderType shaderType) {
|
private void compileShader(ShaderType shaderType) {
|
||||||
int shaderID = glCreateShader(SHADERS.get(shaderType));
|
int shaderID = glCreateShader(SHADERS.get(shaderType));
|
||||||
|
|
||||||
|
|||||||
@@ -1,53 +1,72 @@
|
|||||||
package org.hirw.game;
|
package org.hirw.game;
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL11.*;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.hirw.game.util.Time;
|
|
||||||
|
|
||||||
public class SplashScene extends Scene {
|
public class SplashScene extends Scene {
|
||||||
@Getter public final SceneType SCENE_TYPE = SceneType.SPLASH;
|
@Getter public final SceneType SCENE_TYPE = SceneType.SPLASH;
|
||||||
private final float INITIAL_BRIGHTNESS = 0.0f;
|
|
||||||
private final float FADE_RATE = 0.5f;
|
|
||||||
|
|
||||||
private float brightness;
|
|
||||||
|
|
||||||
@Getter @Setter private Mesh screenCover;
|
@Getter @Setter private Mesh screenCover;
|
||||||
|
@Getter @Setter private FaderShader screenCoverFaderShader;
|
||||||
|
@Getter @Setter private Mesh logo;
|
||||||
|
|
||||||
public SplashScene() {
|
public SplashScene() {
|
||||||
this.brightness = INITIAL_BRIGHTNESS;
|
super(SceneType.SPLASH);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
Shader faderShader = new Shader();
|
createScreenCover();
|
||||||
faderShader.init();
|
createLogo();
|
||||||
Mesh screenCover = new Mesh(faderShader);
|
|
||||||
screenCover.init();
|
|
||||||
setScreenCover(screenCover);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update() {
|
public void update() {
|
||||||
if (Objects.isNull(Window.get().getGlfwWindow())) {
|
getLogo().draw();
|
||||||
return;
|
getScreenCoverFaderShader().update();
|
||||||
|
getScreenCover().draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
screenCover.draw();
|
private void createScreenCover() {
|
||||||
|
FaderShader faderShader = new FaderShader();
|
||||||
fadeIn();
|
faderShader.init();
|
||||||
|
Mesh screenCover = new Mesh(faderShader, screenCoverRectVertices, screenCoverRectElements);
|
||||||
|
screenCover.init();
|
||||||
|
setScreenCoverFaderShader(faderShader);
|
||||||
|
setScreenCover(screenCover);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fadeIn() {
|
private void createLogo() {
|
||||||
glClearColor(this.brightness, this.brightness, this.brightness, 0.0f);
|
Shader texturedShader = new Shader("assets/shaders/texture");
|
||||||
final float fadeAmount = FADE_RATE * Time.deltaTime();
|
texturedShader.init();
|
||||||
this.brightness += fadeAmount;
|
Texture logoTexture = new Texture(225, 225, "assets/textures/plink.png");
|
||||||
|
Texture flameTexture = new Texture(2500, 2500, "assets/textures/flames.png");
|
||||||
|
logoTexture.init();
|
||||||
|
flameTexture.init();
|
||||||
|
Mesh logoMesh =
|
||||||
|
new TexturedMesh(
|
||||||
|
texturedShader,
|
||||||
|
new Texture[] {logoTexture, flameTexture},
|
||||||
|
logoRectVertices,
|
||||||
|
screenCoverRectElements);
|
||||||
|
logoMesh.init();
|
||||||
|
setLogo(logoMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final float[] screenCoverRect = {
|
private static final float[] screenCoverRectVertices = {
|
||||||
1.0f, -0.0f, 0.0f, /* */ 0.0f, 0.0f, 0.0f, 0.0f,
|
1.0f, 1.0f, 0.0f, /* */ 0.0f, 0.0f, 0.0f, 0.0f, // 0 Top Right
|
||||||
-0.0f, 1.0f, 0.0f, /* */ 0.0f, 0.0f, 0.0f, 0.0f,
|
1.0f, -1.0f, 0.0f, /* */ 0.0f, 0.0f, 0.0f, 0.0f, // 1 Bottom Right
|
||||||
1.0f, 1.0f, 0.0f, /* */ 0.0f, 0.0f, 0.0f, 0.0f,
|
-1.0f, -1.0f, 0.0f, /* */ 0.0f, 0.0f, 0.0f, 0.0f, // 2 Bottom Left
|
||||||
-1.0f, -1.0f, 0.0f, /* */ 0.0f, 0.0f, 0.0f, 0.0f,
|
-1.0f, 1.0f, 0.0f, /* */ 0.0f, 0.0f, 0.0f, 0.0f, // 3 Top Left
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final int[] screenCoverRectElements = {
|
||||||
|
0, 1, 3,
|
||||||
|
1, 2, 3
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final float[] logoRectVertices = {
|
||||||
|
0.1f, 0.1f, 0.0f, /* */ 0.0f, 0.0f, 0.0f, 0.0f, /* */ 1.0f, 1.0f, // 0 Top Right
|
||||||
|
0.1f, -0.1f, 0.0f, /* */ 0.0f, 0.0f, 0.0f, 0.0f, /* */ 1.0f, 0.0f, // 1 Bottom Right
|
||||||
|
-0.1f, -0.1f, 0.0f, /* */ 0.0f, 0.0f, 0.0f, 0.0f, /* */ 0.0f, 0.0f, // 2 Bottom Left
|
||||||
|
-0.1f, 0.1f, 0.0f, /* */ 0.0f, 0.0f, 0.0f, 0.0f, /* */ 0.0f, 1.0f, // 3 Top Left
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
105
src/main/java/org/hirw/game/Texture.java
Normal file
105
src/main/java/org/hirw/game/Texture.java
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
package org.hirw.game;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL11.*;
|
||||||
|
import static org.lwjgl.opengl.GL12.*;
|
||||||
|
import static org.lwjgl.stb.STBImage.stbi_image_free;
|
||||||
|
import static org.lwjgl.stb.STBImage.stbi_load;
|
||||||
|
import static org.lwjgl.stb.STBImage.stbi_set_flip_vertically_on_load;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
public class Texture {
|
||||||
|
@Getter private int width;
|
||||||
|
@Getter private int height;
|
||||||
|
@Getter private String texturePath;
|
||||||
|
@Getter @Setter private int textureID;
|
||||||
|
@Getter @Setter private int channelCount;
|
||||||
|
@Getter @Setter private int internalFormat;
|
||||||
|
|
||||||
|
public Texture(int width, int height, String texturePath) {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.texturePath = texturePath;
|
||||||
|
guessChannelCountAndInternalFormat();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void guessChannelCountAndInternalFormat() {
|
||||||
|
int fileExtensionIndex = getTexturePath().lastIndexOf(".");
|
||||||
|
if (fileExtensionIndex == -1) {
|
||||||
|
// No file extension, so just assume 4 channels (.png -> RGBA)
|
||||||
|
setChannelCount(4);
|
||||||
|
setInternalFormat(GL_RGBA);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String fileExtension = getTexturePath().substring(fileExtensionIndex + 1);
|
||||||
|
switch (fileExtension) {
|
||||||
|
case "png":
|
||||||
|
setChannelCount(4);
|
||||||
|
setInternalFormat(GL_RGBA);
|
||||||
|
break;
|
||||||
|
case "jpg":
|
||||||
|
setChannelCount(3);
|
||||||
|
setInternalFormat(GL_RGB);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// just pray at this point
|
||||||
|
setChannelCount(3);
|
||||||
|
setInternalFormat(GL_RGB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
ByteBuffer imageBytes = loadImageBytes();
|
||||||
|
createTexture(imageBytes);
|
||||||
|
stbi_image_free(imageBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ByteBuffer loadImageBytes() {
|
||||||
|
stbi_set_flip_vertically_on_load(true);
|
||||||
|
return stbi_load(
|
||||||
|
getTexturePath(),
|
||||||
|
new int[getWidth()],
|
||||||
|
new int[getHeight()],
|
||||||
|
new int[getChannelCount()],
|
||||||
|
getChannelCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createTexture(ByteBuffer imageBytes) {
|
||||||
|
setTextureID(glGenTextures());
|
||||||
|
glBindTexture(GL_TEXTURE_2D, getTextureID());
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
|
||||||
|
setupFilterParameters();
|
||||||
|
setupWrapParameters();
|
||||||
|
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
getInternalFormat(),
|
||||||
|
getWidth(),
|
||||||
|
getHeight(),
|
||||||
|
0,
|
||||||
|
getInternalFormat(),
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
imageBytes);
|
||||||
|
// glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupFilterParameters() {
|
||||||
|
// https://github.com/mattdesl/lwjgl-basics/wiki/textures#texture-parameters
|
||||||
|
// Set the minification and Magnifiation filters:
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupWrapParameters() {
|
||||||
|
// https://github.com/mattdesl/lwjgl-basics/wiki/textures#texture-parameters
|
||||||
|
// Each Vertex has many attributes, including Position (x, y) and Texture Coordinates (s, t).
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
47
src/main/java/org/hirw/game/TexturedMesh.java
Normal file
47
src/main/java/org/hirw/game/TexturedMesh.java
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package org.hirw.game;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL11.*;
|
||||||
|
import static org.lwjgl.opengl.GL20.*;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
public class TexturedMesh extends Mesh {
|
||||||
|
@Getter private Texture[] textures;
|
||||||
|
|
||||||
|
private final int TEXTURE_COORDS_SIZE = 2;
|
||||||
|
|
||||||
|
public TexturedMesh(Shader shader, Texture[] textures, float[] vertexArray, int[] elementArray) {
|
||||||
|
super(shader, vertexArray, elementArray);
|
||||||
|
this.textures = textures;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TexturedMesh(Shader shader, Texture[] textures) {
|
||||||
|
this(shader, textures, DEFAULT_VERTEX_ARRAY, DEFAULT_ELEMENT_ARRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int initialiseAttribPointers() {
|
||||||
|
int vertexSizeInBytes = super.initialiseAttribPointers();
|
||||||
|
|
||||||
|
int offset = (POSITION_SIZE + RGBA_SIZE) * FLOAT_SIZE_IN_BYTES;
|
||||||
|
glVertexAttribPointer(2, TEXTURE_COORDS_SIZE, GL_FLOAT, false, vertexSizeInBytes, offset);
|
||||||
|
glEnableVertexAttribArray(2);
|
||||||
|
|
||||||
|
return vertexSizeInBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int calculateVertexSizeInBytes() {
|
||||||
|
return (POSITION_SIZE + RGBA_SIZE + TEXTURE_COORDS_SIZE) * FLOAT_SIZE_IN_BYTES;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void glDraw() {
|
||||||
|
for (int i = 0; i < textures.length; i++) {
|
||||||
|
int textureUnitIndexStart = GL_TEXTURE0;
|
||||||
|
int textureUnitIndex = textureUnitIndexStart + i;
|
||||||
|
glActiveTexture(textureUnitIndex);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, getTextures()[i].getTextureID());
|
||||||
|
String uniformName = "texture" + Integer.toString(i + 1);
|
||||||
|
glUniform1i(glGetUniformLocation(getShader().getShaderProgramID(), uniformName), i);
|
||||||
|
}
|
||||||
|
super.glDraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,7 @@ import org.lwjgl.opengl.*;
|
|||||||
|
|
||||||
public class Window {
|
public class Window {
|
||||||
private int width, height;
|
private int width, height;
|
||||||
private final String title;
|
@Getter private String title;
|
||||||
@Getter private long glfwWindow;
|
@Getter private long glfwWindow;
|
||||||
|
|
||||||
private static Window window = null;
|
private static Window window = null;
|
||||||
@@ -61,7 +61,7 @@ public class Window {
|
|||||||
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
|
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
|
||||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
||||||
|
|
||||||
glfwWindow = glfwCreateWindow(this.width, this.height, "Hello World!", NULL, NULL);
|
glfwWindow = glfwCreateWindow(this.width, this.height, getTitle(), NULL, NULL);
|
||||||
if (glfwWindow == NULL) throw new RuntimeException("Failed to create the GLFW window");
|
if (glfwWindow == NULL) throw new RuntimeException("Failed to create the GLFW window");
|
||||||
|
|
||||||
glfwSetCursorPosCallback(glfwWindow, Mouse::cursorPositionCallback);
|
glfwSetCursorPosCallback(glfwWindow, Mouse::cursorPositionCallback);
|
||||||
@@ -74,7 +74,13 @@ public class Window {
|
|||||||
glfwShowWindow(glfwWindow);
|
glfwShowWindow(glfwWindow);
|
||||||
|
|
||||||
GL.createCapabilities();
|
GL.createCapabilities();
|
||||||
glClearColor(0.0f, 0.0f, 2.0f, 0.0f);
|
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createShader() {
|
private void createShader() {
|
||||||
@@ -87,15 +93,14 @@ public class Window {
|
|||||||
Mesh mesh = new Mesh(getShader());
|
Mesh mesh = new Mesh(getShader());
|
||||||
setMesh(mesh);
|
setMesh(mesh);
|
||||||
mesh.init();
|
mesh.init();
|
||||||
mesh.log();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loop() {
|
private void loop() {
|
||||||
while (!glfwWindowShouldClose(glfwWindow)) {
|
while (!glfwWindowShouldClose(glfwWindow)) {
|
||||||
Time.update();
|
Time.update();
|
||||||
SceneManager.update();
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
getMesh().draw();
|
getMesh().draw();
|
||||||
|
SceneManager.update();
|
||||||
glfwSwapBuffers(glfwWindow);
|
glfwSwapBuffers(glfwWindow);
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ public final class Log {
|
|||||||
Map.of(
|
Map.of(
|
||||||
LogType.SUCCESS, Colours.GREEN,
|
LogType.SUCCESS, Colours.GREEN,
|
||||||
LogType.ERROR, Colours.RED,
|
LogType.ERROR, Colours.RED,
|
||||||
LogType.WARNING, Colours.PURPLE));
|
LogType.WARNING, Colours.PURPLE,
|
||||||
|
LogType.DEBUG, Colours.WHITE));
|
||||||
|
|
||||||
public static void error(String errorStage, String errorDescription) {
|
public static void error(String errorStage, String errorDescription) {
|
||||||
System.out.println(formatString(LogType.ERROR, errorStage, errorDescription));
|
System.out.println(formatString(LogType.ERROR, errorStage, errorDescription));
|
||||||
@@ -43,6 +44,10 @@ public final class Log {
|
|||||||
System.out.println(formatString(LogType.WARNING, warningStage, warningDescription));
|
System.out.println(formatString(LogType.WARNING, warningStage, warningDescription));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void debug(String debugMessage) {
|
||||||
|
System.out.println(formatString(LogType.DEBUG, "DEBUG", debugMessage));
|
||||||
|
}
|
||||||
|
|
||||||
private static String formatString(LogType logType, String stage, String description) {
|
private static String formatString(LogType logType, String stage, String description) {
|
||||||
String formattedType = String.format("[%s]", colouriseString(logType, logType.toString()));
|
String formattedType = String.format("[%s]", colouriseString(logType, logType.toString()));
|
||||||
String formattedStage = colouriseString(Colours.YELLOW, String.format("<%s>", stage));
|
String formattedStage = colouriseString(Colours.YELLOW, String.format("<%s>", stage));
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ public enum LogType {
|
|||||||
SUCCESS,
|
SUCCESS,
|
||||||
WARNING,
|
WARNING,
|
||||||
ERROR,
|
ERROR,
|
||||||
|
DEBUG,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user