Collision & Engine refactor

This commit is contained in:
Harrison Corlett 2026-06-30 16:02:08 +01:00
parent f135d99d74
commit 6b51c9b680
261 changed files with 5439 additions and 185169 deletions

View file

@ -41,9 +41,15 @@ public class AudioManager {
}
public void AddSoundBuffer(String name, SoundBuffer soundBuffer){
if(this.SoundBufferMap.containsKey(name)){
SoundBufferMap.get(name).CleanUp();
}
this.SoundBufferMap.put(name,soundBuffer);
}
public void AddSoundSource(String name, AudioSource source){
if(this.SoundSourceMap.containsKey(name)){
SoundSourceMap.get(name).CleanUp();
}
this.SoundSourceMap.put(name,source);
}
public void CleanUp(){

View file

@ -121,12 +121,13 @@ public class Render {
List<GuiTexture> guiTextures = initData.GuiTextures();
String[] SkyBoxTextures = new String[]{
"resources/EngineResources/SkyBoxTextures/skySide.png",
"resources/EngineResources/SkyBoxTextures/skySide.png",
"resources/EngineResources/SkyBoxTextures/SkyTop.png",
"resources/EngineResources/SkyBoxTextures/SkyTop.png",
"resources/EngineResources/SkyBoxTextures/skySide.png",
"resources/EngineResources/SkyBoxTextures/skySide.png"
"resources/EngineResources/SkyBoxTextures/autumn_field_pureskyRight.png",
"resources/EngineResources/SkyBoxTextures/autumn_field_pureskyLeft.png",
"resources/EngineResources/SkyBoxTextures/autumn_field_pureskyUp.png",
"resources/EngineResources/SkyBoxTextures/autumn_field_pureskyDown.png",
"resources/EngineResources/SkyBoxTextures/autumn_field_pureskyFront.png",
"resources/EngineResources/SkyBoxTextures/autumn_field_pureskyBack.png",
};
textureCache.AddCubeMapTexture(RendererContext, DeferredSceneRender.SkyBoxID,SkyBoxTextures,VK_FORMAT_R8G8B8A8_SRGB);
if(guiTextures != null){
@ -184,6 +185,7 @@ public class Render {
CommandPools[i].cleanup(RendererContext);
}
Logger.debug("Command pools cleaned up");
VulkanUtils.CleanUpRemaining(RendererContext.GetDevice());
RendererContext.cleanup();
}
public void DeferredRender(EngineInstance engineInstance){
@ -212,6 +214,7 @@ public class Render {
Submit(CommandBuffer, CurrentFrame, ImageIndex);
Resize = swapChain.PresentImage(PresentQueue, RenderCompleteSemaphores[ImageIndex],ImageIndex);
CurrentFrame = (CurrentFrame + 1) % VulkanUtils.MAX_IN_FLIGHT;
VulkanUtils.ProcessDeferredDeletionQueue(RendererContext.GetDevice());
}
public void ForwardRender(EngineInstance engineInstance){
@ -237,15 +240,12 @@ public class Render {
Submit(CommandBuffer, CurrentFrame, ImageIndex);
Resize = swapChain.PresentImage(PresentQueue, RenderCompleteSemaphores[ImageIndex],ImageIndex);
CurrentFrame = (CurrentFrame + 1) % VulkanUtils.MAX_IN_FLIGHT;
VulkanUtils.ProcessDeferredDeletionQueue(RendererContext.GetDevice());
}
public void render(EngineInstance engineInstance){
if(Deferred) DeferredRender(engineInstance);
else ForwardRender(engineInstance);
// if(LastGamma != EngineConfig.getInstance().GetGamma()){
// vkDeviceWaitIdle(RendererContext.GetDevice().FetchVulkanDevice());
// PrimaryRuntime.GetRenderThread().RefreshRenderer();
// }
}
private void resize(EngineInstance engineInstance){

View file

@ -0,0 +1,50 @@
package net.halbear.Terrain4J.EngineCore.Logic.Collision;
import org.joml.Vector3f;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CollisionManager {
public static Map<String,CollisionMesh> CollisionMeshes = new HashMap<>();
public static Map<String,List<String>> CollisionChunks = new HashMap<>();
public static int ChunkWidth = 64;
public static void AddNewMesh(CollisionMesh mesh){
CollisionMeshes.put(mesh.ID, mesh);
Vector3f WorldPos = new Vector3f(mesh.WorldPosition).div(ChunkWidth);
WorldPos.x = (int)Math.floor(WorldPos.x);
WorldPos.y = (int)Math.floor(WorldPos.y);
WorldPos.z = (int)Math.floor(WorldPos.z);
String ChunkPosition = WorldPos.x + ":" + WorldPos.y + ":" + WorldPos.z;
if(!CollisionChunks.containsKey(ChunkPosition)){
List<String> newStrList = new ArrayList<>();
CollisionChunks.put(ChunkPosition, newStrList);
}
CollisionChunks.get(ChunkPosition).add(mesh.ID);
}
public static List<CollisionMesh> GetAllCollisionMeshes(){return CollisionMeshes.values().stream().toList();}
public static void UpdateCollisionChunks(){
Map<String,List<String>> newMap = new HashMap<>();
List<CollisionMesh> meshes = GetAllCollisionMeshes();
for(int i = 0; i < meshes.size(); i++){
Vector3f WorldPos = new Vector3f(meshes.get(i).WorldPosition).div(ChunkWidth);
WorldPos.x = (int)Math.floor(WorldPos.x);
WorldPos.y = (int)Math.floor(WorldPos.y);
WorldPos.z = (int)Math.floor(WorldPos.z);
String ChunkPosition = WorldPos.x + ":" + WorldPos.y + ":" + WorldPos.z;
if(!newMap.containsKey(ChunkPosition)){
List<String> newStrList = new ArrayList<>();
newMap.put(ChunkPosition, newStrList);
}
newMap.get(ChunkPosition).add(meshes.get(i).ID);
}
CollisionChunks.clear();
CollisionChunks.putAll(newMap);
}
}

View file

@ -0,0 +1,172 @@
package net.halbear.Terrain4J.EngineCore.Logic.Collision;
import net.halbear.Terrain4J.EngineCore.Main.Util.Maths.T4Math;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VertexBufferStructure;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.MeshData;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.ModelData;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.VulkanMesh;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.VulkanModel;
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils;
import org.joml.Intersectionf;
import org.joml.Quaternionf;
import org.joml.Vector2f;
import org.joml.Vector3f;
import org.lwjgl.system.MemoryUtil;
import java.io.*;
import java.nio.FloatBuffer;
import java.nio.LongBuffer;
import java.util.*;
public class CollisionMesh {
public final List<CollisionPoly> Polygons;
public Vector3f TopLeftFront = new Vector3f(0,0,0);
public Vector3f BottomRightBack = new Vector3f(0,0,0);
public Vector3f WorldPosition = new Vector3f(0,0,0);
public Quaternionf Rotation;
public Vector3f Scale;
public final String ID;
public CollisionMesh(String ID){
this.ID = ID;
Polygons = new ArrayList<>();
CollisionManager.AddNewMesh(this);
}
public CollisionMesh SetWorldPosition(Vector3f newPos){
this.WorldPosition = new Vector3f(newPos);
return this;
}
public void SetScaleTransform(Vector3f Scale){
this.Scale = new Vector3f(Scale);
}
public void SetRotationTransform(Quaternionf quaternionf){
this.Rotation = new Quaternionf(quaternionf);
}
public void GenerateCollisionMeshFromVulkanModel(ModelData vkModel) throws IOException {
Polygons.clear();
DataInputStream VertexInput = new DataInputStream(new BufferedInputStream(
new FileInputStream(vkModel.VertexPath())));
DataInputStream IndexInput = new DataInputStream(new BufferedInputStream(
new FileInputStream(vkModel.IndexPath())));
List<float[]> Vertices = new ArrayList<>();
int totalFloatCount = 0;
for (MeshData meshData : vkModel.Meshes()) {
int floatsToRead = meshData.VertexSize() / VulkanUtils.FLOAT_SIZE;
float[] meshFloats = new float[floatsToRead];
for (int i = 0; i < floatsToRead; i++) {
meshFloats[i] = VertexInput.readFloat();
}
Vertices.add(meshFloats);
totalFloatCount += floatsToRead;
}
float[] FullMeshFloatArr = new float[totalFloatCount];
int iterator = 0;
for (float[] meshFloats : Vertices) {
System.arraycopy(meshFloats, 0, FullMeshFloatArr, iterator, meshFloats.length);
iterator += meshFloats.length;
}
List<int[]> Indices = new ArrayList<>();
int IndexCount = 0;
int vertexOffset = 0;
int vertexStride = 14; // Your stride configuration
for (MeshData meshData : vkModel.Meshes()) {
int intsToRead = meshData.IndexSize() / VulkanUtils.INT_SIZE;
int[] meshIndices = new int[intsToRead];
for (int i = 0; i < intsToRead; i++) {
meshIndices[i] = IndexInput.readInt() + vertexOffset;
}
Indices.add(meshIndices);
IndexCount += intsToRead;
int meshVertexCount = (meshData.VertexSize() / VulkanUtils.FLOAT_SIZE) / vertexStride;
vertexOffset += meshVertexCount;
}
int[] FullMeshIndexArr = new int[IndexCount];
iterator = 0;
for (int[] meshIndices : Indices) {
System.arraycopy(meshIndices, 0, FullMeshIndexArr, iterator, meshIndices.length);
iterator += meshIndices.length;
}
for(int i = 0; i < IndexCount/(3); i++){
Vector3f[] points = new Vector3f[3];
for(int j = 0; j < 3; j++){
int Start = (i * 3) + j;
int elementOffset = FullMeshIndexArr[Start] * vertexStride;
points[j] = new Vector3f(
(FullMeshFloatArr[elementOffset]),
(FullMeshFloatArr[elementOffset + 1]),
(FullMeshFloatArr[elementOffset + 2])
);
}
AddNewCollisionPoly(points[0],points[1],points[2]);
}
}
public void CheckAABbounds(Vector3f v1, Vector3f v2, Vector3f v3){
float Bottom = Math.min(Math.min(v3.y, v1.y), Math.min(v3.y, v2.y));
float Left = Math.min(Math.min(v3.x, v1.x), Math.min(v3.x, v2.x));
float back = Math.min(Math.min(v3.z, v1.z), Math.min(v3.z, v2.z));
float Top = Math.max(Math.max(v3.y, v1.y), Math.max(v3.y, v2.y));
float Right = Math.max(Math.max(v3.x, v1.x), Math.max(v3.x, v2.x));
float Front = Math.max(Math.max(v3.z, v1.z), Math.max(v3.z, v2.z));
TopLeftFront.x = Math.min(TopLeftFront.x, Left);
TopLeftFront.y = Math.max(TopLeftFront.y, Top);
TopLeftFront.z = Math.max(TopLeftFront.z, Front);
BottomRightBack.x = Math.max(BottomRightBack.x, Right);
BottomRightBack.y = Math.min(BottomRightBack.y, Bottom);
BottomRightBack.z = Math.min(BottomRightBack.z, back);
}
public void AddNewCollisionPoly(Vector3f v1, Vector3f v2, Vector3f v3){
CollisionPoly newPoly = new CollisionPoly(v1,v2,v3,new Vector3f(0,0,0));
newPoly.CalculateCentre();
Polygons.add(newPoly);
CheckAABbounds(v1,v2,v3);
}
public boolean CheckAABCollision(Vector3f Origin, Vector3f Sensor){
Vector3f LineDirection = new Vector3f(Sensor).sub(Origin);
Vector2f Result = new Vector2f();
return Intersectionf.intersectRayAab(Origin, LineDirection,BottomRightBack,TopLeftFront,Result) && Result.x <= 1.0f && Result.y >= 0.0f;
}
public boolean SimpleCheckCollision(Vector3f Origin, Vector3f Sensor){
Vector3f LineDirection = new Vector3f(Sensor).sub(Origin);
Vector2f Result = new Vector2f(0,0);
if(Intersectionf.intersectRayAab(Origin, LineDirection,BottomRightBack,TopLeftFront,Result) && Result.x <= 1.0f && Result.y >= 0.0f){
for(int i = 0; i < Polygons.size(); i++){
CollisionPoly polygon = Polygons.get(i);
if(T4Math.Math3D.DoesLineCollideWithPoly(Origin,Sensor,new Vector3f[]{polygon.v1(),polygon.v2(),polygon.v3()})){
return true;
}
}
}
return false;
}
public CollisionPoly[] GetAllPolygons(){
int Rows = Polygons.size();
CollisionPoly[] PolygonArr = new CollisionPoly[Rows * 3];
for(int row = 0; row < Rows; row++){
PolygonArr[row] = Polygons.get(row).TransformScale(Scale).TransformRotation(Rotation).TransformPosition(WorldPosition);
}
return PolygonArr;
}
public Vector3f[] GetAllVertices(){
int Rows = Polygons.size();
Vector3f[] Vertices = new Vector3f[Rows * 3];
for(int row = 0; row < Rows; row++){
int StartPos = row * 3;
CollisionPoly poly = Polygons.get(row).TransformScale(Scale).TransformRotation(Rotation).TransformPosition(WorldPosition);
Vertices[StartPos] = new Vector3f(poly.v1().x,poly.v1().y,poly.v1().z);
Vertices[StartPos + 1] = new Vector3f(poly.v2().x,poly.v2().y,poly.v2().z);
Vertices[StartPos + 2] = new Vector3f(poly.v3().x,poly.v3().y,poly.v3().z);
}
return Vertices;
}
}

View file

@ -0,0 +1,75 @@
package net.halbear.Terrain4J.EngineCore.Logic.Collision;
import net.halbear.Terrain4J.EngineCore.Main.Util.Maths.T4Math;
import org.joml.Math;
import org.joml.Quaternionf;
import org.joml.Vector3f;
public record CollisionPoly(Vector3f v1, Vector3f v2, Vector3f v3, Vector3f Centre) {
public Vector3f CalculateCentre(){
float x = v1.x + v2.x + v3.x;
float y = v1.y + v2.y + v3.y;
float z = v1.z + v2.z + v3.z;
x/=3f;
y/=3f;
z/=3f;
Centre.set(new Vector3f(x,y,z));
return Centre;
}
public CollisionPoly TransformRotation(Quaternionf quaternionf){
if(quaternionf == null ) return this;
Vector3f newV1 = new Vector3f(v1);
newV1.rotate(quaternionf);
Vector3f newV2 = new Vector3f(v2);
newV2.rotate(quaternionf);
Vector3f newV3 = new Vector3f(v3);
newV3.rotate(quaternionf);
CollisionPoly newPoly = new CollisionPoly(newV1,newV2,newV3,new Vector3f());
newPoly.CalculateCentre();
return newPoly;
}
public CollisionPoly TransformScale(Vector3f Scale){
if(Scale == null ) return this;
Vector3f newV1 = new Vector3f(v1);
newV1.mul(Scale);
Vector3f newV2 = new Vector3f(v2);
newV2.mul(Scale);
Vector3f newV3 = new Vector3f(v3);
newV3.mul(Scale);
CollisionPoly newPoly = new CollisionPoly(newV1,newV2,newV3,new Vector3f());
newPoly.CalculateCentre();
return newPoly;
}
public CollisionPoly TransformPosition(Vector3f Position){
if(Position == null ) return this;
Vector3f newV1 = new Vector3f(v1);
newV1.add(Position);
Vector3f newV2 = new Vector3f(v2);
newV2.add(Position);
Vector3f newV3 = new Vector3f(v3);
newV3.add(Position);
CollisionPoly newPoly = new CollisionPoly(newV1,newV2,newV3,new Vector3f());
newPoly.CalculateCentre();
return newPoly;
}
public static CollisionPoly TransformPosition(Vector3f Position, CollisionPoly OriginalPoly){
Vector3f newV1 = new Vector3f(OriginalPoly.v1).add(Position);
Vector3f newV2 = new Vector3f(OriginalPoly.v2).add(Position);
Vector3f newV3 = new Vector3f(OriginalPoly.v3).add(Position);
CollisionPoly newPoly = new CollisionPoly(newV1,newV2,newV3,new Vector3f());
newPoly.CalculateCentre();
return newPoly;
}
public Vector3f CalculateNormal(){
Vector3f U = new Vector3f(v2.sub(v1));
Vector3f V = new Vector3f(v3.sub(v1));
Vector3f N = new Vector3f(U.mul(V));
float Nx = (U.x * V.z) - (U.z * V.y);
float Ny = (U.z * V.x) - (U.x * V.z);
float Nz = (U.x * V.y) - (U.y * V.x);
float Length = (float) Math.sqrt(T4Math.Square(Nx)+T4Math.Square(Ny)+T4Math.Square(Nz));
return new Vector3f(Nx/Length, Ny/Length, Nz/Length);
}
}

View file

@ -57,6 +57,7 @@ public class EngineConfig {
private String IconPath = "/WindowResources/Icon/";
private String DefaultTexturePath = "resources/EngineResources/Texture/NoTexture.png";
private String IconName = "ProgramIcon.png";
private String LoadingScreenLocation = "resources/EngineResources/Texture/Terrain4JTitleImage.png";
private float FOV = 60f;
private float zFarPlane;
private float zNearPlane;
@ -76,7 +77,17 @@ public class EngineConfig {
public int ShadowMapSize = 16;
public float Gamma = 0.8545f;
public int MaxVulkanCrashesAllowed = 10;
public boolean RenderCollisionMesh = true;
public boolean RenderCollisionMeshes(){
return RenderCollisionMesh;
}
public void SetRenderCollisionMesh(boolean RenderCollisionMesh){
this.RenderCollisionMesh = RenderCollisionMesh;
}
public String GetLoadingScreenImageLocation(){return LoadingScreenLocation;}
public void SetLoadingScreenImageLocation(String location){this.LoadingScreenLocation = location;}
public int GetMaxVulkanCrashes(){return MaxVulkanCrashesAllowed;}
public void SetShadowMapSize(int ShadowSize){this.ShadowMapSize = ShadowSize;}
public int GetShadowMapSize(){return ShadowMapSize;}
@ -199,6 +210,7 @@ public class EngineConfig {
}
if(SuccessfulLoad) {
IconName = (EngineConfigVar.getOrDefault("Software_Icon", "ProgramIcon.png").toString());
LoadingScreenLocation = (EngineConfigVar.getOrDefault("LoadingScreenLocation", LoadingScreenLocation).toString());
IconPath = (EngineConfigVar.getOrDefault("Software_Icon_Path", "/WindowResources/Icon/").toString());
CapMainToTickRate = Boolean.parseBoolean(EngineConfigVar.getOrDefault("cap_main_to_tickrate", true).toString());
CapFastToTickRate = Boolean.parseBoolean(EngineConfigVar.getOrDefault("cap_fast_to_tickrate", true).toString());
@ -278,6 +290,7 @@ public class EngineConfig {
EngineConfigVar.setProperty("DefaultTexturePath",DefaultTexturePath);
EngineConfigVar.setProperty("MaxDescriptors","1000");
EngineConfigVar.setProperty("anti_alias_mode","1");
EngineConfigVar.setProperty("LoadingScreenLocation",LoadingScreenLocation);
EngineConfigVar.store(new FileWriter(path.toAbsolutePath().toString() + "/" + FILENAME), "created new properties file");
Logger.debug("Wrote New Config File [{}]", ConfigFile.getAbsolutePath());
} catch (IOException excp2) {

View file

@ -0,0 +1,55 @@
package net.halbear.Terrain4J.EngineCore.Main;
import net.halbear.Terrain4J.EngineCore.Audio.AudioManager;
import net.halbear.Terrain4J.EngineCore.Audio.AudioSource;
import net.halbear.Terrain4J.EngineCore.Audio.SoundBuffer;
import org.joml.Vector3f;
public class AudioInstance {
private String SourcePath;
private String BUFFER_ID = "AUDIO_INSTANCE_BUFFER";
private String SOURCE_ID = "AUDIO_INSTANCE_SOURCE";
private String InstanceName = "";
private AudioSource audioSource;
public AudioInstance(String AudioSourcePath, String InstanceName, AudioManager manager, boolean loop){
SourcePath = AudioSourcePath;
BUFFER_ID = "AUDIO_INSTANCE_" + InstanceName + "_BUFFER";
SOURCE_ID = "AUDIO_INSTANCE_" + InstanceName + "_SOURCE";
this.InstanceName = InstanceName;
SoundBuffer buffer = new SoundBuffer(AudioSourcePath);
manager.AddSoundBuffer(BUFFER_ID, buffer);
AudioSource audioSource = new AudioSource(loop,true);
audioSource.SetBuffer(buffer.GetBufferID());
manager.AddSoundSource(SOURCE_ID,audioSource);
}
public AudioInstance(String AudioSourcePath,String InstanceName, AudioManager manager, float X, float Y, float Z, boolean loop){
SourcePath = AudioSourcePath;
BUFFER_ID = "AUDIO_INSTANCE_" + InstanceName + "_BUFFER";
SOURCE_ID = "AUDIO_INSTANCE_" + InstanceName + "_SOURCE";
this.InstanceName = InstanceName;
SoundBuffer buffer = new SoundBuffer(AudioSourcePath);
manager.AddSoundBuffer(BUFFER_ID, buffer);
AudioSource audioSource = new AudioSource(loop,false);
audioSource.SetPosition(new Vector3f(X,Y,Z));
audioSource.SetBuffer(buffer.GetBufferID());
manager.AddSoundSource(SOURCE_ID,audioSource);
}
public void ChangePath(String AudioSourcePath, AudioManager manager){
SourcePath = AudioSourcePath;
SoundBuffer buffer = new SoundBuffer(AudioSourcePath);
manager.AddSoundBuffer(BUFFER_ID, buffer);
audioSource.SetBuffer(buffer.GetBufferID());
}
public AudioInstance Play(){
audioSource.Play();
return this;
}
public String GetBufferID(){return BUFFER_ID;}
public String GetSourceID(){return SOURCE_ID;}
public String GetInstanceName(){return InstanceName;}
public String GetSourcePath(){return SourcePath;}
public AudioSource GetAudioSource(){return audioSource;}
}

View file

@ -12,12 +12,15 @@ import net.halbear.Terrain4J.EngineCore.Audio.SoundListener;
import net.halbear.Terrain4J.EngineCore.Display.Window;
import net.halbear.Terrain4J.EngineCore.Input.KeyboardInput;
import net.halbear.Terrain4J.EngineCore.Input.MouseListener;
import net.halbear.Terrain4J.EngineCore.Logic.Collision.CollisionMesh;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
import net.halbear.Terrain4J.EngineCore.Logic.GameLogic;
import net.halbear.Terrain4J.EngineCore.Logic.InitData;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.ModelLoader;
import net.halbear.Terrain4J.EngineCore.Main.Scene.*;
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.Gimbal;
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.LoadingScreen;
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.PerformanceOverlay;
import net.halbear.Terrain4J.EngineCore.Profiling.CPUMonitor;
import net.halbear.Terrain4J.EngineCore.Profiling.GPUProfiler;
@ -30,6 +33,7 @@ import org.joml.Vector3f;
import org.lwjgl.openal.AL11;
import org.tinylog.Logger;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@ -39,23 +43,10 @@ public class GameCore implements GameLogic {
private static final float MOUSE_SENSITIVITY = 0.1f;
private static final float MOVEMENT_SPEED = 0.025f;
public static boolean LoadingLevel = false;
private static final String SOUND_BUFFER_MUSIC = "music-sound-buffer";
private static final String SOUND_BUFFER_PLAYER = "player-sound-buffer";
private static final String SOUND_SOURCE_MUSIC = "music-sound-source";
private static final String SOUND_SOURCE_PLAYER = "player-sound-source";
private final Vector3f rotatingAngle = new Vector3f(0, 1, 0);
private float angle = 180;
private List<Float> angles = new ArrayList<>();
private List<Vector3f> rotatingAngles = new ArrayList<>();
private List<Vector3f> Velocities = new ArrayList<>();
private Actor CubeActor;
public List<Actor> CubeActors = new ArrayList<>();
public List<JackOfAllTradesActor> entities = new ArrayList<>();
public List<ParticleActor> particleActors = new ArrayList<>();
private Vector2f LastMousePos = new Vector2f(0,0);
private int Ticks = 0;
private int GUI_MODE = 0;
private GuiTexture guiTexture;
public List<String[]> PerformanceMetrics = new ArrayList<>();
@ -67,8 +58,14 @@ public class GameCore implements GameLogic {
public long CoolDown = 1000;
public ModelData MusicParticle;
public ModelData radio;
public ModelData MelonaData;
public ILight SkyLight;
private LoadingScreen loadingScreen;
public List<IMoveableActorComponent> ActorEditorComponents = new ArrayList<>();
private Gimbal gimbal;
private Vector2f DeltaPos = new Vector2f(0,0);
public Vector2f GetDeltaPos(){return DeltaPos;}
@Override
public void cleanup() {
@ -78,92 +75,43 @@ public class GameCore implements GameLogic {
public InitData Initialise(EngineInstance engineInstance) {
IScene scene = engineInstance.scene();
List<ModelData> models = new ArrayList<>();
MusicParticle = ModelLoader.LoadModel("resources/models/MusicParticle/MusicParticle.json");
List<MaterialData> MusicParticleMat = ModelLoader.LoadMaterials("resources/models/MusicParticle/MusicParticle_mat.json");
ModelData SponzaData = ModelLoader.LoadModel("resources/models/Forest/forest.json");
List<MaterialData> SponzaMaterial = ModelLoader.LoadMaterials("resources/models/Forest/forest_mat.json");
radio = ModelLoader.LoadModel("resources/models/radio/radio.json");
List<MaterialData> SponzaMaterial2 = ModelLoader.LoadMaterials("resources/models/radio/radio_mat.json");
// ModelData SponzaData = ModelLoader.LoadModel("resources/models/Cafe/exterior.json");
// List<MaterialData> SponzaMaterial = ModelLoader.LoadMaterials("resources/models/Cafe/exterior_mat.json");
// ModelData SponzaData1 = ModelLoader.LoadModel("resources/models/Cafe/interior.json");
// List<MaterialData> SponzaMaterial1= ModelLoader.LoadMaterials("resources/models/Cafe/interior_mat.json");
scene.AddActor(new Actor("Sponza1", SponzaData.ID(), new Vector3f(0,0f,-5f)));
// scene.AddActor(new Actor("Sponza2", SponzaData1.ID(), new Vector3f(0,0f,-5f)));
MelonaData = ModelLoader.LoadModel("resources/models/melona/melona.json");
List<MaterialData> MelonaDataMat = ModelLoader.LoadMaterials("resources/models/melona/melona_mat.json");
var Melona = new Actor("Melona", MelonaData.ID(), new Vector3f(0,0f,-5f)).SetRotation(0,(float)Math.toRadians(180),0);
CollisionMesh mesh = new CollisionMesh("Super Collision Mesh");
mesh.AddNewCollisionPoly(new Vector3f(-100,-5,0),new Vector3f(-100,-5,-100),new Vector3f(0,-5,-100));
mesh.AddNewCollisionPoly(new Vector3f(0,-5,0),new Vector3f(0,-5,-100),new Vector3f(-100,-5,0));
try {
Melona.GenerateCollisionMesh(MelonaData);
} catch(IOException e){
Logger.error("Could Not Generate Collison Mesh [{}]",e);
}
scene.AddActor(Melona);
ActorEditorComponents.add(new EditorActorComponent(Melona,new Vector3f(0,0f,-5f),new Vector3f(1.0f,1.8f,1.0f)));
CubeActors.forEach(scene::AddActor);
List<MaterialData> materials = new ArrayList<>();
materials.addAll(SponzaMaterial);
materials.addAll(MusicParticleMat);
// materials.addAll(SponzaMaterial1);
materials.addAll(SponzaMaterial2);
// models.add(SponzaData1);
models.add(SponzaData);
models.add(MusicParticle);
models.add(radio);
materials.addAll(MelonaDataMat);
models.add(MelonaData);
Camera camera = scene.GetCamera();
scene.AddCameraFrame("Default", new CameraFrame(new Vector3f(-120.10f,136.83f,-62.63f),new Vector3f(-1.90f,78.09f,0),scene.GetCamera().GetFOV(),"Second"));
scene.AddCameraFrame("Second", new CameraFrame(new Vector3f(-40.26f,141.08f,-72.12f),new Vector3f(-2.40f,143,0.0f),scene.GetCamera().GetFOV(),"Third"));
scene.AddCameraFrame("Third", new CameraFrame(new Vector3f(10.85f,149.56f,-14.10f),new Vector3f(2.5f,36.37f,0.00f),scene.GetCamera().GetFOV(),"Fourth"));
scene.AddCameraFrame("Fourth", new CameraFrame(new Vector3f(40.0f, 155.0f, -42.0f),new Vector3f(10,90,0),scene.GetCamera().GetFOV(),"Fifth"));
scene.AddCameraFrame("Fifth", new CameraFrame(new Vector3f(64.92f,158.06f,-35.25f),new Vector3f(-11.20f,156.5f,0.0f),scene.GetCamera().GetFOV(),"Sixth"));
scene.AddCameraFrame("Sixth", new CameraFrame(new Vector3f(94.52f,172.54f,47.57f),new Vector3f(4.3f,329.27f,0.0f),scene.GetCamera().GetFOV(),"NO_FRAME"));
camera.SetPosition(40.0f, 155.0f, -42.0f);
//camera.SetPosition(0,0,0);
camera.SetRotation((float) Math.toRadians(10.0f), (float) Math.toRadians(-90.0f),0);
//camera.SetRotation(0,0,0);
camera.SetPosition(0,0,0);
camera.SetRotation(0,0,0);
var LoadingScreenTexture = new GuiTexture(EngineConfig.getInstance().GetLoadingScreenImageLocation());
loadingScreen = new LoadingScreen(LoadingScreenTexture);
guiTexture = new GuiTexture("resources/EngineResources/Texture/Billy.png");
Logger.debug("GUI TEXTURE CREATED, ID->[{}], PATH->[{}]",guiTexture.ID(),guiTexture.TexturePath());
List<GuiTexture> guiTextures = new ArrayList<>();
guiTextures.add(LoadingScreenTexture);
guiTextures.add(guiTexture);
scene.GetLightingManager().GetAmbientLightColour().set(1.0f, 0.9f, 0.75f);
scene.GetLightingManager().SetAmbientLightIntensity(1.5f);
scene.GetLightingManager().SetAmbientLightIntensity(0.4f);
SkyLight = new Light(new Vector3f(1.5f, 1.20f, 1.0f),new Vector3f(0.0f, -1.0f, 0.0f), true, 10.00f);
SkyLight = new Light(new Vector3f(1.5f, 1.20f, 1.0f),new Vector3f(0.0f, -1.0f, 0.3f), true, 10.00f);
List<ILight> lights = new ArrayList<>();
//lights.add(new Light(new Vector3f(2.9f,2.75f,1.5f),new Vector3f(0.35f,2.69f,-2.11f),false,3.0f));
//lights.add(new Light(new Vector3f(3.0f,2.5f,0.75f),new Vector3f(2.65f,1.57f,-3.31f),false,0.5f));
/*lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-433, 445f, -424f),false,300000.0f+ (float)(Math.random() * 10000.0)));
lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(-210, 445f, 460f),false,70000.0f + (float)(Math.random() * 15000.0f)));
lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(-966, 445f, 204f),false,70000.0f + (float)(Math.random() * 15000.0f)));
lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(-176, 445f, 1000f),false,70000.0f + (float)(Math.random() * 15000.0f)));
lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(777, 445f, 858),false,70000.0f + (float)(Math.random() * 15000.0f)));
lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(376, 445f, -2136),false,70000.0f + (float)(Math.random() * 15000.0f)));
lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,2.0f),new Vector3f(2163, 445f, 1880),false,70000.0f + (float)(Math.random() * 15000.0f)));
lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(3334, 445f, 2405),false,70000.0f + (float)(Math.random() * 15000.0f)));
lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(3509, 445f, 1825),false,70000.0f + (float)(Math.random() * 15000.0f)));
lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(3877, 445f, 3378),false,70000.0f + (float)(Math.random() * 15000.0f)));
lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(4925, 445f, 3430),false,70000.0f + (float)(Math.random() * 15000.0f)));
lights.add(new Light(new Vector3f(1.9f+ (float)Math.random(),1.5f,1.0f),new Vector3f(-2083, 445f, -1826),false,70000.0f + (float)(Math.random() * 15000.0f)));
lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(2076, 410, 1272),false,10000.0f));
lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(2446, 465, 2303),false,10000.0f));
lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-842, 410, -1141),false,10000.0f));
lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-207, 410, -1830),false,10000.0f));
lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(899, 460, -2015),false,10000.0f));
lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(1775, 460, -3448),false,10000.0f));
lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(1800, 460, -4154),false,10000.0f));
lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-1727, 410, -387),false,10000.0f));
lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-1198, 410, -964),false,10000.0f));
lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-1778, 410, -1502),false,10000.0f));
lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-2692, 333, -2109),false,10000.0f));
lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-2849, 333, -1724),false,10000.0f));
lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-2019, 410, -729),false,10000.0f));
lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-1727, 410, -389),false,10000.0f));
lights.add(new Light(new Vector3f(1.9f + (float)Math.random(),1.5f,1.0f),new Vector3f(-1337, 410, 122),false,10000.0f));
lights.add(new Light(new Vector3f(0.75f,2.0f,0.75f),new Vector3f(1086, 425, -3375),false,50000.0f));
*/
lights.add(new Light(new Vector3f(3.0f,2.75f,0.0f),new Vector3f(35.0f, 150.0f, -42.0f),false,100.0f));
lights.add(new Light(new Vector3f(0.0f,3.0f,0.0f),new Vector3f(40.0f, 155.0f, -35.0f),false,20.0f));
lights.add(SkyLight);
ILight[] lightArr = new ILight[lights.size()];
@ -171,29 +119,29 @@ public class GameCore implements GameLogic {
scene.GetLightingManager().AddLights(lightArr);
InitiateAudio(engineInstance);
for(int i = 0; i < ActorEditorComponents.size(); i++){
ActorEditorComponents.get(i).UpdateAll();
}
return new InitData(models,materials,guiTextures);
}
public void SpawnNewActorEditorComponent(EngineInstance engineInstance){
var scene = engineInstance.scene();
var Melona = new Actor("Melona" + scene.GetActors().size(), MelonaData.ID(), new Vector3f(scene.GetCamera().GetPosition())).SetRotation(new Vector3f(scene.GetCamera().GetRotation()));
try {
Melona.GenerateCollisionMesh(MelonaData);
} catch(IOException e){
Logger.error("Could Not Generate Collison Mesh [{}]",e);
}
scene.AddActor(Melona);
ActorEditorComponents.add(new EditorActorComponent(Melona,new Vector3f(scene.GetCamera().GetPosition()),new Vector3f(1.0f,1.8f,1.0f)));
}
private void InitiateAudio(EngineInstance engineInstance){
AudioManager audioManager = engineInstance.audioManager();
Camera camera = engineInstance.scene().GetCamera();
audioManager.SetAttenuationModel(AL11.AL_EXPONENT_DISTANCE);
audioManager.SetListener(new SoundListener(camera.GetPosition()));
SoundBuffer buffer = new SoundBuffer("resources/EngineResources/audio/sounds/youusedtocallmeonyourcellphone.ogg");
audioManager.AddSoundBuffer(SOUND_BUFFER_PLAYER, buffer);
AudioSource playerAudioSource = new AudioSource(true,false);
playerAudioSource.SetPosition(new Vector3f(40.0f, 155.0f, -42.0f));
playerAudioSource.SetBuffer(buffer.GetBufferID());
audioManager.AddSoundSource(SOUND_SOURCE_PLAYER,playerAudioSource);
//playerAudioSource.Play();
buffer = new SoundBuffer("resources/EngineResources/audio/music/chimken_wing.ogg");
audioManager.AddSoundBuffer(SOUND_BUFFER_MUSIC,buffer);
AudioSource source = new AudioSource(true, true);
source.SetBuffer(buffer.GetBufferID());
audioManager.AddSoundSource(SOUND_SOURCE_MUSIC,source);
//source.Play();
}
@Override
@ -218,6 +166,7 @@ public class GameCore implements GameLogic {
camera.AddRotation((float)Math.toRadians(-deltaPos.y * Multiplier),(float)Math.toRadians(-deltaPos.x * Multiplier),0);
}
DeltaPos = new Vector2f(deltaPos);
engineInstance.audioManager().UpdateListenerPosition(camera);
}
@ -247,14 +196,17 @@ public class GameCore implements GameLogic {
KeyboardInput input = window.getKeyboardInput();
float MovementDist = (float)(FrameDiffNanoSeconds / 1000000L) * MOVEMENT_SPEED;
Camera camera = scene.GetCamera();
if(input.keyPressed(GLFW_KEY_1)){
GUI_MODE = 0;
if(input.keyPressed(GLFW_KEY_F3)){
GUI_MODE = (GUI_MODE + 1) % 2;
}
if(input.keyPressed(GLFW_KEY_2)){
GUI_MODE = 1;
if(input.keyPressed(GLFW_KEY_1)) {
Gimbal.universalType = Gimbal.GimbalType.Move;
}
if(input.keyPressed(GLFW_KEY_3)){
GUI_MODE = 2;
if(input.keyPressed(GLFW_KEY_2)) {
Gimbal.universalType = Gimbal.GimbalType.Resize;
}
if(input.keyPressed(GLFW_KEY_3)) {
Gimbal.universalType = Gimbal.GimbalType.Rotate;
}
if(input.keyPressed(GLFW_KEY_W)){
camera.MoveForward(MovementDist);
@ -294,28 +246,20 @@ public class GameCore implements GameLogic {
| ImGuiWindowFlags.NoNav
| ImGuiWindowFlags.NoMove;
ImGui.newFrame();
if(GUI_MODE == 0){
PerformanceOverlay overlay = new PerformanceOverlay();
overlay.RenderGUI(engineInstance,frameTimeNS,this);
} else if (GUI_MODE == 1){
ImGui.setNextWindowPos(0,0, ImGuiCond.Always);
ImGui.setNextWindowSize(500,500);
ImGui.begin("Test Window");
ImGui.image(PrimaryRuntime.GetRenderThread().GetRenderer().GetGuiTexture(guiTexture.ID()),300,300);
Logger.debug(PrimaryRuntime.GetRenderThread().GetRenderer().GetGuiTexture(guiTexture.ID()));
ImGui.end();
} else if (GUI_MODE == 2){
}
if (ChangeGraphicsSettings){
ImGuiViewport viewport = ImGui.getMainViewport();
float CenterX = viewport.getWorkPosX() + viewport.getWorkSizeX() / 2.0f;
float CenterY = viewport.getWorkPosY() + viewport.getWorkSizeY() / 2.0f;
ImGui.setNextWindowPos(CenterX,CenterY, ImGuiCond.Always,0.5f,0.5f);
ImGui.begin("change notification",windowFlags);
ImGui.setWindowFontScale(4.0f);
ImGui.text("APPLYING GRAPHICS SETTINGS...");
ImGui.end();
if(LoadingLevel){
loadingScreen.RenderGUI(engineInstance,frameTimeNS,this);
} else {
engineInstance.scene().RenderGUIs(engineInstance, frameTimeNS, this);
if (ChangeGraphicsSettings) {
ImGuiViewport viewport = ImGui.getMainViewport();
float CenterX = viewport.getWorkPosX() + viewport.getWorkSizeX() / 2.0f;
float CenterY = viewport.getWorkPosY() + viewport.getWorkSizeY() / 2.0f;
ImGui.setNextWindowPos(CenterX, CenterY, ImGuiCond.Always, 0.5f, 0.5f);
ImGui.begin("change notification", windowFlags);
ImGui.setWindowFontScale(4.0f);
ImGui.text("APPLYING GRAPHICS SETTINGS...");
ImGui.end();
}
}
ImGui.endFrame();
ImGui.render();
@ -325,26 +269,10 @@ public class GameCore implements GameLogic {
@Override
public void Update(EngineInstance engineInstance, long FrameDiffNanoSeconds) {
float DeltaTime = (float)(FrameDiffNanoSeconds/16000000.0);
}
@Override
public void UpdateFastThread(EngineInstance engineInstance, long FrameDiffNanoSeconds) {
float DeltaTime = (float)(FrameDiffNanoSeconds/16000000.0);
for(int i = 0; i < angles.size(); i++) {
angles.set(i, (angles.get(i) + 1.0f* DeltaTime) % 360);
CubeActors.get(i).GetRotation().identity().rotateAxis((float) EngineConfig.DegToRad * angles.get(i), rotatingAngles.get(i));
CubeActors.get(i).GetPosition().add((Velocities.get(i).x/100.0f) * DeltaTime,(Velocities.get(i).y/100.0f) * DeltaTime,(Velocities.get(i).z/100.0f) * DeltaTime);
CubeActors.get(i).UpdateModelMatrix();
}
Ticks++;
if(Ticks == 1000){
// engineInstance.scene().StartCameraTrack("Default","Second",24000);
}
for(int i = 0; i < entities.size(); i++){
JackOfAllTradesActor entity = entities.get(i);
entity.tick(engineInstance.scene());
}
}
@Override

View file

@ -91,6 +91,7 @@ public class PrimaryRuntime {
}
public void PrimaryRuntimeInputUpdate(long nsTimeDiff){
gameLogic.Input(PrimaryRuntime.GetEngineInstance(), (nsTimeDiff));
gameLogic.CameraInput(PrimaryRuntime.GetEngineInstance(), (nsTimeDiff));
}
@ -139,6 +140,7 @@ public class PrimaryRuntime {
}
ShutDownStart = System.nanoTime();
Logger.debug("Closing Software of name [{}]",EngineConfig.getInstance().GetSoftwareName());
FastThread.KillThread();
PrimaryThread.KillThread();
DrawingThread.KillThread();
cleanup();
@ -158,11 +160,18 @@ public class PrimaryRuntime {
if (ThreadsOpen > 0 || VulkanContext.VulkanLayersOpen > -1) {
Logger.debug("Waiting to close Primary Thread, making sure vulkan has shut down properly first and Engine Threads are closed\nThreads Open:[{}]\nVulkan Layers Open:[{}]", ThreadsOpen, VulkanContext.VulkanLayersOpen < 0 ? "All processes closed and vulkan instance removed" : VulkanContext.VulkanLayersOpen);
while ((ThreadsOpen > 0 || VulkanContext.VulkanLayersOpen > 0) && VulkanContext.VulkanLayersOpen > -1 && !CanClose) {
if (!DrawingThread.FetchThread().isAlive() && !PrimaryThread.FetchThread().isAlive() && ThreadsOpen >0){
if (!DrawingThread.FetchThread().isAlive() && !PrimaryThread.FetchThread().isAlive() && !FastThread.FetchThread().isAlive() && ThreadsOpen >0){
break;
}
if(FastThread.FetchThread().isAlive()){
FastThread.FetchThread().interrupt();
}
}
}
while(FastThread.FetchThread().isAlive()){
FastTickThread.running = false;
FastThread.FetchThread().interrupt();
}
Logger.debug("Closing Primary Thread, Thread: [{}]",Thread.currentThread().toString());
double ShutDownTime = Math.floor(((double)(System.nanoTime() - ShutDownStart)/1000000.0)*1000.0)/1000.0;
Logger.info("Successful stable Shut Down of Terrain4J in [{}] MilliSeconds", ShutDownTime);

View file

@ -1,43 +1,83 @@
package net.halbear.Terrain4J.EngineCore.Main.Scene;
import net.halbear.Terrain4J.EngineCore.Logic.Collision.CollisionMesh;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.ModelData;
import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.io.IOException;
public class Actor{
private final String ID;
private final String ModelID;
private final Matrix4f ModelMatrix;
private final Vector3f Position;
private final Quaternionf Rotation;
private float Scale;
private CollisionMesh collisionMesh;
private Vector3f Scale;
public CollisionMesh GetCollisionMesh(){
return collisionMesh;
}
public Actor(String ID, String ModelID, Vector3f Position){
this.ID = ID;
this.ModelID = ModelID;
this.Position = Position;
Scale = 1f;
Scale = new Vector3f(1f,1f,1f);
Rotation = new Quaternionf();
ModelMatrix = new Matrix4f();
UpdateModelMatrix();
}
public void ResetRotation(){
public Actor GenerateCollisionMesh(ModelData modelData) throws IOException {
collisionMesh = new CollisionMesh(ID + "_COLLISION_MESH");
collisionMesh.GenerateCollisionMeshFromVulkanModel(modelData);
return this;
}
public Actor ResetRotation(){
Rotation.x = 0;
Rotation.y = 0;
Rotation.z = 0;
Rotation.w = 1.0f;
return this;
}
public final void SetPosition(float x, float y, float z){
public Actor SetRotation(Vector3f rot){
Rotation.rotateX(rot.x);
Rotation.rotateY(rot.y);
Rotation.rotateZ(rot.z);
UpdateModelMatrix();
return this;
}
public Actor SetRotation(float x, float y, float z){
Rotation.rotateX(x);
Rotation.rotateY(y);
Rotation.rotateZ(z);
UpdateModelMatrix();
return this;
}
public Actor SetPosition(float x, float y, float z){
Position.x = x;
Position.y = y;
Position.z = z;
UpdateModelMatrix();
return this;
}
public Actor SetScale(float x, float y, float z){
Scale.x = x;
Scale.y = y;
Scale.z = z;
UpdateModelMatrix();
return this;
}
public Actor SetScale(float Scale){
this.Scale = Scale;
this.Scale = new Vector3f(Scale,Scale,Scale);
UpdateModelMatrix();
return this;
}
@ -51,5 +91,5 @@ public class Actor{
public Matrix4f GetModelMatrix(){return ModelMatrix;}
public Vector3f GetPosition(){ return Position;}
public Quaternionf GetRotation(){return Rotation;}
public float GetScale(){return Scale;}
public Vector3f GetScale(){return Scale;}
}

View file

@ -0,0 +1,118 @@
package net.halbear.Terrain4J.EngineCore.Main.Scene;
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.Gimbal;
import org.joml.Vector3f;
public class EditorActorComponent implements IMoveableActorComponent{
public static int ActorComponentCount = 0;
private Gimbal ActorGimbal;
private Actor actor;
private Vector3f Position;
private Vector3f ActorDimensions;
private String ID = "ActorComponent";
public EditorActorComponent(Actor actor, Vector3f Position, Vector3f Dimensions){
ID = actor.GetID() + "_COMPONENT" + ActorComponentCount;
this.Position = new Vector3f(Position);
this.actor = actor;
this.ActorDimensions = new Vector3f(Dimensions);
ActorGimbal = new Gimbal(Position, new Vector3f(1.0f,1.0f,1.0f),this).SetID(ID);
ActorComponentCount++;
UpdateAll();
}
@Override
public void UpdateAll() {
actor.GetPosition().set(Position.x,Position.y,Position.z);
if(actor.GetCollisionMesh() != null) {
actor.GetCollisionMesh().SetWorldPosition(new Vector3f(Position.x,Position.y,Position.z));
actor.GetCollisionMesh().SetRotationTransform(actor.GetRotation());
actor.GetCollisionMesh().SetScaleTransform(actor.GetScale());
}
ActorGimbal.SetPosition(new Vector3f(Position.x, Position.y + ActorDimensions.y/2, Position.z));
}
@Override
public Actor GetActor() {
return actor;
}
@Override
public void SetActor(Actor actor) {
this.actor = actor;
}
@Override
public void AddPosition(Vector3f addedPos) {
Vector3f Pos = actor.GetPosition();
actor.SetPosition(Pos.x + addedPos.x, Pos.y + addedPos.y, Pos.z + addedPos.z);
Position = new Vector3f(actor.GetPosition());
UpdateAll();
}
@Override
public void AddRotation(Vector3f addedRot) {
actor.SetRotation( addedRot.x, addedRot.y, addedRot.z);
}
@Override
public void AddScale(Vector3f addedScale) {
Vector3f scale = actor.GetScale();
actor.SetScale(scale.x + addedScale.x, scale.y + addedScale.y, scale.z + addedScale.z);
}
@Override
public Vector3f GetPosition() {
return Position;
}
@Override
public Gimbal GetActorGimbal() {
return ActorGimbal;
}
@Override
public void SetActorGimbal(Gimbal gimbal) {
this.ActorGimbal = gimbal;
}
@Override
public void SetPosition(float x, float y, float z) {
this.Position = new Vector3f(x,y,z);
UpdateAll();
}
@Override
public void SetPosition(Vector3f Position) {
this.Position = new Vector3f(Position);
UpdateAll();
}
@Override
public void SetActorDimensions(float x, float y, float z) {
ActorDimensions = new Vector3f(x,y,z);
UpdateAll();
}
@Override
public Vector3f GetActorDimensions() {
return ActorDimensions;
}
@Override
public void SetActorScale(float scale) {
actor.SetScale(scale);
}
@Override
public void SetActorScale(Vector3f scale) {
actor.SetScale(scale.x,scale.y,scale.z);
}
@Override
public Vector3f GetActorScale() {
return actor.GetScale();
}
}

View file

@ -0,0 +1,308 @@
package net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs;
import imgui.ImDrawList;
import imgui.ImGui;
import imgui.ImVec2;
import imgui.flag.ImGuiCol;
import imgui.flag.ImGuiWindowFlags;
import net.halbear.Terrain4J.EngineCore.Logic.Collision.CollisionManager;
import net.halbear.Terrain4J.EngineCore.Logic.Collision.CollisionMesh;
import net.halbear.Terrain4J.EngineCore.Logic.Collision.CollisionPoly;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
import net.halbear.Terrain4J.EngineCore.Main.GameCore;
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIOverlay;
import net.halbear.Terrain4J.EngineCore.Main.Scene.IMoveableActorComponent;
import net.halbear.Terrain4J.EngineCore.Main.Util.Maths.T4Math;
import org.joml.Matrix4f;
import org.joml.Vector2f;
import org.joml.Vector3f;
import org.tinylog.Logger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Gimbal implements GUIOverlay {
private IMoveableActorComponent parent;
public static Map<String, Gimbal> gimbalMap = new HashMap<>();
public static GimbalType universalType = GimbalType.Move;
private static Vector2f LastMousePos;
private static Vector2f MouseDiff = new Vector2f(0,0);
public static void RenderGimbals(EngineInstance engineInstance, long FrameTimeNS, GameCore parent){
Vector2f CurrentMousePos = new Vector2f(engineInstance.window().getMouseInput().getCurrentPos());
if(LastMousePos != null) MouseDiff = new Vector2f(CurrentMousePos).sub(LastMousePos);
LastMousePos = new Vector2f(CurrentMousePos);
List<Gimbal> gimbals = gimbalMap.values().stream().toList();
int winWidth = engineInstance.window().getWidth();
int winHeight = engineInstance.window().getHeight();
ImGui.setNextWindowPos(0, 0);
ImGui.setNextWindowSize(winWidth, winHeight);
int flags = ImGuiWindowFlags.NoTitleBar |
ImGuiWindowFlags.NoBringToFrontOnFocus |
ImGuiWindowFlags.NoResize |
ImGuiWindowFlags.NoMove |
ImGuiWindowFlags.NoScrollbar |
ImGuiWindowFlags.NoBackground |
ImGuiWindowFlags.NoSavedSettings;
ImGui.begin("WorldSpaceUIOverlay", flags);
ImGui.getStyle().setAntiAliasedLines(true);
if(EngineConfig.getInstance().RenderCollisionMesh){
List<CollisionMesh> meshes = CollisionManager.GetAllCollisionMeshes();
for(int i = 0; i < meshes.size(); i++){
CollisionMesh mesh = meshes.get(i);
CollisionPoly[] polygons = mesh.GetAllPolygons();
for(int j = 0; j < polygons.length; j++){
DrawCollisionPolygon(engineInstance.scene().GetCamera().GetViewMatrix(), engineInstance.scene().GetProjection().GetProjectionMatrix(),winWidth,winHeight,polygons[j]);
}
}
}
for(int i = 0; i < gimbals.size(); i++){
gimbals.get(i).DrawGimbalInWorld(engineInstance.scene().GetCamera().GetViewMatrix(), engineInstance.scene().GetProjection().GetProjectionMatrix(),winWidth,winHeight);
}
ImGui.end();
}
public enum GimbalType{
Move,
Resize,
Rotate
}
private Vector3f Position = new Vector3f(0,0,0);
private Vector3f GimbalArmLengths = new Vector3f(1.0f,1.0f,1.0f);
private String ID = "Gimbal";
public Gimbal(Vector3f pos, Vector3f GimbalArmLengths, IMoveableActorComponent parent){
this.parent = parent;
Position = new Vector3f(pos);
this.GimbalArmLengths = new Vector3f(GimbalArmLengths);
}
public Gimbal SetID(String IDIn){
this.ID = IDIn;
gimbalMap.put(ID, this);
return this;
}
public Gimbal SetGimbalType(GimbalType type){
universalType = type;
return this;
}
public void SetPosition(Vector3f vector3f){
Position = new Vector3f(vector3f);
}
public void SetArmLengths(Vector3f gimbalArmLengths){
GimbalArmLengths = new Vector3f(gimbalArmLengths);
}
@Override
public void RenderGUI(EngineInstance engineInstance, long FrameTimeNS, GameCore parent) {
Vector2f CurrentMousePos = new Vector2f(engineInstance.window().getMouseInput().getCurrentPos());
if(LastMousePos != null) MouseDiff = new Vector2f(CurrentMousePos).sub(LastMousePos);
LastMousePos = new Vector2f(CurrentMousePos);
DrawGimbalInWorld(engineInstance.scene().GetCamera().GetViewMatrix(), engineInstance.scene().GetProjection().GetProjectionMatrix(),engineInstance.window().getWidth(),engineInstance.window().getHeight());
}
public static void DrawCollisionPolygon(Matrix4f viewMatrix, Matrix4f projMatrix, int winWidth, int winHeight, CollisionPoly polygon){
if(polygon == null || polygon.v1() == null || polygon.v2() == null || polygon.v3() == null) return;
Vector3f v1 = T4Math.Math3D.GetScreenCoordFromWorldSpace(polygon.v1(), viewMatrix, projMatrix, winWidth, winHeight);
Vector3f v2 = T4Math.Math3D.GetScreenCoordFromWorldSpace(polygon.v2(), viewMatrix, projMatrix, winWidth, winHeight);
Vector3f v3 = T4Math.Math3D.GetScreenCoordFromWorldSpace(polygon.v3(), viewMatrix, projMatrix, winWidth, winHeight);
if(v1 == null || v2 == null || v3 == null) return;
ImDrawList drawList = ImGui.getBackgroundDrawList();
int colour = ImGui.getColorU32(0.0f, 0.0f, 0.0f, 1.0f);
drawList.addLine(v1.x, v1.y, v2.x, v2.y, colour, 1f);
drawList.addLine(v2.x, v2.y, v3.x, v3.y, colour, 1f);
drawList.addLine(v3.x, v3.y, v1.x, v1.y, colour, 1f);
colour = ImGui.getColorU32(0.0f, 0.4f, 1.0f, 0.3f);
drawList.addTriangleFilled(
new ImVec2(v1.x,v1.y),
new ImVec2(v2.x,v2.y),
new ImVec2(v3.x,v3.y)
,colour);
}
public void DrawGimbalInWorld(Matrix4f viewMatrix, Matrix4f projMatrix, int winWidth, int winHeight) {
Vector3f CentrePoint = new Vector3f(Position);
Vector3f XCPoint = new Vector3f(Position.x + (GimbalArmLengths.x/2.5f),Position.y,Position.z);
Vector3f YCPoint = new Vector3f(Position.x,Position.y + (GimbalArmLengths.y/2.5f),Position.z);
Vector3f ZCPoint = new Vector3f(Position.x,Position.y,Position.z + (GimbalArmLengths.z/2.5f));
Vector3f ZYPoint = new Vector3f(Position.x,Position.y + (GimbalArmLengths.y/2.5f),Position.z + (GimbalArmLengths.z/2.5f));
Vector3f XPoint = new Vector3f(Position.x + GimbalArmLengths.x,Position.y,Position.z);
Vector3f XYPoint = new Vector3f(Position.x + (GimbalArmLengths.x/2.5f),Position.y+ (GimbalArmLengths.y/2.5f),Position.z);
Vector3f XZPoint = new Vector3f(Position.x + (GimbalArmLengths.x/2.5f),Position.y,Position.z + (GimbalArmLengths.z/2.5f));
Vector3f YPoint = new Vector3f(Position.x,Position.y + GimbalArmLengths.y,Position.z);
Vector3f ZPoint = new Vector3f(Position.x,Position.y,Position.z + GimbalArmLengths.z);
Vector3f CentreScreenPos = T4Math.Math3D.GetScreenCoordFromWorldSpace(CentrePoint, viewMatrix, projMatrix, winWidth, winHeight);
Vector3f XCScreenPos = T4Math.Math3D.GetScreenCoordFromWorldSpace(XCPoint, viewMatrix, projMatrix, winWidth, winHeight);
Vector3f YCScreenPos = T4Math.Math3D.GetScreenCoordFromWorldSpace(YCPoint, viewMatrix, projMatrix, winWidth, winHeight);
Vector3f ZCScreenPos = T4Math.Math3D.GetScreenCoordFromWorldSpace(ZCPoint, viewMatrix, projMatrix, winWidth, winHeight);
Vector3f ZYScreenPos = T4Math.Math3D.GetScreenCoordFromWorldSpace(ZYPoint, viewMatrix, projMatrix, winWidth, winHeight);
Vector3f XYScreenPos = T4Math.Math3D.GetScreenCoordFromWorldSpace(XYPoint, viewMatrix, projMatrix, winWidth, winHeight);
Vector3f XZScreenPos = T4Math.Math3D.GetScreenCoordFromWorldSpace(XZPoint, viewMatrix, projMatrix, winWidth, winHeight);
Vector3f XPointScreenPos = T4Math.Math3D.GetScreenCoordFromWorldSpace(XPoint, viewMatrix, projMatrix, winWidth, winHeight);
Vector3f YPointScreenPos = T4Math.Math3D.GetScreenCoordFromWorldSpace(YPoint, viewMatrix, projMatrix, winWidth, winHeight);
Vector3f ZPointScreenPos = T4Math.Math3D.GetScreenCoordFromWorldSpace(ZPoint, viewMatrix, projMatrix, winWidth, winHeight);
if (CentreScreenPos == null) return;
ImDrawList drawList = ImGui.getBackgroundDrawList();
float thickness = 5.0f;
float ButtonMultiplier = 6.0f;
float buttonWidth = thickness * ButtonMultiplier;
float buttonHeight = thickness * ButtonMultiplier;
int color = ImGui.getColorU32(1.0f, 0.0f, 0.0f, 1.0f);
ImGui.pushStyleColor(ImGuiCol.Button, 0.0f, 0.0f, 0.0f, 0.0f);
ImGui.pushStyleColor(ImGuiCol.ButtonHovered, 1.0f, 1.0f, 1.0f, 0.2f);
ImGui.pushStyleColor(ImGuiCol.ButtonActive, 1.0f, 1.0f, 1.0f, 0.4f);
if(XPointScreenPos != null) {
drawList.addLine(CentreScreenPos.x, CentreScreenPos.y, XPointScreenPos.x, XPointScreenPos.y, color, thickness);
float adjustedX = XPointScreenPos.x - (buttonWidth / 2.0f);
float adjustedY = XPointScreenPos.y - (buttonHeight / 2.0f);
ImGui.setCursorScreenPos(adjustedX, adjustedY);
ImGui.button("X##" + ID, buttonWidth, buttonHeight);
switch(universalType) {
case Rotate:
ImVec2 Right = new ImVec2(XPointScreenPos.x, XPointScreenPos.y).plus(new ImVec2(thickness * ButtonMultiplier/2.0f,0));
ImVec2 Left = new ImVec2(XPointScreenPos.x, XPointScreenPos.y).minus(new ImVec2(thickness * ButtonMultiplier/2.0f,0));
ImVec2 Bottom = new ImVec2(XPointScreenPos.x, XPointScreenPos.y).minus(new ImVec2(0,thickness * ButtonMultiplier/2.0f));
ImVec2 Top = new ImVec2(XPointScreenPos.x, XPointScreenPos.y).plus(new ImVec2(0,thickness * ButtonMultiplier/2.0f));
drawList.addQuadFilled(Left,Top,Right,Bottom,color);
break;
case Resize:
drawList.addRectFilled(XPointScreenPos.x- (thickness * ButtonMultiplier/2.0f), XPointScreenPos.y- (thickness * ButtonMultiplier/2.0f), XPointScreenPos.x+ (thickness * ButtonMultiplier/2.0f), XPointScreenPos.y + (thickness * ButtonMultiplier/2.0f), color);
break;
case Move:
default:
drawList.addCircleFilled(XPointScreenPos.x, XPointScreenPos.y, thickness * ButtonMultiplier/2.0f, color);
break;
}
if (ImGui.isItemActive()) {
switch(universalType) {
case Rotate:
parent.AddRotation(new Vector3f(0,(float) ((MouseDiff.x + MouseDiff.y) / (float) (winWidth / 10.0f)),0));
break;
case Resize:
parent.AddScale(new Vector3f((MouseDiff.x + MouseDiff.y) / (float) (winWidth / 10.0f), 0, 0));
break;
case Move:
default:
parent.AddPosition(new Vector3f((MouseDiff.x + MouseDiff.y) / (float) (winWidth / 10.0f), 0, 0));
break;
}
parent.UpdateAll();
}
}
color = ImGui.getColorU32(1.0f, 0.0f, 0.0f, 0.4f);
if(XYScreenPos != null && YCScreenPos != null && XCScreenPos != null) {
drawList.addConvexPolyFilled(new ImVec2[]{
new ImVec2(CentreScreenPos.x,CentreScreenPos.y),
new ImVec2(XCScreenPos.x,XCScreenPos.y),
new ImVec2(XYScreenPos.x,XYScreenPos.y),
new ImVec2(YCScreenPos.x,YCScreenPos.y),
},4,color);
}
color = ImGui.getColorU32(0.0f, 1.0f, 0.0f, 1.0f);
if(YPointScreenPos != null) {
drawList.addLine(CentreScreenPos.x, CentreScreenPos.y, YPointScreenPos.x, YPointScreenPos.y, color, thickness);
float adjustedX = YPointScreenPos.x - (buttonWidth / 2.0f);
float adjustedY = YPointScreenPos.y - (buttonHeight / 2.0f);
ImGui.setCursorScreenPos(adjustedX, adjustedY);
ImGui.button("Y##" + ID, buttonWidth, buttonHeight);
switch(universalType) {
case Rotate:
ImVec2 Right = new ImVec2(YPointScreenPos.x, YPointScreenPos.y).plus(new ImVec2(thickness * ButtonMultiplier/2.0f,0));
ImVec2 Left = new ImVec2(YPointScreenPos.x, YPointScreenPos.y).minus(new ImVec2(thickness * ButtonMultiplier/2.0f,0));
ImVec2 Bottom = new ImVec2(YPointScreenPos.x, YPointScreenPos.y).minus(new ImVec2(0,thickness * ButtonMultiplier/2.0f));
ImVec2 Top = new ImVec2(YPointScreenPos.x, YPointScreenPos.y).plus(new ImVec2(0,thickness * ButtonMultiplier/2.0f));
drawList.addQuadFilled(Left,Top,Right,Bottom,color);
break;
case Resize:
drawList.addRectFilled(YPointScreenPos.x- (thickness * ButtonMultiplier/2.0f), YPointScreenPos.y- (thickness * ButtonMultiplier/2.0f), YPointScreenPos.x+ (thickness * ButtonMultiplier/2.0f), YPointScreenPos.y + (thickness * ButtonMultiplier/2.0f), color);
break;
case Move:
default:
drawList.addCircleFilled(YPointScreenPos.x, YPointScreenPos.y, thickness * ButtonMultiplier/2.0f, color);
break;
}
if (ImGui.isItemActive()) {
switch(universalType) {
case Rotate:
parent.AddRotation(new Vector3f((float) ((MouseDiff.x + MouseDiff.y) / (float) (winWidth / 10.0f)),0,0));
break;
case Resize:
parent.AddScale(new Vector3f(0, (MouseDiff.x + MouseDiff.y) / (float) (winWidth / 10.0f), 0));
break;
case Move:
default:
parent.AddPosition(new Vector3f(0,-(MouseDiff.y)/(float)(winHeight/10.0f), 0));
break;
}
parent.UpdateAll();
}
}
color = ImGui.getColorU32(0.0f, 1.0f, 0.0f, 0.4f);
if(XZScreenPos != null && ZCScreenPos != null && XCScreenPos != null) {
drawList.addConvexPolyFilled(new ImVec2[]{
new ImVec2(CentreScreenPos.x,CentreScreenPos.y),
new ImVec2(XCScreenPos.x,XCScreenPos.y),
new ImVec2(XZScreenPos.x,XZScreenPos.y),
new ImVec2(ZCScreenPos.x,ZCScreenPos.y),
},4,color);
}
color = ImGui.getColorU32(0.0f, 0.0f, 1.0f, 1.0f);
if(ZPointScreenPos != null) {
drawList.addLine(CentreScreenPos.x, CentreScreenPos.y, ZPointScreenPos.x, ZPointScreenPos.y, color, thickness);
float adjustedX = ZPointScreenPos.x - (buttonWidth / 2.0f);
float adjustedY = ZPointScreenPos.y - (buttonHeight / 2.0f);
ImGui.setCursorScreenPos(adjustedX, adjustedY);
ImGui.button("Z##" + ID, buttonWidth, buttonHeight);
switch(universalType) {
case Rotate:
ImVec2 Right = new ImVec2(ZPointScreenPos.x, ZPointScreenPos.y).plus(new ImVec2(thickness * ButtonMultiplier/2.0f,0));
ImVec2 Left = new ImVec2(ZPointScreenPos.x, ZPointScreenPos.y).minus(new ImVec2(thickness * ButtonMultiplier/2.0f,0));
ImVec2 Bottom = new ImVec2(ZPointScreenPos.x, ZPointScreenPos.y).minus(new ImVec2(0,thickness * ButtonMultiplier/2.0f));
ImVec2 Top = new ImVec2(ZPointScreenPos.x, ZPointScreenPos.y).plus(new ImVec2(0,thickness * ButtonMultiplier/2.0f));
drawList.addQuadFilled(Left,Top,Right,Bottom,color);
break;
case Resize:
drawList.addRectFilled(ZPointScreenPos.x- (thickness * ButtonMultiplier/2.0f), ZPointScreenPos.y- (thickness * ButtonMultiplier/2.0f), ZPointScreenPos.x+ (thickness * ButtonMultiplier/2.0f), ZPointScreenPos.y + (thickness * ButtonMultiplier/2.0f), color);
break;
case Move:
default:
drawList.addCircleFilled(ZPointScreenPos.x, ZPointScreenPos.y, thickness * ButtonMultiplier/2.0f, color);
break;
}
if (ImGui.isItemActive()) {
switch(universalType) {
case Rotate:
parent.AddRotation(new Vector3f(0,0,(float) ((MouseDiff.x + MouseDiff.y) / (float) (winWidth / 10.0f))));
break;
case Resize:
parent.AddScale(new Vector3f( 0, 0,(MouseDiff.x + MouseDiff.y) / (float) (winWidth / 10.0f)));
break;
case Move:
default:
parent.AddPosition(new Vector3f(0,0, (-MouseDiff.x + MouseDiff.y)/(float)(winWidth/10.0f)));
break;
}
parent.UpdateAll();
}
}
color = ImGui.getColorU32(0.0f, 0.0f, 1.0f, 0.4f);
if(ZYScreenPos != null && YCScreenPos != null && ZCScreenPos != null) {
drawList.addConvexPolyFilled(new ImVec2[]{
new ImVec2(CentreScreenPos.x,CentreScreenPos.y),
new ImVec2(ZCScreenPos.x,ZCScreenPos.y),
new ImVec2(ZYScreenPos.x,ZYScreenPos.y),
new ImVec2(YCScreenPos.x,YCScreenPos.y),
},4,color);
}
ImGui.popStyleColor(3);
}
}

View file

@ -0,0 +1,48 @@
package net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs;
import imgui.ImGui;
import imgui.ImGuiViewport;
import imgui.flag.ImGuiCol;
import imgui.flag.ImGuiCond;
import imgui.flag.ImGuiWindowFlags;
import imgui.type.ImFloat;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
import net.halbear.Terrain4J.EngineCore.Main.GameCore;
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIOverlay;
import net.halbear.Terrain4J.EngineCore.Vulkan.GUI.GuiTexture;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen.DeferredSceneRender;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen.ForwardSceneRender;
import org.joml.Vector3f;
import org.tinylog.Logger;
public class LoadingScreen implements GUIOverlay {
private final ImFloat GammaValue = new ImFloat(0.8545f);
private final GuiTexture LoadingTexture;
public LoadingScreen(GuiTexture LoadingScreenTexture){
LoadingTexture = LoadingScreenTexture;
}
@Override
public void RenderGUI(EngineInstance engineInstance, long frameTimeNS, GameCore parent) {
int windowFlags = ImGuiWindowFlags.NoDecoration
| ImGuiWindowFlags.AlwaysAutoResize
| ImGuiWindowFlags.NoSavedSettings
| ImGuiWindowFlags.NoFocusOnAppearing
| ImGuiWindowFlags.NoNav
| ImGuiWindowFlags.NoMove;
ImGuiViewport viewport = ImGui.getMainViewport();
float CenterX = viewport.getWorkPosX() + viewport.getWorkSizeX() / 2.0f;
float CenterY = viewport.getWorkPosY() + viewport.getWorkSizeY() / 2.0f;
ImGui.setNextWindowPos(0,0, ImGuiCond.Always);
ImGui.setNextWindowSize(viewport.getWorkSizeX(),viewport.getWorkSizeY());
ImGui.pushStyleColor(ImGuiCol.WindowBg, 0,0.1f,0.5f,1.0f);
ImGui.begin("Loading Screen BG",windowFlags);
ImGui.end();
ImGui.setNextWindowPos(CenterX,CenterY, ImGuiCond.Always,0.5f,0.5f);
ImGui.pushStyleColor(ImGuiCol.WindowBg, 0,0.1f,0.5f,0.0f);
ImGui.begin("Loading Screen",windowFlags);
ImGui.image(PrimaryRuntime.GetRenderThread().GetRenderer().GetGuiTexture(LoadingTexture.ID()),viewport.getWorkSizeX() / 2.0f,viewport.getWorkSizeY() / 2.0f);
ImGui.end();
}
}

View file

@ -10,7 +10,6 @@ import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
import net.halbear.Terrain4J.EngineCore.Main.GameCore;
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIOverlay;
import net.halbear.Terrain4J.EngineCore.Main.Scene.JackOfAllTradesActor;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen.DeferredSceneRender;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen.ForwardSceneRender;
import org.joml.Vector3f;
@ -148,10 +147,8 @@ public class PerformanceOverlay implements GUIOverlay {
}
ImGui.separator();
ImGui.text("Level Tools:");
if(ImGui.button("Spawn Radio")){
JackOfAllTradesActor newJackentity = new JackOfAllTradesActor("Radio" + parent.entities.size(), parent.radio.ID(), new Vector3f(engineInstance.scene().GetCamera().GetPosition()),parent.MusicParticle).SetAudio(engineInstance, "resources/EngineResources/audio/sounds/youusedtocallmeonyourcellphone.ogg").SetScale(0.01f);
parent.entities.add(newJackentity);
engineInstance.scene().AddActor(newJackentity);
if(ImGui.button("Spawn Melona")){
parent.SpawnNewActorEditorComponent(engineInstance);
}
if(parent.PerformanceMetrics.size() > 0) {
ImGui.text(" ");

View file

@ -0,0 +1,33 @@
package net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs;
import imgui.ImDrawList;
import imgui.ImGui;
import imgui.ImVec2;
import imgui.flag.ImGuiCol;
import imgui.flag.ImGuiMouseButton;
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.*;
import static net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.T4ImGuiUtil.IsPointInPolygon;
public class T4ImGui {
public static boolean polygonButton(String id, ImVec2[] Vertices) {
ImGui.pushID(id);
ImVec2 MousePos = ImGui.getMousePos();
ImDrawList DrawList = ImGui.getWindowDrawList();
boolean isHovered = IsPointInPolygon(MousePos, Vertices) && ImGui.isWindowHovered();
boolean isActive = isHovered && ImGui.isMouseDown(ImGuiMouseButton.Left);
boolean isClicked = isHovered && ImGui.isMouseReleased(ImGuiMouseButton.Left);
int Colour;
if (isActive) {
Colour = ImGui.getColorU32(ImGuiCol.ButtonActive);
} else if (isHovered) {
Colour = ImGui.getColorU32(ImGuiCol.ButtonHovered);
} else {
Colour = ImGui.getColorU32(ImGuiCol.Button);
}
DrawList.addConvexPolyFilled(Vertices, Vertices.length, Colour);
int BorderColour = ImGui.getColorU32(ImGuiCol.Border);
DrawList.addPolyline(Vertices, Vertices.length, BorderColour, 0, 1.0f);
ImGui.popID();
return isClicked;
}
}

View file

@ -0,0 +1,21 @@
package net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs;
import imgui.ImDrawList;
import imgui.ImGui;
import imgui.ImVec2;
import imgui.flag.ImGuiCol;
import imgui.flag.ImGuiMouseButton;
public class T4ImGuiUtil {
public static boolean IsPointInPolygon(ImVec2 point, ImVec2[] polygon) {
boolean inside = false;
int numVertices = polygon.length;
for (int i = 0, j = numVertices - 1; i < numVertices; j = i++) {
if (((polygon[i].y > point.y) != (polygon[j].y > point.y)) &&
(point.x < (polygon[j].x - polygon[i].x) * (point.y - polygon[i].y) / (polygon[j].y - polygon[i].y) + polygon[i].x)) {
inside = !inside;
}
}
return inside;
}
}

View file

@ -0,0 +1,23 @@
package net.halbear.Terrain4J.EngineCore.Main.Scene;
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.Gimbal;
import org.joml.Vector3f;
public interface IMoveableActorComponent {
public void UpdateAll();
public Actor GetActor();
public void SetActor(Actor actor);
public void AddPosition(Vector3f addedPos);
public void AddRotation(Vector3f addedRot);
public void AddScale(Vector3f addedScale);
public Vector3f GetPosition();
public Gimbal GetActorGimbal();
public void SetActorGimbal(Gimbal gimbal);
public void SetPosition(float x, float y, float z);
public void SetPosition(Vector3f Position);
public void SetActorDimensions(float x, float y, float z);
public Vector3f GetActorDimensions();
public void SetActorScale(float scale);
public void SetActorScale(Vector3f scale);
public Vector3f GetActorScale();
}

View file

@ -3,6 +3,7 @@ package net.halbear.Terrain4J.EngineCore.Main.Scene;
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.SkyBox;
import net.halbear.Terrain4J.EngineCore.Main.GameCore;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.DynamicMesh.DynamicTerrainMesh;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Projection.Project3D;
import java.util.List;
@ -21,7 +22,7 @@ public interface IScene {
public List<Actor> GetActors();
public Project3D GetProjection();
public void RemoveAllActors();
public void RemoveActor(Actor actor);
public Actor RemoveActor(Actor actor);
public void Input(EngineInstance engineInstance, long FrameDiffNanoSeconds);
public void Update(EngineInstance engineInstance, long FrameDiffNanoSeconds);
public void UpdateFastThread(EngineInstance engineInstance, long FrameDiffNanoSeconds);
@ -34,4 +35,6 @@ public interface IScene {
public ISceneLightingManager GetLightingManager();
public SkyBox GetSkyBox();
public void SetSkyBox(SkyBox skyBox);
public DynamicTerrainMesh GetTerrainMesh();
public void CreateTerrainMesh();
}

View file

@ -1,66 +0,0 @@
package net.halbear.Terrain4J.EngineCore.Main.Scene;
import net.halbear.Terrain4J.EngineCore.Audio.AudioManager;
import net.halbear.Terrain4J.EngineCore.Audio.AudioSource;
import net.halbear.Terrain4J.EngineCore.Audio.SoundBuffer;
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.ModelData;
import org.joml.Vector3f;
import java.util.ArrayList;
import java.util.List;
public class JackOfAllTradesActor extends Actor {
private ModelData Particle;
private List<ParticleActor> particleActors = new ArrayList<>();
private String SOUND_ID_BUFFER;
private String SOUND_ID_PLAYER;
private AudioSource playerAudioSource;
public JackOfAllTradesActor(String ID, String ModelID, Vector3f Position, ModelData Particle){
super(ID,ModelID,Position);
SOUND_ID_BUFFER = ID + "_AUDIO_BUFFER";
SOUND_ID_PLAYER = ID+"_AUDIO_PLAYER";
this.Particle = Particle;
}
public JackOfAllTradesActor SetScale(float scale){
super.SetScale(scale);
return this;
}
public JackOfAllTradesActor SetAudio(EngineInstance engineInstance, String AudioFile){
AudioManager audioManager = engineInstance.audioManager();
SoundBuffer buffer = new SoundBuffer(AudioFile);
audioManager.AddSoundBuffer(SOUND_ID_BUFFER, buffer);
playerAudioSource = new AudioSource(true,false);
playerAudioSource.SetPosition(new Vector3f(GetPosition()));
playerAudioSource.SetBuffer(buffer.GetBufferID());
audioManager.AddSoundSource(SOUND_ID_PLAYER,playerAudioSource);
PlayAudio();
return this;
}
public JackOfAllTradesActor PlayAudio(){
playerAudioSource.Play();
return this;
}
public void tick(IScene scene){
List<Integer> ParticlesToDelete = new ArrayList<>();
if((int)(Math.random() * 20) == 0){
ParticleActor particle = new ParticleActor("particle" + particleActors.size(), Particle.ID(), new Vector3f(GetPosition()),new Vector3f(1,1,1),0,new Vector3f(-1f + (float)Math.random() * 2,-1f + (float)Math.random() * 2,-1f + (float)Math.random() * 2),0.0005f,5000);
particleActors.add(particle);
scene.AddActor(particle);
}
for(int i = 0; i < particleActors.size(); i++){
particleActors.get(i).TickUpdate();
if(particleActors.get(i).TicksLeft() <= 0){
scene.RemoveActor(particleActors.get(i));
ParticlesToDelete.add(i);
}
}
for(int i = ParticlesToDelete.size() - 1; i >= 0; i--){
particleActors.remove((int)ParticlesToDelete.get(i));
}
}
}

View file

@ -6,8 +6,12 @@ import net.halbear.Terrain4J.EngineCore.Input.MouseListener;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.SkyBox;
import net.halbear.Terrain4J.EngineCore.Main.AudioInstance;
import net.halbear.Terrain4J.EngineCore.Main.GameCore;
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.Gimbal;
import net.halbear.Terrain4J.EngineCore.Main.Scene.GUIs.PerformanceOverlay;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.DynamicMesh.DynamicTerrainMesh;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Projection.Project3D;
import org.joml.Vector2f;
import org.joml.Vector3f;
@ -27,7 +31,8 @@ public class Scene implements IScene {
private static final float MOUSE_SENSITIVITY = 0.1f;
private static final float MOVEMENT_SPEED = 0.025f;
private final List<Actor> Actors;
private final Map<String, Actor> Actors;
private final List<String> ActiveActors;
private final Map<String, CameraFrame> CameraFrames;
private final Project3D Projection;
private final Camera camera;
@ -40,6 +45,8 @@ public class Scene implements IScene {
private Vector2f LastMousePos = new Vector2f(0,0);
private final ISceneLightingManager lightingManager;
private SkyBox skyBox;
private Map<String,AudioInstance> audioInstances;
private DynamicTerrainMesh terrainMesh;
public List<String> ActiveGUIs = new ArrayList<>();
public Map<String, GUIOverlay> GUIReg = new HashMap<>();
@ -48,11 +55,30 @@ public class Scene implements IScene {
this.skyBox = skyBox;
}
@Override
public DynamicTerrainMesh GetTerrainMesh() {
return terrainMesh;
}
@Override
public void CreateTerrainMesh() {
int Width = 32;
int Height = 32;
float[] Heights = new float[Width * Height];
for(int i = 0; i < Heights.length; i++){
Heights[i] = 3 * (float)Math.random();
}
terrainMesh = new DynamicTerrainMesh(PrimaryRuntime.GetRenderThread().GetRenderer().GetVulkanContext().GetDevice(), Heights, Width, Height);
}
public SkyBox GetSkyBox(){return skyBox;}
public Scene(Window window) {
// CreateTerrainMesh();
lightingManager = new SceneLightingManager(1000,new Vector3f(1f,1f,1f), 0.5f);
Actors = new ArrayList<>();
Actors = new HashMap<>();
audioInstances = new HashMap<>();
ActiveActors = new ArrayList<>();
CameraFrames = new HashMap<>();
var EngConfig = EngineConfig.getInstance();
camera = new Camera();
@ -122,11 +148,11 @@ public class Scene implements IScene {
public void SetActiveCameraFrame(String frameName){SetCameraFrame = frameName;}
public String GetActiveCameraFrame(){return ActiveCameraFrame;}
public Camera GetCamera(){return camera;}
public void AddActor(Actor NewActor){Actors.add(NewActor);}
public List<Actor> GetActors(){return Actors;}
public void AddActor(Actor NewActor){Actors.put(NewActor.GetID(), NewActor);}
public List<Actor> GetActors(){return Actors.values().stream().toList();}
public Project3D GetProjection(){return Projection;}
public void RemoveAllActors(){Actors.clear();}
public void RemoveActor(Actor actor){Actors.removeIf(Actor->Actor.GetID().equals(actor.GetID()));}
public Actor RemoveActor(Actor actor){return Actors.remove(actor.GetID());}
public void SetUpAudio(EngineInstance engineInstance){
@ -195,8 +221,9 @@ public class Scene implements IScene {
@Override
public void RenderGUIs(EngineInstance engineInstance, long frameTimeNS, GameCore parent) {
List<String> ActiveGuis = new ArrayList<>(ActiveGUIs);
Gimbal.RenderGimbals(engineInstance,frameTimeNS,parent);
ActiveGuis.forEach(gui->{
if(GUIReg.containsKey(gui)){
if(GUIReg.containsKey(gui) && !GUIReg.get(gui).getClass().equals(Gimbal.class)){
GUIReg.get(gui).RenderGUI(engineInstance,frameTimeNS,parent);
}
});

View file

@ -0,0 +1,5 @@
package net.halbear.Terrain4J.EngineCore.Main.Scene;
public class SceneLoadData {
}

View file

@ -1,8 +1,137 @@
package net.halbear.Terrain4J.EngineCore.Main.Util.Maths;
import imgui.ImVec2;
import org.joml.*;
import java.lang.Math;
public class T4Math {
public static double Log2(int n){
return Math.log(n) / Math.log(n);
}
public static double Square(double n){return n*n;}
public static class Math2D {
public static boolean IsPointInPolygon(Vector2f point, Vector2f[] polygon) {
boolean inside = false;
int numVertices = polygon.length;
for (int i = 0, j = numVertices - 1; i < numVertices; j = i++) {
if (((polygon[i].y > point.y) != (polygon[j].y > point.y)) &&
(point.x < (polygon[j].x - polygon[i].x) * (point.y - polygon[i].y) / (polygon[j].y - polygon[i].y) + polygon[i].x)) {
inside = !inside;
}
}
return inside;
}
}
public static class Math3D {
public static float epsilon = 1e-6f;
public static boolean DoesLineCollideWithPoly(Vector3f Origin, Vector3f Point, Vector3f[] Vertices){
Vector3f LineDirection = new Vector3f(Point).sub(Origin);
float Test = Intersectionf.intersectRayTriangle(Origin,LineDirection,
Vertices[0],Vertices[1],Vertices[2], epsilon);
return(Test >= 0.0f && Test <= 1.0f);
}
public static boolean ComplexLinePolyCollisionCheck(Vector3f Origin, Vector3f Point, Vector3f[] Vertices){
Vector3f LineDirection = new Vector3f(Point).sub(Origin);
float Test = Intersectionf.intersectRayTriangle(Origin,LineDirection,
Vertices[0],Vertices[1],Vertices[2], epsilon);
if(Test >= 0.0f && Test <= 1.0f) return true;
Vector3f edge1 = new Vector3f(Vertices[1]).sub(Vertices[0]);
Vector3f edge2 = new Vector3f(Vertices[2]).sub(Vertices[0]);
Vector3f normal = new Vector3f(edge1).cross(edge2).normalize();
Vector3f pAFromV0 = new Vector3f(Origin).sub(Vertices[0]);
Vector3f pBFromV0 = new Vector3f(Point).sub(Vertices[0]);
boolean pAOnPlane = Math.abs(pAFromV0.dot(normal)) < epsilon;
boolean pBOnPlane = Math.abs(pBFromV0.dot(normal)) < epsilon;
if (pAOnPlane && pBOnPlane) {
if (Intersectionf.testPointInTriangle(Origin.x,Origin.y,Origin.z,
Vertices[0].x,Vertices[0].y,Vertices[0].z,
Vertices[1].x,Vertices[1].y,Vertices[1].z,
Vertices[2].x,Vertices[2].y,Vertices[2].z) ||
Intersectionf.testPointInTriangle(Point.x,Point.y,Point.z,
Vertices[0].x,Vertices[0].y,Vertices[0].z,
Vertices[1].x,Vertices[1].y,Vertices[1].z,
Vertices[2].x,Vertices[2].y,Vertices[2].z)) {
return true;
}
if (Intersectionf.testLineSegmentTriangle(Origin, Point, Vertices[0], Vertices[1],Vertices[2], epsilon)){
return true;
}
}
return false;
}
public static Vector3f LineCollisionPointWithPoly(Vector3f Origin, Vector3f Point, Vector3f[] Vertices){
Vector3f LineDirection = new Vector3f(Point).sub(Origin);
float Test = Intersectionf.intersectRayTriangle(Origin,LineDirection,
Vertices[0],Vertices[1],Vertices[2], epsilon);
if (Test >= 0.0f && Test <= 1.0f) {
return new Vector3f(LineDirection).mul(Test).add(Origin);
}
return null;
}
public static boolean DoesInfiniteLineCollideWithPoly(Vector3f LinePoint, Vector3f LineDirection, Vector3f[] Vertices){
//forward test
float Test = Intersectionf.intersectRayTriangle(LinePoint,LineDirection,
Vertices[0],Vertices[1],Vertices[2], epsilon);
if(Test >= 0.0f){
return true;
}
//backward test
Test = Intersectionf.intersectRayTriangle(LinePoint,new Vector3f(LineDirection.mul(-1f)),
Vertices[0],Vertices[1],Vertices[2], epsilon);
return Test >= 0.0f;
}
public static Vector3f RayCastCollisionWithPolygon(Vector3f LinePoint, Vector3f LineDirection, Vector3f[] Vertices){
//forward test
float Test = Intersectionf.intersectRayTriangle(LinePoint,LineDirection,
Vertices[0],Vertices[1],Vertices[2], epsilon);
if(Test >= 0.0f){
return new Vector3f(LineDirection).mul(Test).add(LinePoint);
}
//backward test
Test = Intersectionf.intersectRayTriangle(LinePoint,new Vector3f(LineDirection.mul(-1f)),
Vertices[0],Vertices[1],Vertices[2], epsilon);
if(Test >= 0.0f){
return new Vector3f(LineDirection).mul(-Test).add(LinePoint);
}
return null;
}
public static Vector3f CalculateNormal(Vector3f v1, Vector3f v2, Vector3f v3) {
Vector3f U = new Vector3f(v2.sub(v1));
Vector3f V = new Vector3f(v3.sub(v1));
Vector3f N = new Vector3f(U.mul(V));
float Nx = (U.x * V.z) - (U.z * V.y);
float Ny = (U.z * V.x) - (U.x * V.z);
float Nz = (U.x * V.y) - (U.y * V.x);
float Length = (float) org.joml.Math.sqrt(T4Math.Square(Nx) + T4Math.Square(Ny) + T4Math.Square(Nz));
return new Vector3f(Nx / Length, Ny / Length, Nz / Length);
}
public static Vector3f GetScreenCoordFromWorldSpace(Vector3f worldPos, Matrix4f viewMatrix, Matrix4f projMatrix, int windowWidth, int windowHeight) {
Matrix4f viewProj = new Matrix4f(projMatrix).mul(viewMatrix);
Vector4f clipSpacePos = new Vector4f(worldPos, 1.0f).mul(viewProj);
if (clipSpacePos.w <= 0.0f) {
return null;
}
float ndcX = clipSpacePos.x / clipSpacePos.w;
float ndcY = clipSpacePos.y / clipSpacePos.w;
float ndcZ = clipSpacePos.z / clipSpacePos.w;
if (ndcZ < -1.0f || ndcZ > 1.0f) return null;
float screenX = ((ndcX + 1.0f) / 2.0f) * windowWidth;
float screenY = ((1.0f - ndcY) / 2.0f) * windowHeight;
return new Vector3f(screenX, screenY, ndcZ);
}
}
}

View file

@ -77,7 +77,7 @@ public class EngineThread implements Runnable{
Logger.debug("{} Thread Started",ThreadName);
EngineAccuracy = EngineConfig.getInstance().getAccuracy();
OriginalAccuracy = EngineAccuracy;
while (running){
while (running && !PrimaryRuntime.CanClose){
long now = System.nanoTime();
FrameTimes[0] = now - InitialTime;
FrameTimes[1] += FrameTimes[0];

View file

@ -15,7 +15,6 @@ public class FastTickThread extends EngineThread {
@Override
public void TickEvent(long nsTimeDiff){
gameLogic.Input(PrimaryRuntime.GetEngineInstance(), (nsTimeDiff));
gameLogic.UpdateFastThread(PrimaryRuntime.GetEngineInstance(), nsTimeDiff);
}
@Override
@ -38,7 +37,7 @@ public class FastTickThread extends EngineThread {
if (CappedToTickRate){
TickThreshold = (double) 1000000000 / (double) TickRate;
} else{
TickThreshold = 0;
TickThreshold = 1;
}
}

View file

@ -0,0 +1,13 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.DynamicMesh;
public class DeferredResource {
public final long bufferHandle;
public final long memoryHandle;
public int framesLeft;
public DeferredResource(long bufferHandle, long memoryHandle, int framesLeft) {
this.bufferHandle = bufferHandle;
this.memoryHandle = memoryHandle;
this.framesLeft = framesLeft;
}
}

View file

@ -0,0 +1,143 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.DynamicMesh;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.CommandBuffer;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.Device;
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanBuffer;
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils;
import org.lwjgl.PointerBuffer;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkBufferCopy;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.LongBuffer;
import static org.lwjgl.system.MemoryUtil.memByteBuffer;
import static org.lwjgl.vulkan.VK10.*;
public class DynamicTerrainMesh {
private final Device device;
private long VertexBuffer;
private long VertexBufferMemoryAlloc;
private long IndexBuffer;
private long IndexBufferMemoryAlloc;
private int VertexCount;
private int IndexCount;
private boolean IsDirty = true;
private float[] Positions;
private float[] MaterialWeights;
private int[] Indices;
public DynamicTerrainMesh(Device device, float[] InitialHeights, int Width, int Height){
this.device = device;
GenerateMeshGeometry(InitialHeights, Width, Height);
InitVulkanBuffers();
}
private void InitVulkanBuffers(){
long VertexSize = (long) Positions.length * 4 + (long) MaterialWeights.length * 4;
long IndexSize = (long)Indices.length * 4;
LongBuffer longBuffer = LongBuffer.allocate(1);
VertexBuffer = VulkanUtils.CreateBuffer(device, VertexSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, longBuffer);
VertexBufferMemoryAlloc = longBuffer.get(0);
IndexBuffer = VulkanUtils.CreateBuffer(device, IndexSize,
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, longBuffer);
IndexBufferMemoryAlloc = longBuffer.get(0);
}
private void GenerateMeshGeometry(float[] Heights, int w, int h){
this.VertexCount = w * h;
this.Positions = new float[VertexCount * 3];
this.MaterialWeights = new float[VertexCount * 4];
for(int row = 0; row < h; row++){
for(int column = 0; column < w; column++){
int Index = row * w + column;
Positions[Index * 3] = column;
Positions[Index * 3 + 1] = Heights[Index];
Positions[Index * 3 + 2] = row;
MaterialWeights[Index * 4] = 1.0f; // Grass
MaterialWeights[Index * 4 + 1] = 0.0f; // Rock
MaterialWeights[Index * 4 + 2] = 0.0f; // Sand
MaterialWeights[Index * 4 + 3] = 0.0f; // Mud
}
}
this.IndexCount = (w - 1) * (h - 1) * 6;
this.Indices = new int[IndexCount];
int CellPtr = 0;
for (int row = 0; row < h - 1; row++) {
for (int col = 0; col < w - 1; col++) {
int TopLeft = row * w + col;
int TopRight = TopLeft + 1;
int BottomLeft = (row + 1) * w + col;
int BottomRight = BottomLeft + 1;
Indices[CellPtr++] = TopLeft;
Indices[CellPtr++] = BottomLeft;
Indices[CellPtr++] = TopRight;
Indices[CellPtr++] = TopRight;
Indices[CellPtr++] = BottomLeft;
Indices[CellPtr++] = BottomRight;
}
}
}
public void UpdateVertexRuntimeData(int index, float newHeight, float[] weights) {
this.Positions[index * 3 + 1] = newHeight;
System.arraycopy(weights, 0, this.MaterialWeights, index * 4, 4);
this.IsDirty = true;
}
public void StreamUpdatesToGPU(CommandBuffer cmdBuffer) {
if (!IsDirty) return;
long vSize = (long) Positions.length * 4 + (long) MaterialWeights.length * 4;
long stagingBuffer;
long stagingBufferMemory;
try (MemoryStack stack = MemoryStack.stackPush()) {
LongBuffer pBuffer = stack.mallocLong(1);
stagingBuffer = VulkanUtils.CreateBuffer(device, vSize,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, pBuffer);
stagingBufferMemory = pBuffer.get(0);
PointerBuffer pData = stack.pointers(VK_NULL_HANDLE);
vkMapMemory(device.FetchVulkanDevice(), stagingBufferMemory, 0, vSize, 0, pData);
long dataAddr = pData.get(0);
ByteBuffer buffer = memByteBuffer(dataAddr, (int) vSize);
FloatBuffer floatBuffer = buffer.asFloatBuffer();
for (int i = 0; i < VertexCount; i++) {
floatBuffer.put(Positions, i * 3, 3);
floatBuffer.put(MaterialWeights, i * 4, 4);
}
vkUnmapMemory(device.FetchVulkanDevice(), stagingBufferMemory);
VkBufferCopy.Buffer copyRegion = VkBufferCopy.calloc(1, stack)
.srcOffset(0)
.dstOffset(0)
.size(vSize);
vkCmdCopyBuffer(cmdBuffer.GetVulkanCommandBuffer(), stagingBuffer, VertexBuffer, copyRegion);
this.IsDirty = false;
VulkanUtils.QueueForDeletion(stagingBuffer, stagingBufferMemory);
}
}
public long GetVertexBuffer() { return VertexBuffer; }
public long GetIndexBuffer() { return IndexBuffer; }
public int GetIndexCount() { return IndexCount; }
}

View file

@ -0,0 +1,63 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering;
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils;
import org.lwjgl.vulkan.VkPipelineVertexInputStateCreateInfo;
import org.lwjgl.vulkan.VkVertexInputAttributeDescription;
import org.lwjgl.vulkan.VkVertexInputBindingDescription;
import static org.lwjgl.vulkan.VK10.VK_FORMAT_R32G32B32A32_SFLOAT;
import static org.lwjgl.vulkan.VK10.VK_FORMAT_R32G32_SFLOAT;
import static org.lwjgl.vulkan.VK13.VK_FORMAT_R32G32B32_SFLOAT;
import static org.lwjgl.vulkan.VK13.VK_VERTEX_INPUT_RATE_VERTEX;
public class TerrainMeshVertexBufferStructure {
public static final int TEXT_COORD_COMPONENTS = 2;
public static final int NORMAL_COMPONENTS = 3;
private static final int NUMBER_OF_ATTRIBUTES = 2;
private final int POSITION_COMPONENTS = 3;
private final VkPipelineVertexInputStateCreateInfo VertexInput;
private final VkVertexInputAttributeDescription.Buffer VertexInputAttributes;
private final VkVertexInputBindingDescription.Buffer VertexInputBindings;
public TerrainMeshVertexBufferStructure(){
VertexInputAttributes = VkVertexInputAttributeDescription.calloc(NUMBER_OF_ATTRIBUTES);
VertexInputBindings = VkVertexInputBindingDescription.calloc(1);
VertexInput = VkPipelineVertexInputStateCreateInfo.calloc();
int i =0;
int Offset = 0;
//vertex position
VertexInputAttributes.get(i)
.binding(0)
.location(0)
.format(VK_FORMAT_R32G32B32_SFLOAT)
.offset(Offset);
i++;
Offset += POSITION_COMPONENTS * VulkanUtils.FLOAT_SIZE;
//Material Weight Parameters
VertexInputAttributes.get(i)
.binding(0)
.location(1)
.format(VK_FORMAT_R32G32B32A32_SFLOAT)
.offset(Offset);
int Stride = 7 * VulkanUtils.FLOAT_SIZE;
VertexInputBindings.get(0)
.binding(0)
.stride(Stride)
.inputRate(VK_VERTEX_INPUT_RATE_VERTEX);
VertexInput
.sType$Default()
.pVertexAttributeDescriptions(VertexInputAttributes)
.pVertexBindingDescriptions(VertexInputBindings);
}
public void cleanup(){
VertexInput.free();
VertexInputAttributes.free();
}
public VkPipelineVertexInputStateCreateInfo getVertexInput(){
return VertexInput;
}
}

View file

@ -13,12 +13,24 @@ public class VertexBufferStructure {
public static final int TEXT_COORD_COMPONENTS = 2;
public static final int NORMAL_COMPONENTS = 3;
private static final int NUMBER_OF_ATTRIBUTES = 5;
private final int POSITION_COMPONENTS = 3;
private static final int POSITION_COMPONENTS = 3;
public static int VertexInputSize = 5 * VulkanUtils.FLOAT_SIZE;
private final VkPipelineVertexInputStateCreateInfo VertexInput;
private final VkVertexInputAttributeDescription.Buffer VertexInputAttributes;
private final VkVertexInputBindingDescription.Buffer VertexInputBindings;
public static int GetVertexInputSize(){
int Offset = 0;
Offset += POSITION_COMPONENTS * VulkanUtils.FLOAT_SIZE;
Offset += NORMAL_COMPONENTS * VulkanUtils.FLOAT_SIZE;
Offset += NORMAL_COMPONENTS * VulkanUtils.FLOAT_SIZE;
Offset += NORMAL_COMPONENTS * VulkanUtils.FLOAT_SIZE;
Offset += TEXT_COORD_COMPONENTS * VulkanUtils.FLOAT_SIZE;
VertexInputSize = Offset;
return VertexInputSize;
}
public VertexBufferStructure(){
VertexInputAttributes = VkVertexInputAttributeDescription.calloc(NUMBER_OF_ATTRIBUTES);
VertexInputBindings = VkVertexInputBindingDescription.calloc(1);

View file

@ -7,10 +7,15 @@ public class ModelBinaryData {
private final DataOutputStream IndexOutput;
private final String VertexFilePath;
private final DataOutputStream VertexOutput;
private final String CollisionVertexFilePath;
private final DataOutputStream CollisionVertexOutput;
private int IndexOffset;
private int CollisionOffset;
private int VertexOffset;
public ModelBinaryData(String ModelPath) throws FileNotFoundException{
CollisionVertexFilePath = ModelPath.substring(0,ModelPath.lastIndexOf('.')) + ".colmesh";
CollisionVertexOutput = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(CollisionVertexFilePath)));
VertexFilePath = ModelPath.substring(0,ModelPath.lastIndexOf('.')) + ".vtx";
VertexOutput = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(VertexFilePath)));
IndexFilePath= ModelPath.substring(0,ModelPath.lastIndexOf('.')) + ".idx";
@ -28,8 +33,12 @@ public class ModelBinaryData {
public String GetVertexFilePath(){return VertexFilePath;}
public int GetVertexOffset(){return VertexOffset;}
public DataOutputStream GetVertexOutput(){return VertexOutput;}
public String GetCollisionVertexFilePath(){return CollisionVertexFilePath;}
public int GetCollisionVertexOffset(){return CollisionOffset;}
public DataOutputStream GetCollisionVertexOutput(){return CollisionVertexOutput;}
public void IncrementIndexOffset(int Increment){
IndexOffset+=Increment;
}
public void IncrementVertexOffset(int Increment){VertexOffset+=Increment;}
public void IncrementCollisionVertexOffset(int Increment){VertexOffset+=Increment;}
}

View file

@ -74,9 +74,7 @@ public class ModelsCache {
try (MemoryStack MemStack = MemoryStack.stackPush()) {
LongBuffer pBuffers = MemStack.longs(vkBufferHandle);
LongBuffer pOffsets = MemStack.longs(0);
vkCmdBindVertexBuffers(commandHandle, 0, pBuffers, pOffsets);
vkCmdDraw(commandHandle, 36, 1, 0, 0);
}
}

View file

@ -1,4 +0,0 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel;
public class ProceduralMesh {
}

View file

@ -6,6 +6,7 @@ import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor;
import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.DeferredRendering.MultiRenderTargetAttachments;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.DynamicMesh.DynamicTerrainMesh;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.DefaultPipeline;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.Images.*;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.Pipeline;
@ -30,6 +31,8 @@ import java.nio.ByteBuffer;
import java.nio.LongBuffer;
import java.util.*;
import static org.lwjgl.system.MemoryUtil.memAllocLong;
import static org.lwjgl.system.MemoryUtil.memFree;
import static org.lwjgl.vulkan.VK13.*;
public class DeferredSceneRender implements SceneRenderer {//dynamic rendering
@ -297,6 +300,10 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering
public void Render(EngineInstance engineInstance,VulkanContext vulkanContext, CommandBuffer commandBuffer, ModelsCache modelsCache,MaterialsCache materialsCache, int CurrentFrame){
try(var MemStack = MemoryStack.stackPush()){
// DynamicTerrainMesh terrainMesh = engineInstance.scene().GetTerrainMesh();
// terrainMesh.StreamUpdatesToGPU(commandBuffer);
VkCommandBuffer CommandHandle = commandBuffer.GetVulkanCommandBuffer();
List<Attachment> attachments = MRTAttachments.GetColourAttachments();
@ -338,6 +345,20 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering
VulkanUtils.CopyMatrixToBuffer(vulkanContext, BufferViewMatrices[CurrentFrame],engineInstance.scene().GetCamera().GetViewMatrix(), 0); // here
/* LongBuffer vBuffers = memAllocLong(1).put(0, terrainMesh.GetVertexBuffer());
LongBuffer offsets = memAllocLong(1).put(0, 0L);
vkCmdBindVertexBuffers(commandBuffer.GetVulkanCommandBuffer(), 0, vBuffers, offsets);
vkCmdBindIndexBuffer(commandBuffer.GetVulkanCommandBuffer(), terrainMesh.GetIndexBuffer(), 0, VK_INDEX_TYPE_UINT32);
// Draw the procedural geometry primitives
vkCmdDrawIndexed(commandBuffer.GetVulkanCommandBuffer(), terrainMesh.GetIndexCount(), 1, 0, 0, 0);
memFree(vBuffers);
memFree(offsets);
*/
vkCmdBindPipeline(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, DualPassRendering ? VkPipelineOpaque.GetVulkanPipeline() : VkPipeline.GetVulkanPipeline());
DescriptorAllocator descriptorAllocator = vulkanContext.GetDescriptorAllocator();
LongBuffer DescriptorSets = MemStack.mallocLong(4)
.put(0,descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_PRJ).GetVkDescriptorSet())
@ -370,8 +391,6 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering
if(DualPassRendering) {
vkCmdBindPipeline(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkPipelineTranslucent.GetVulkanPipeline());
vkCmdBindDescriptorSets(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkPipelineTranslucent.GetVulkanPipelineLayout(), 0, DescriptorSets, null);
//vkCmdBindPipeline(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkPipelineOpaque.GetVulkanPipeline());
//vkCmdBindDescriptorSets(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkPipelineOpaque.GetVulkanPipelineLayout(), 0, DescriptorSets, null);
} else{
vkCmdBindPipeline(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkPipeline.GetVulkanPipeline());
vkCmdBindDescriptorSets(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkPipeline.GetVulkanPipelineLayout(),0,DescriptorSets,null);
@ -500,7 +519,7 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering
AttachmentInfoDepth.free();
MRTAttachments.CleanUp(VkCtx);
AttachmentInfoColour.free();
MemoryUtil.memFree(PushConstBuffer);
memFree(PushConstBuffer);
ClearValueDepth.free();
ClearValueColour.free();
}

View file

@ -2,6 +2,7 @@ package net.halbear.Terrain4J.EngineCore.Vulkan.Util;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.DynamicMesh.DeferredResource;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.DescriptorAllocator;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.DescriptorSet;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.DescriptorSetLayout;
@ -15,10 +16,10 @@ import org.tinylog.Logger;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import static org.lwjgl.util.vma.Vma.VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
@ -37,12 +38,103 @@ public class VulkanUtils {
public static final int VEC2_SIZE = 2 * FLOAT_SIZE;
public static final int SHORT_LENGTH = 2;
private static final List<DeferredResource> DeletionQueue = new ArrayList<>();
public static void QueueForDeletion(long bufferHandle, long memoryHandle) {
synchronized (DeletionQueue) {
DeletionQueue.add(new DeferredResource(bufferHandle, memoryHandle, MAX_IN_FLIGHT));
}
}
public static void ProcessDeferredDeletionQueue(Device device) {
VkDevice vkDevice = device.FetchVulkanDevice();
synchronized (DeletionQueue) {
Iterator<DeferredResource> iterator = DeletionQueue.iterator();
while (iterator.hasNext()) {
DeferredResource resource = iterator.next();
resource.framesLeft--;
if (resource.framesLeft <= 0) {
if (resource.bufferHandle != VK_NULL_HANDLE) {
vkDestroyBuffer(vkDevice, resource.bufferHandle, null);
}
if (resource.memoryHandle != VK_NULL_HANDLE) {
vkFreeMemory(vkDevice, resource.memoryHandle, null);
}
iterator.remove();
}
}
}
}
public static void CleanUpRemaining(Device device) {
VkDevice vkDevice = device.FetchVulkanDevice();
synchronized (DeletionQueue) {
for (DeferredResource resource : DeletionQueue) {
vkDestroyBuffer(vkDevice, resource.bufferHandle, null);
vkFreeMemory(vkDevice, resource.memoryHandle, null);
}
DeletionQueue.clear();
}
}
public static void CopyMatrixToBuffer(VulkanContext VkCtx, VulkanBuffer VkBuffer, Matrix4f matrix, int Offset){
long MappedMemory = VkBuffer.MapMemory(VkCtx);
ByteBuffer matrixBuffer = MemoryUtil.memByteBuffer(MappedMemory, (int)VkBuffer.GetRequestedSize());
matrix.get(Offset, matrixBuffer);
VkBuffer.UnMapMemory(VkCtx);
}
public static long CreateBuffer(Device device, long size, int usage, int requirementsMask, LongBuffer pMemoryOut) {
VkDevice vkDevice = device.FetchVulkanDevice();
long bufferHandle;
try (MemoryStack stack = MemoryStack.stackPush()) {
VkBufferCreateInfo bufferInfo = VkBufferCreateInfo.calloc(stack)
.sType(VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO)
.size(size)
.usage(usage)
.sharingMode(VK_SHARING_MODE_EXCLUSIVE);
LongBuffer pBuffer = stack.mallocLong(1);
int err = vkCreateBuffer(vkDevice, bufferInfo, null, pBuffer);
if (err != VK_SUCCESS) {
throw new RuntimeException("Failed to create Vulkan buffer. Error code: " + err);
}
bufferHandle = pBuffer.get(0);
VkMemoryRequirements memRequirements = VkMemoryRequirements.calloc(stack);
vkGetBufferMemoryRequirements(vkDevice, bufferHandle, memRequirements);
VkMemoryAllocateInfo allocInfo = VkMemoryAllocateInfo.calloc(stack)
.sType(VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO)
.allocationSize(memRequirements.size())
.memoryTypeIndex(findMemoryType(device, memRequirements.memoryTypeBits(), requirementsMask));
int allocErr = vkAllocateMemory(vkDevice, allocInfo, null, pMemoryOut);
if (allocErr != VK_SUCCESS) {
throw new RuntimeException("Failed to allocate Vulkan buffer memory. Error code: " + allocErr);
}
vkBindBufferMemory(vkDevice, bufferHandle, pMemoryOut.get(0), 0);
}
return bufferHandle;
}
private static int findMemoryType(Device device, int typeFilter, int properties) {
VkPhysicalDeviceMemoryProperties memProperties = VkPhysicalDeviceMemoryProperties.calloc();
vkGetPhysicalDeviceMemoryProperties(device.FetchVulkanDevice().getPhysicalDevice(), memProperties);
for (int i = 0; i < memProperties.memoryTypeCount(); i++) {
if ((typeFilter & (1 << i)) != 0 &&
(memProperties.memoryTypes(i).propertyFlags() & properties) == properties) {
return i;
}
}
throw new RuntimeException("Failed to find suitable memory type for buffer allocation!");
}
public static VulkanBuffer CreateRawVertexAttrBuffer(VulkanContext VkCtx, long BufferSize) {
return new VulkanBuffer(
VkCtx,