2D rendering (big feature)
This commit is contained in:
parent
6d7ea4ebc5
commit
5a05b9d65e
21 changed files with 1075 additions and 22 deletions
25
resources/EngineResources/SpriteShaders/sprite_fragment.glsl
Normal file
25
resources/EngineResources/SpriteShaders/sprite_fragment.glsl
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
const int MAX_TEXTURES = 128;
|
||||||
|
const float GAMMA_CONST = 0.4545;
|
||||||
|
layout(location = 0) in vec2 inUV;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
layout(push_constant) uniform pc {
|
||||||
|
layout(offset = 24) uint textureIndex;
|
||||||
|
} push_constants;
|
||||||
|
|
||||||
|
layout(set = 1, binding = 0) uniform sampler2D spriteTextures[MAX_TEXTURES];
|
||||||
|
|
||||||
|
vec4 gamma(vec4 color){
|
||||||
|
return color = vec4(pow(color.rgb,vec3(GAMMA_CONST)),color.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 tex = texture(spriteTextures[push_constants.textureIndex], inUV);
|
||||||
|
outColor = gamma(tex);
|
||||||
|
|
||||||
|
if (outColor.a <= 0.09) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
const int MAX_TEXTURES = 128;
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 inUV;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
layout(push_constant) uniform pc {
|
||||||
|
layout(offset = 24) uint textureIndex;
|
||||||
|
} push_constants;
|
||||||
|
|
||||||
|
layout(set = 1, binding = 0) uniform sampler2D spriteTextures[MAX_TEXTURES];
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 tex = texture(spriteTextures[push_constants.textureIndex], inUV);
|
||||||
|
outColor = tex;
|
||||||
|
|
||||||
|
if(outColor.a >= 0.9 || outColor.a <= 0.001){discard;}
|
||||||
|
}
|
||||||
36
resources/EngineResources/SpriteShaders/sprite_vertex.glsl
Normal file
36
resources/EngineResources/SpriteShaders/sprite_vertex.glsl
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 inPos;
|
||||||
|
layout(location = 1) in vec2 inUV;
|
||||||
|
|
||||||
|
layout(location = 0) out vec2 outUV;
|
||||||
|
|
||||||
|
|
||||||
|
layout(push_constant) uniform pc {
|
||||||
|
vec2 modelSize;
|
||||||
|
vec2 position;
|
||||||
|
vec2 screenSize;
|
||||||
|
|
||||||
|
} push_constants;
|
||||||
|
|
||||||
|
layout(set = 0, binding = 0) uniform ViewUniform{
|
||||||
|
vec2 camPos;
|
||||||
|
vec2 camScale;
|
||||||
|
} viewUniform;
|
||||||
|
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 ScaledPos = inPos * push_constants.modelSize;
|
||||||
|
vec2 worldPos = push_constants.position + ScaledPos;
|
||||||
|
worldPos += viewUniform.camPos;
|
||||||
|
vec2 ndc = vec2(
|
||||||
|
(worldPos.x / push_constants.screenSize.x) * 2.0 - 1.0,
|
||||||
|
(worldPos.y / push_constants.screenSize.y) * 2.0 - 1.0
|
||||||
|
);
|
||||||
|
|
||||||
|
ndc.y = -ndc.y;
|
||||||
|
|
||||||
|
|
||||||
|
gl_Position = vec4(ndc * viewUniform.camScale, 0.0, 1.0);
|
||||||
|
outUV = vec2(inUV.x, 1 - inUV.y);
|
||||||
|
}
|
||||||
|
|
@ -153,5 +153,5 @@ void main() {
|
||||||
outFragColor = vec4(albedo,1.0f);
|
outFragColor = vec4(albedo,1.0f);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// outFragColor = vec4(normal, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.DeferredRendering.Light
|
||||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.Images.TextureCache;
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.Images.TextureCache;
|
||||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.PostProcessing.PostProcess;
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.PostProcessing.PostProcess;
|
||||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.*;
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.*;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Vulkan.SpriteRendering.SpriteRenderer;
|
||||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.CommandBuffer;
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.CommandBuffer;
|
||||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.CommandPool;
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.CommandPool;
|
||||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.GPUSynchronisation.Fence;
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.GPUSynchronisation.Fence;
|
||||||
|
|
@ -47,6 +48,7 @@ public class Render {
|
||||||
private final Queue.PresentQueue PresentQueue;
|
private final Queue.PresentQueue PresentQueue;
|
||||||
private final Semaphore[] RenderCompleteSemaphores;
|
private final Semaphore[] RenderCompleteSemaphores;
|
||||||
private final SceneRenderer sceneRender;
|
private final SceneRenderer sceneRender;
|
||||||
|
private final SpriteRenderer spriteRenderer;
|
||||||
private final LightRenderer lightRenderer;
|
private final LightRenderer lightRenderer;
|
||||||
private final PostProcess PostProcessor;
|
private final PostProcess PostProcessor;
|
||||||
private final SwapChainRender swapChainRender;
|
private final SwapChainRender swapChainRender;
|
||||||
|
|
@ -102,6 +104,7 @@ public class Render {
|
||||||
PostProcessor = new PostProcess(RendererContext, sceneRender.GetAttachmentColour());
|
PostProcessor = new PostProcess(RendererContext, sceneRender.GetAttachmentColour());
|
||||||
lightRenderer = null;
|
lightRenderer = null;
|
||||||
}
|
}
|
||||||
|
spriteRenderer= new SpriteRenderer(engineInstance, RendererContext, PostProcessor.GetAttachment());
|
||||||
GuiRender = new GuiRenderer(engineInstance, RendererContext, GraphicsQueue, PostProcessor.GetAttachment());
|
GuiRender = new GuiRenderer(engineInstance, RendererContext, GraphicsQueue, PostProcessor.GetAttachment());
|
||||||
swapChainRender = new SwapChainRender(RendererContext,PostProcessor.GetAttachment());
|
swapChainRender = new SwapChainRender(RendererContext,PostProcessor.GetAttachment());
|
||||||
textureCache = new TextureCache();
|
textureCache = new TextureCache();
|
||||||
|
|
@ -147,6 +150,8 @@ public class Render {
|
||||||
Logger.debug("Loaded {} models", Models.size());
|
Logger.debug("Loaded {} models", Models.size());
|
||||||
|
|
||||||
sceneRender.LoadMaterials(RendererContext,materialsCache,textureCache);
|
sceneRender.LoadMaterials(RendererContext,materialsCache,textureCache);
|
||||||
|
spriteRenderer.CompileSprites(RendererContext,modelsCache, textureCache);
|
||||||
|
spriteRenderer.LoadMaterials(RendererContext,materialsCache,textureCache);
|
||||||
GuiRender.LoadTextures(RendererContext,initData.GuiTextures(),textureCache);
|
GuiRender.LoadTextures(RendererContext,initData.GuiTextures(),textureCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,6 +174,7 @@ public class Render {
|
||||||
if(lightRenderer != null)lightRenderer.cleanup(RendererContext);
|
if(lightRenderer != null)lightRenderer.cleanup(RendererContext);
|
||||||
PostProcessor.CleanUp(RendererContext);
|
PostProcessor.CleanUp(RendererContext);
|
||||||
swapChainRender.CleanUp(RendererContext);
|
swapChainRender.CleanUp(RendererContext);
|
||||||
|
spriteRenderer.cleanup(RendererContext);
|
||||||
GuiRender.CleanUp(RendererContext);
|
GuiRender.CleanUp(RendererContext);
|
||||||
modelsCache.CleanUp(RendererContext);
|
modelsCache.CleanUp(RendererContext);
|
||||||
materialsCache.CleanUp(RendererContext);
|
materialsCache.CleanUp(RendererContext);
|
||||||
|
|
@ -200,6 +206,7 @@ public class Render {
|
||||||
sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame);
|
sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame);
|
||||||
lightRenderer.render(engineInstance, RendererContext, CommandBuffer, sceneRender.GetMRTAttachments(), CurrentFrame);
|
lightRenderer.render(engineInstance, RendererContext, CommandBuffer, sceneRender.GetMRTAttachments(), CurrentFrame);
|
||||||
PostProcessor.Render(RendererContext,CommandBuffer,lightRenderer.getAttachment());
|
PostProcessor.Render(RendererContext,CommandBuffer,lightRenderer.getAttachment());
|
||||||
|
spriteRenderer.Render(engineInstance,RendererContext,CommandBuffer,PostProcessor.GetAttachment(),modelsCache,CurrentFrame);
|
||||||
GuiRender.Render(RendererContext,CommandBuffer,CurrentFrame,PostProcessor.GetAttachment());
|
GuiRender.Render(RendererContext,CommandBuffer,CurrentFrame,PostProcessor.GetAttachment());
|
||||||
|
|
||||||
int ImageIndex;
|
int ImageIndex;
|
||||||
|
|
@ -226,6 +233,7 @@ public class Render {
|
||||||
|
|
||||||
sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame);
|
sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame);
|
||||||
PostProcessor.Render(RendererContext,CommandBuffer,sceneRender.GetAttachmentColour());
|
PostProcessor.Render(RendererContext,CommandBuffer,sceneRender.GetAttachmentColour());
|
||||||
|
spriteRenderer.Render(engineInstance,RendererContext,CommandBuffer,PostProcessor.GetAttachment(),modelsCache,CurrentFrame);
|
||||||
GuiRender.Render(RendererContext,CommandBuffer,CurrentFrame,PostProcessor.GetAttachment());
|
GuiRender.Render(RendererContext,CommandBuffer,CurrentFrame,PostProcessor.GetAttachment());
|
||||||
|
|
||||||
int ImageIndex;
|
int ImageIndex;
|
||||||
|
|
@ -275,6 +283,7 @@ public class Render {
|
||||||
} else{
|
} else{
|
||||||
PostProcessor.Resize(RendererContext, sceneRender.GetAttachmentColour());
|
PostProcessor.Resize(RendererContext, sceneRender.GetAttachmentColour());
|
||||||
}
|
}
|
||||||
|
spriteRenderer.Resize(engineInstance,RendererContext,PostProcessor.GetAttachment());
|
||||||
GuiRender.Resize(RendererContext,PostProcessor.GetAttachment());
|
GuiRender.Resize(RendererContext,PostProcessor.GetAttachment());
|
||||||
swapChainRender.Resize(RendererContext,PostProcessor.GetAttachment());
|
swapChainRender.Resize(RendererContext,PostProcessor.GetAttachment());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,10 +80,10 @@ public class EngineConfig {
|
||||||
public boolean RenderCollisionMesh = true;
|
public boolean RenderCollisionMesh = true;
|
||||||
public float PhysicsSpeed = 1.0f;
|
public float PhysicsSpeed = 1.0f;
|
||||||
|
|
||||||
public float MusicVolume = 1.0f;
|
public float MusicVolume = 0.0f;
|
||||||
public float SoundVolume = 1.0f;
|
public float SoundVolume = 0.0f;
|
||||||
public float WeaponVolume = 1.0f;
|
public float WeaponVolume = 0.0f;
|
||||||
public float AmbientVolume = 1.0f;
|
public float AmbientVolume = 0.0f;
|
||||||
|
|
||||||
public float PlayerOnline = 1.0f;
|
public float PlayerOnline = 1.0f;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
package net.halbear.Terrain4J.EngineCore.Logic.Physics;
|
||||||
|
|
||||||
|
import org.joml.primitives.AABBf;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class StaticSpatialHashGrid {
|
||||||
|
public static float CellSize = 16f;
|
||||||
|
|
||||||
|
private static final Map<Long, List<String>> Cells = new HashMap<>();
|
||||||
|
|
||||||
|
public static void Clear() {
|
||||||
|
Cells.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Insert(String bodyID, AABBf worldBounds) {
|
||||||
|
int minX = (int) Math.floor(worldBounds.minX / CellSize);
|
||||||
|
int minY = (int) Math.floor(worldBounds.minY / CellSize);
|
||||||
|
int minZ = (int) Math.floor(worldBounds.minZ / CellSize);
|
||||||
|
int maxX = (int) Math.floor(worldBounds.maxX / CellSize);
|
||||||
|
int maxY = (int) Math.floor(worldBounds.maxY / CellSize);
|
||||||
|
int maxZ = (int) Math.floor(worldBounds.maxZ / CellSize);
|
||||||
|
|
||||||
|
for (int x = minX; x <= maxX; x++) {
|
||||||
|
for (int y = minY; y <= maxY; y++) {
|
||||||
|
for (int z = minZ; z <= maxZ; z++) {
|
||||||
|
long key = HashCell(x, y, z);
|
||||||
|
Cells.computeIfAbsent(key, k -> new ArrayList<>()).add(bodyID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long HashCell(int x, int y, int z) {
|
||||||
|
long xi = ((long) x) & 0x1FFFFFL;
|
||||||
|
long yi = ((long) y) & 0x1FFFFFL;
|
||||||
|
long zi = ((long) z) & 0x1FFFFFL;
|
||||||
|
return (xi << 42) | (yi << 21) | zi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Collection<List<String>> Buckets() {
|
||||||
|
return Cells.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -87,7 +87,6 @@ public class GameCore implements GameLogic {
|
||||||
public InitData Initialise(EngineInstance engineInstance) {
|
public InitData Initialise(EngineInstance engineInstance) {
|
||||||
Scene scene = (Scene) engineInstance.scene();
|
Scene scene = (Scene) engineInstance.scene();
|
||||||
List<ModelData> models = new ArrayList<>();
|
List<ModelData> models = new ArrayList<>();
|
||||||
|
|
||||||
MelonaData = ModelLoader.LoadModel("resources/models/cube/Cube.json");
|
MelonaData = ModelLoader.LoadModel("resources/models/cube/Cube.json");
|
||||||
CubeModelID = MelonaData.ID();
|
CubeModelID = MelonaData.ID();
|
||||||
List<MaterialData> MelonaMat = ModelLoader.LoadMaterials("resources/models/cube/Cube_mat.json");
|
List<MaterialData> MelonaMat = ModelLoader.LoadMaterials("resources/models/cube/Cube_mat.json");
|
||||||
|
|
@ -112,6 +111,13 @@ public class GameCore implements GameLogic {
|
||||||
scene.MusketItem = MusketItem;
|
scene.MusketItem = MusketItem;
|
||||||
scene.RevolverItem = RevolverItem;
|
scene.RevolverItem = RevolverItem;
|
||||||
scene.FlintLockItem = FlintLock;
|
scene.FlintLockItem = FlintLock;
|
||||||
|
|
||||||
|
String texturePath = "resources/EngineResources/Texture/Terrain4JTitleImage.png";
|
||||||
|
|
||||||
|
for(int i = 0; i < 200; i++) {
|
||||||
|
float height = 16 + (float)(128f* Math.random());
|
||||||
|
scene.AddSprite(new Sprite("Title" + i, texturePath, new Vector2f(3440.0f * (float) Math.random(), 1440.0f * (float) Math.random()), new Vector2f(height,height), new Vector2f(1,1)));
|
||||||
|
}
|
||||||
boolean createOfflinePlayer = !PrimaryRuntime.Server && !ClientConnectionThread.Connected;
|
boolean createOfflinePlayer = !PrimaryRuntime.Server && !ClientConnectionThread.Connected;
|
||||||
|
|
||||||
materials.addAll(MelonaMat);
|
materials.addAll(MelonaMat);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package net.halbear.Terrain4J.EngineCore.Main.Scene;
|
||||||
|
|
||||||
|
import org.joml.Vector2f;
|
||||||
|
|
||||||
|
public class Camera2D {
|
||||||
|
private final Vector2f Position;
|
||||||
|
private final Vector2f Rotation;
|
||||||
|
private final Vector2f Scale;
|
||||||
|
|
||||||
|
public Camera2D(Vector2f position, Vector2f rotation) {
|
||||||
|
Position = position;
|
||||||
|
Rotation = rotation;
|
||||||
|
Scale = new Vector2f(1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Camera2D(){
|
||||||
|
Position = new Vector2f();
|
||||||
|
Rotation = new Vector2f();
|
||||||
|
Scale = new Vector2f(1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2f GetScale() {
|
||||||
|
return Scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Camera2D SetScale(Vector2f scale) {
|
||||||
|
Scale.set(scale);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2f GetPosition() {
|
||||||
|
return Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2f GetRotation() {
|
||||||
|
return Rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Camera2D SetRotation(Vector2f rotation) {
|
||||||
|
Rotation.set(rotation);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Camera2D SetPosition(Vector2f position) {
|
||||||
|
Position.set(position);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -38,4 +38,6 @@ public interface IScene {
|
||||||
public void SetSkyBox(SkyBox skyBox);
|
public void SetSkyBox(SkyBox skyBox);
|
||||||
public DynamicTerrainMesh GetTerrainMesh();
|
public DynamicTerrainMesh GetTerrainMesh();
|
||||||
public void CreateTerrainMesh();
|
public void CreateTerrainMesh();
|
||||||
|
public List<Sprite> GetSprites();
|
||||||
|
public Camera2D Get2DCamera();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,14 @@ public class Scene implements IScene {
|
||||||
public static long LastGunFire = 0;
|
public static long LastGunFire = 0;
|
||||||
private static final float MOUSE_SENSITIVITY = 0.1f;
|
private static final float MOUSE_SENSITIVITY = 0.1f;
|
||||||
private static final float MOVEMENT_SPEED = 0.025f;
|
private static final float MOVEMENT_SPEED = 0.025f;
|
||||||
|
|
||||||
private final Map<String, Actor> Actors;
|
private final Map<String, Actor> Actors;
|
||||||
private final List<String> ActiveActors;
|
private final List<String> ActiveActors;
|
||||||
|
|
||||||
|
private final Camera2D camera2D;
|
||||||
|
private final Map<String, Sprite> Sprites;
|
||||||
|
private final List<String> ActiveSprites;
|
||||||
|
|
||||||
private final Map<String, CameraFrame> CameraFrames;
|
private final Map<String, CameraFrame> CameraFrames;
|
||||||
private final Project3D Projection;
|
private final Project3D Projection;
|
||||||
private final Camera camera;
|
private final Camera camera;
|
||||||
|
|
@ -101,16 +107,43 @@ public class Scene implements IScene {
|
||||||
terrainMesh = new DynamicTerrainMesh(PrimaryRuntime.GetRenderThread().GetRenderer().GetVulkanContext().GetDevice(), Heights, Width, Height);
|
terrainMesh = new DynamicTerrainMesh(PrimaryRuntime.GetRenderThread().GetRenderer().GetVulkanContext().GetDevice(), Heights, Width, Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Sprite> GetSprites() {
|
||||||
|
List<Sprite> actors = new ArrayList<>();
|
||||||
|
for(int i = 0; i < ActiveSprites.size(); i++){
|
||||||
|
actors.add(Sprites.get(ActiveSprites.get(i)));
|
||||||
|
}
|
||||||
|
return actors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddSprite(Sprite NewActor){
|
||||||
|
if(NewActor == null) return;
|
||||||
|
|
||||||
|
Sprites.put(NewActor.GetID(), NewActor);
|
||||||
|
|
||||||
|
if(!ActiveSprites.contains(NewActor.GetID())) {
|
||||||
|
ActiveSprites.add(NewActor.GetID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Camera2D Get2DCamera() {
|
||||||
|
return camera2D;
|
||||||
|
}
|
||||||
|
|
||||||
public SkyBox GetSkyBox(){return skyBox;}
|
public SkyBox GetSkyBox(){return skyBox;}
|
||||||
|
|
||||||
public Scene(Window window) {
|
public Scene(Window window) {
|
||||||
// CreateTerrainMesh();
|
// CreateTerrainMesh();
|
||||||
lightingManager = new SceneLightingManager(1000,new Vector3f(1f,1f,1f), 0.5f);
|
lightingManager = new SceneLightingManager(1000,new Vector3f(1f,1f,1f), 0.5f);
|
||||||
Actors = new HashMap<>();
|
Actors = new HashMap<>();
|
||||||
|
Sprites = new HashMap<>();
|
||||||
audioInstances = new HashMap<>();
|
audioInstances = new HashMap<>();
|
||||||
ActiveActors = new ArrayList<>();
|
ActiveActors = new ArrayList<>();
|
||||||
|
ActiveSprites = new ArrayList<>();
|
||||||
CameraFrames = new HashMap<>();
|
CameraFrames = new HashMap<>();
|
||||||
var EngConfig = EngineConfig.getInstance();
|
var EngConfig = EngineConfig.getInstance();
|
||||||
|
camera2D = new Camera2D();
|
||||||
camera = new Camera("DebugCamera");
|
camera = new Camera("DebugCamera");
|
||||||
LastCameraFrame = new CameraFrame(camera.GetPosition(),camera.GetRotation(),camera.GetFOV(), "NO_FRAME");
|
LastCameraFrame = new CameraFrame(camera.GetPosition(),camera.GetRotation(),camera.GetFOV(), "NO_FRAME");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,118 @@
|
||||||
|
package net.halbear.Terrain4J.EngineCore.Main.Scene;
|
||||||
|
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.Images.TextureCache;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.ModelsCache;
|
||||||
|
import org.joml.Vector2f;
|
||||||
|
import org.joml.Vector4f;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static net.halbear.Terrain4J.EngineCore.Vulkan.SpriteRendering.SpriteMeshGenerator.GenerateModelFromTexture;
|
||||||
|
|
||||||
|
public class Sprite {
|
||||||
|
public static final Map<String, Sprite> SpriteRegistry = new HashMap<>();
|
||||||
|
|
||||||
|
private String ModelID;
|
||||||
|
private final String textureId;
|
||||||
|
private final Vector2f position;
|
||||||
|
private final Vector2f scale;
|
||||||
|
private final Vector2f size;
|
||||||
|
private final Vector4f colour;
|
||||||
|
private float rotation;
|
||||||
|
private int layer;
|
||||||
|
private final String ID;
|
||||||
|
private int texturePosition;
|
||||||
|
|
||||||
|
public Sprite(String ID, String textureId, Vector2f position, Vector2f Size, Vector2f Scale) {
|
||||||
|
this.ID = ID;
|
||||||
|
this.ModelID = "TO_BE_FULFILLED_LATER";
|
||||||
|
this.textureId = textureId;
|
||||||
|
this.position = new Vector2f().set(position);
|
||||||
|
this.scale = new Vector2f().set(Scale);
|
||||||
|
this.size = new Vector2f().set(Size);
|
||||||
|
this.colour = new Vector4f(1.0f);
|
||||||
|
this.rotation = 0.0f;
|
||||||
|
this.layer = 0;
|
||||||
|
SpriteRegistry.put(ID, this);
|
||||||
|
}
|
||||||
|
public Sprite(String ID, String ModelID, String textureId, Vector2f position, Vector2f Scale, Vector2f Size) {
|
||||||
|
this.ID = ID;
|
||||||
|
this.ModelID = ModelID;
|
||||||
|
this.textureId = textureId;
|
||||||
|
this.position = new Vector2f().set(position);
|
||||||
|
this.scale = new Vector2f().set(Scale);
|
||||||
|
this.size = new Vector2f().set(Size);
|
||||||
|
this.colour = new Vector4f(1.0f);
|
||||||
|
this.rotation = 0.0f;
|
||||||
|
this.layer = 0;
|
||||||
|
SpriteRegistry.put(ID, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sprite(String ID, String TextureID, Vector2f Position, Vector2f Scale, Vector2f Size, TextureCache textureCache, ModelsCache modelsCache, VulkanContext VkCtx){
|
||||||
|
this.ID = ID;
|
||||||
|
this.textureId = TextureID;
|
||||||
|
this.ModelID = GenerateModelFromTexture(textureCache, modelsCache, VkCtx, TextureID, Size.y);
|
||||||
|
texturePosition = textureCache.GetPosition(textureId);
|
||||||
|
this.position = new Vector2f().set(Position);
|
||||||
|
this.scale = new Vector2f().set(Scale);
|
||||||
|
this.size = new Vector2f().set(Size);
|
||||||
|
this.colour = new Vector4f(1.0f);
|
||||||
|
SpriteRegistry.put(ID, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sprite CompileSprite(TextureCache textureCache, ModelsCache modelsCache, VulkanContext VkCtx){
|
||||||
|
this.ModelID = GenerateModelFromTexture(textureCache, modelsCache, VkCtx, textureId, this.size.y);
|
||||||
|
texturePosition = textureCache.GetPosition(textureId);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetTexturePosition(){
|
||||||
|
return texturePosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String GetID(){
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String GetModelID() {
|
||||||
|
return ModelID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String GetTextureID() {
|
||||||
|
return textureId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2f GetPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2f GetSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2f GetScale() {
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector4f GetColour() {
|
||||||
|
return colour;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetRotation() {
|
||||||
|
return rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetRotation(float rotation) {
|
||||||
|
this.rotation = rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetLayer() {
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetLayer(int layer) {
|
||||||
|
this.layer = layer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -76,6 +76,18 @@ public class ClientConnectionThread implements Runnable{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final Map<Byte, Boolean> BypassNullTargets = new HashMap<>();
|
||||||
|
|
||||||
|
static{
|
||||||
|
BypassNullTargets.put(Packet.PACKET_CREATE_ACTOR, true);
|
||||||
|
BypassNullTargets.put(Packet.PACKET_PING, true);
|
||||||
|
BypassNullTargets.put(Packet.PACKET_POSSESS_ACTOR, true);
|
||||||
|
BypassNullTargets.put(Packet.PACKET_DESTROY_ACTOR, true );
|
||||||
|
BypassNullTargets.put(Packet.PACKET_ASSIGN_UUID, true );
|
||||||
|
BypassNullTargets.put(Packet.PACKET_SEND_PLAYER_COUNT, true );
|
||||||
|
BypassNullTargets.put(Packet.PACKET_FIRE_RESULT, true);
|
||||||
|
}
|
||||||
|
|
||||||
public static void DecodePackets(EngineInstance engineInstance, GameCore gameCore, IScene scene){
|
public static void DecodePackets(EngineInstance engineInstance, GameCore gameCore, IScene scene){
|
||||||
if(!IncomingPacketQueue.isEmpty()){
|
if(!IncomingPacketQueue.isEmpty()){
|
||||||
Packet packet;
|
Packet packet;
|
||||||
|
|
@ -90,31 +102,26 @@ public class ClientConnectionThread implements Runnable{
|
||||||
vector3f = Packet.DecodeAsVector3f(packet.Data);
|
vector3f = Packet.DecodeAsVector3f(packet.Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Target == null
|
if(Target == null &&
|
||||||
&& packet.PacketTypeByte != Packet.PACKET_CREATE_ACTOR
|
(!BypassNullTargets.containsKey(packet.PacketTypeByte) || !BypassNullTargets.get(packet.PacketTypeByte))) {
|
||||||
&& packet.PacketTypeByte != Packet.PACKET_PING
|
|
||||||
&& packet.PacketTypeByte != Packet.PACKET_POSSESS_ACTOR
|
|
||||||
&& packet.PacketTypeByte != Packet.PACKET_DESTROY_ACTOR
|
|
||||||
&& packet.PacketTypeByte != Packet.PACKET_ASSIGN_UUID
|
|
||||||
&& packet.PacketTypeByte != Packet.PACKET_SEND_PLAYER_COUNT) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (packet.PacketTypeByte) {
|
switch (packet.PacketTypeByte) {
|
||||||
case 0:
|
case Packet.PACKET_UPDATE_LOCATION:
|
||||||
Target.SetNewPosition(vector3f);
|
Target.SetNewPosition(vector3f);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case Packet.PACKET_UPDATE_ROTATION:
|
||||||
quaternionfdata = Packet.DecodeAsQuaternation(packet.Data);
|
quaternionfdata = Packet.DecodeAsQuaternation(packet.Data);
|
||||||
Target.SetNewRotation(quaternionfdata);
|
Target.SetNewRotation(quaternionfdata);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case Packet.PACKET_UPDATE_LINEAR_VELOCITY:
|
||||||
Target.SetNewVelocity(vector3f);
|
Target.SetNewVelocity(vector3f);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case Packet.PACKET_UPDATE_ANGULAR_VELOCITY:
|
||||||
Target.SetNewAngularVelocity(vector3f);
|
Target.SetNewAngularVelocity(vector3f);
|
||||||
break;
|
break;
|
||||||
case 4: //"ACtorType:ModelID:x:y:z:rx:ry:rz:sx:sy:sz:hx:hy:hz:MassKG:vx:vy:vz:avx:avy:avz:posOffx:posOffy:posOffz:camOffx:camOffy:camOffz"
|
case Packet.PACKET_CREATE_ACTOR: //"ACtorType:ModelID:x:y:z:rx:ry:rz:sx:sy:sz:hx:hy:hz:MassKG:vx:vy:vz:avx:avy:avz:posOffx:posOffy:posOffz:camOffx:camOffy:camOffz"
|
||||||
try {
|
try {
|
||||||
stringdata = Packet.DecodeAsString(packet.Data);
|
stringdata = Packet.DecodeAsString(packet.Data);
|
||||||
String[] Split = stringdata.split(":");
|
String[] Split = stringdata.split(":");
|
||||||
|
|
@ -217,7 +224,7 @@ public class ClientConnectionThread implements Runnable{
|
||||||
Logger.error(e, "Failed to decode create actor packet for actor [{}]", packet.TargetID);
|
Logger.error(e, "Failed to decode create actor packet for actor [{}]", packet.TargetID);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 6:
|
case Packet.PACKET_MOVEMENT_UPDATE:
|
||||||
MovementUpdate = Packet.DecodeAsMovementUpdate(packet.Data);
|
MovementUpdate = Packet.DecodeAsMovementUpdate(packet.Data);
|
||||||
|
|
||||||
if(packet.TargetID.equals(OwnedActorID)) {
|
if(packet.TargetID.equals(OwnedActorID)) {
|
||||||
|
|
@ -230,16 +237,16 @@ public class ClientConnectionThread implements Runnable{
|
||||||
Target.SetNewVelocity(MovementUpdate.LinearVelocity);
|
Target.SetNewVelocity(MovementUpdate.LinearVelocity);
|
||||||
Target.SetNewAngularVelocity(MovementUpdate.AngularVelocity);
|
Target.SetNewAngularVelocity(MovementUpdate.AngularVelocity);
|
||||||
break;
|
break;
|
||||||
case 8:
|
case Packet.PACKET_POSSESS_ACTOR:
|
||||||
TryPossessActor(packet.TargetID, gameCore, scene);
|
TryPossessActor(packet.TargetID, gameCore, scene);
|
||||||
break;
|
break;
|
||||||
case 9:
|
case Packet.PACKET_DESTROY_ACTOR:
|
||||||
Actor actorToDestroy = Actor.Actors.get(packet.TargetID);
|
Actor actorToDestroy = Actor.Actors.get(packet.TargetID);
|
||||||
if(actorToDestroy != null) {
|
if(actorToDestroy != null) {
|
||||||
scene.RemoveActor(actorToDestroy);
|
scene.RemoveActor(actorToDestroy);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 11:
|
case Packet.PACKET_UPDATE_MODEL_ID:
|
||||||
Logger.debug("Rebound packet received for actor [{}]", packet.TargetID);
|
Logger.debug("Rebound packet received for actor [{}]", packet.TargetID);
|
||||||
stringdata = Packet.DecodeAsString(packet.Data);
|
stringdata = Packet.DecodeAsString(packet.Data);
|
||||||
Actor actorToChangeModelID = Actor.Actors.get(packet.TargetID);
|
Actor actorToChangeModelID = Actor.Actors.get(packet.TargetID);
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import net.halbear.Terrain4J.EngineCore.Main.Util.Maths.T4Raycast;
|
||||||
import net.halbear.Terrain4J.EngineCore.ServerNetworking.Packet;
|
import net.halbear.Terrain4J.EngineCore.ServerNetworking.Packet;
|
||||||
import org.joml.Quaternionf;
|
import org.joml.Quaternionf;
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
|
@ -248,6 +249,7 @@ public class ServerConnectionThread implements Runnable{
|
||||||
} else {
|
} else {
|
||||||
resultPoint = new Vector3f(request.Direction).normalize().mul(request.MaxRange).add(request.Origin);
|
resultPoint = new Vector3f(request.Direction).normalize().mul(request.MaxRange).add(request.Origin);
|
||||||
}
|
}
|
||||||
|
// Logger.debug("\n Raycast Result: " + hit + "\n Raycast Request: Origin->" + request.Origin + " | Direction->" + request.Direction + " | MaxRange->" + request.MaxRange + "\n Result point: " + resultPoint + "\n Hit Actor: " + hitActorID);
|
||||||
|
|
||||||
Packet result = new Packet(Packet.PACKET_FIRE_RESULT);
|
Packet result = new Packet(Packet.PACKET_FIRE_RESULT);
|
||||||
result.SetID(hitActorID);
|
result.SetID(hitActorID);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
|
||||||
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
|
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
|
||||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.DescriptorAllocator;
|
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.DescriptorSet;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Vulkan.SpriteRendering.SpriteMeshGenerator;
|
||||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.CommandBuffer;
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.CommandBuffer;
|
||||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.CommandPool;
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.CommandPool;
|
||||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.GPUSynchronisation.TransferBuffer;
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.GPUSynchronisation.TransferBuffer;
|
||||||
|
|
@ -18,6 +19,7 @@ import org.lwjgl.vulkan.VkCommandBuffer;
|
||||||
import org.tinylog.Logger;
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
import java.nio.LongBuffer;
|
import java.nio.LongBuffer;
|
||||||
|
|
@ -79,6 +81,64 @@ public class ModelsCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String createSpriteModel(VulkanContext vulkanContext, SpriteMeshGenerator.GeneratedSpriteMesh generatedMesh, String modelId) {
|
||||||
|
if (ModelsMap.containsKey(modelId)) {
|
||||||
|
return modelId;
|
||||||
|
}
|
||||||
|
|
||||||
|
float[] vertices = generatedMesh.vertices();
|
||||||
|
int[] indices = generatedMesh.indices();
|
||||||
|
|
||||||
|
int vertexBufferSize = vertices.length * VulkanUtils.FLOAT_SIZE;
|
||||||
|
int indexBufferSize = indices.length * VulkanUtils.INT_SIZE;
|
||||||
|
|
||||||
|
VulkanBuffer verticesBuffer = new VulkanBuffer(
|
||||||
|
vulkanContext,
|
||||||
|
vertexBufferSize,
|
||||||
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||||
|
VMA_MEMORY_USAGE_AUTO,
|
||||||
|
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||||
|
);
|
||||||
|
|
||||||
|
VulkanBuffer indicesBuffer = new VulkanBuffer(
|
||||||
|
vulkanContext,
|
||||||
|
indexBufferSize,
|
||||||
|
VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
||||||
|
VMA_MEMORY_USAGE_AUTO,
|
||||||
|
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||||
|
);
|
||||||
|
|
||||||
|
long mappedVertices = verticesBuffer.MapMemory(vulkanContext);
|
||||||
|
ByteBuffer vertexByteBuffer = MemoryUtil.memByteBuffer(mappedVertices, vertexBufferSize);
|
||||||
|
FloatBuffer vertexFloatBuffer = vertexByteBuffer.asFloatBuffer();
|
||||||
|
vertexFloatBuffer.put(vertices);
|
||||||
|
verticesBuffer.UnMapMemory(vulkanContext);
|
||||||
|
|
||||||
|
long mappedIndices = indicesBuffer.MapMemory(vulkanContext);
|
||||||
|
ByteBuffer indexByteBuffer = MemoryUtil.memByteBuffer(mappedIndices, indexBufferSize);
|
||||||
|
IntBuffer indexIntBuffer = indexByteBuffer.asIntBuffer();
|
||||||
|
indexIntBuffer.put(indices);
|
||||||
|
indicesBuffer.UnMapMemory(vulkanContext);
|
||||||
|
|
||||||
|
VulkanModel model = new VulkanModel(modelId);
|
||||||
|
VulkanMesh mesh = new VulkanMesh(
|
||||||
|
modelId + "_MESH",
|
||||||
|
verticesBuffer,
|
||||||
|
indicesBuffer,
|
||||||
|
indices.length,
|
||||||
|
"NULL_MAT"
|
||||||
|
);
|
||||||
|
|
||||||
|
model.GetVkMeshList().add(mesh);
|
||||||
|
ModelsMap.put(modelId, model);
|
||||||
|
|
||||||
|
return modelId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void loadModels(VulkanContext VkCtx, List<ModelData> Models, CommandPool commandPool, Queue queue){
|
public void loadModels(VulkanContext VkCtx, List<ModelData> Models, CommandPool commandPool, Queue queue){
|
||||||
try {
|
try {
|
||||||
List<VulkanBuffer> StagingBufferList = new ArrayList<>();
|
List<VulkanBuffer> StagingBufferList = new ArrayList<>();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
package net.halbear.Terrain4J.EngineCore.Vulkan.SpriteRendering;
|
||||||
|
|
||||||
|
public final class BillboardMeshGenerator {
|
||||||
|
|
||||||
|
private BillboardMeshGenerator() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GeneratedSpriteMesh createQuad(float width, float height) {
|
||||||
|
float halfWidth = width * 0.5f;
|
||||||
|
float halfHeight = height * 0.5f;
|
||||||
|
|
||||||
|
float normalX = 0.0f;
|
||||||
|
float normalY = 0.0f;
|
||||||
|
float normalZ = 1.0f;
|
||||||
|
|
||||||
|
float tangentX = 1.0f;
|
||||||
|
float tangentY = 0.0f;
|
||||||
|
float tangentZ = 0.0f;
|
||||||
|
|
||||||
|
float bitangentX = 0.0f;
|
||||||
|
float bitangentY = 1.0f;
|
||||||
|
float bitangentZ = 0.0f;
|
||||||
|
|
||||||
|
float[] vertices = new float[] {
|
||||||
|
// pos.xyz normal.xyz tangent.xyz bitangent.xyz uv.xy
|
||||||
|
-halfWidth, -halfHeight, 0.0f, normalX, normalY, normalZ, tangentX, tangentY, tangentZ, bitangentX, bitangentY, bitangentZ, 0.0f, 1.0f,
|
||||||
|
halfWidth, -halfHeight, 0.0f, normalX, normalY, normalZ, tangentX, tangentY, tangentZ, bitangentX, bitangentY, bitangentZ, 1.0f, 1.0f,
|
||||||
|
halfWidth, halfHeight, 0.0f, normalX, normalY, normalZ, tangentX, tangentY, tangentZ, bitangentX, bitangentY, bitangentZ, 1.0f, 0.0f,
|
||||||
|
-halfWidth, halfHeight, 0.0f, normalX, normalY, normalZ, tangentX, tangentY, tangentZ, bitangentX, bitangentY, bitangentZ, 0.0f, 0.0f
|
||||||
|
};
|
||||||
|
|
||||||
|
int[] indices = new int[] {
|
||||||
|
0, 1, 2,
|
||||||
|
2, 3, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
return new GeneratedSpriteMesh(vertices, indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GeneratedSpriteMesh createQuadFromTextureSize(int textureWidth, int textureHeight, float worldHeight) {
|
||||||
|
float aspect = (float) textureWidth / (float) textureHeight;
|
||||||
|
float worldWidth = worldHeight * aspect;
|
||||||
|
return createQuad(worldWidth, worldHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record GeneratedSpriteMesh(float[] vertices, int[] indices) {}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
package net.halbear.Terrain4J.EngineCore.Vulkan.SpriteRendering;
|
||||||
|
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.Images.TextureCache;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.ModelsCache;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.lwjgl.vulkan.VK10.VK_FORMAT_R8G8B8A8_SRGB;
|
||||||
|
|
||||||
|
public final class SpriteMeshGenerator {
|
||||||
|
|
||||||
|
public static final Map<String, GeneratedSpriteMesh> SPRITE_MESHES = new HashMap<>();
|
||||||
|
public static final Map<String, String> CACHED_MODELS = new HashMap<>();
|
||||||
|
|
||||||
|
public static void CacheModels(VulkanContext vkCtx, ModelsCache cache){
|
||||||
|
CACHED_MODELS.clear();
|
||||||
|
SPRITE_MESHES.forEach((x, y)->{
|
||||||
|
CACHED_MODELS.put(x, cache.createSpriteModel(vkCtx, y,x));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private SpriteMeshGenerator() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static GeneratedSpriteMesh createUnitQuad() {
|
||||||
|
float[] vertices = new float[] {
|
||||||
|
// pos.xy uv.xy
|
||||||
|
-0.5f, -0.5f, 0.0f, 1.0f,
|
||||||
|
0.5f, -0.5f, 1.0f, 1.0f,
|
||||||
|
0.5f, 0.5f, 1.0f, 0.0f,
|
||||||
|
-0.5f, 0.5f, 0.0f, 0.0f
|
||||||
|
};
|
||||||
|
|
||||||
|
int[] indices = new int[] {
|
||||||
|
0, 1, 2,
|
||||||
|
2, 3, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
return new GeneratedSpriteMesh(vertices, indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String GenerateModelFromTexture(TextureCache textureCache, ModelsCache modelsCache, VulkanContext VkCtx, String TexturePath, float BaseHeight){
|
||||||
|
textureCache.AddTexture(VkCtx, TexturePath, TexturePath, VK_FORMAT_R8G8B8A8_SRGB);
|
||||||
|
var texture = textureCache.GetTexture(TexturePath);
|
||||||
|
int Width = texture.GetWidth();
|
||||||
|
int Height = texture.GetHeight();
|
||||||
|
float aspect = (float) Width / (float) Height;
|
||||||
|
return modelsCache.createSpriteModel(VkCtx, createQuad(BaseHeight*aspect, BaseHeight), TexturePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GeneratedSpriteMesh createQuad(float width, float height) {
|
||||||
|
float halfWidth = width * 0.5f;
|
||||||
|
float halfHeight = height * 0.5f;
|
||||||
|
|
||||||
|
float[] vertices = new float[] {
|
||||||
|
// pos.xy uv.xy
|
||||||
|
-halfWidth, -halfHeight, 0.0f, 1.0f,
|
||||||
|
halfWidth, -halfHeight, 1.0f, 1.0f,
|
||||||
|
halfWidth, halfHeight, 1.0f, 0.0f,
|
||||||
|
-halfWidth, halfHeight, 0.0f, 0.0f
|
||||||
|
};
|
||||||
|
|
||||||
|
int[] indices = new int[] {
|
||||||
|
0, 1, 2,
|
||||||
|
2, 3, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
return new GeneratedSpriteMesh(vertices, indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeSprite(float[] dst,int offset,float x,float y,float width,float height) {
|
||||||
|
// vertex format:
|
||||||
|
// pos.xy, uv.xy, color.rgba
|
||||||
|
|
||||||
|
int i = offset;
|
||||||
|
|
||||||
|
// bottom-left
|
||||||
|
dst[i++] = x;
|
||||||
|
dst[i++] = y + height;
|
||||||
|
dst[i++] = 0.0f;
|
||||||
|
dst[i++] = 1.0f;
|
||||||
|
|
||||||
|
// bottom-right
|
||||||
|
dst[i++] = x + width;
|
||||||
|
dst[i++] = y + height;
|
||||||
|
dst[i++] = 1.0f;
|
||||||
|
dst[i++] = 1.0f;
|
||||||
|
|
||||||
|
// top-right
|
||||||
|
dst[i++] = x + width;
|
||||||
|
dst[i++] = y;
|
||||||
|
dst[i++] = 1.0f;
|
||||||
|
dst[i++] = 0.0f;
|
||||||
|
|
||||||
|
// top-left
|
||||||
|
dst[i++] = x;
|
||||||
|
dst[i++] = y;
|
||||||
|
dst[i++] = 0.0f;
|
||||||
|
dst[i++] = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeIndices(int[] dst, int offset, int vertexBase) {
|
||||||
|
dst[offset] = vertexBase;
|
||||||
|
dst[offset + 1] = vertexBase + 1;
|
||||||
|
dst[offset + 2] = vertexBase + 2;
|
||||||
|
|
||||||
|
dst[offset + 3] = vertexBase + 2;
|
||||||
|
dst[offset + 4] = vertexBase + 3;
|
||||||
|
dst[offset + 5] = vertexBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record GeneratedSpriteMesh(float[] vertices, int[] indices) {}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,334 @@
|
||||||
|
package net.halbear.Terrain4J.EngineCore.Vulkan.SpriteRendering;
|
||||||
|
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Main.Scene.Sprite;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.DeferredRendering.MultiRenderTargetAttachments;
|
||||||
|
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;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.PipelineBuildInfo;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.PushConstantsRange;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.*;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.*;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.CommandBuffer;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.Device;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen.ImageView;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.SwapChain.SwapChain;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanBuffer;
|
||||||
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils;
|
||||||
|
import org.joml.Vector2f;
|
||||||
|
import org.lwjgl.system.MemoryStack;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
import org.lwjgl.util.shaderc.Shaderc;
|
||||||
|
import org.lwjgl.vulkan.*;
|
||||||
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.LongBuffer;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.lwjgl.vulkan.VK10.*;
|
||||||
|
import static org.lwjgl.vulkan.VK10.VK_BORDER_COLOR_INT_OPAQUE_BLACK;
|
||||||
|
import static org.lwjgl.vulkan.VK13.*;
|
||||||
|
import static org.lwjgl.vulkan.VK13.vkCmdEndRendering;
|
||||||
|
|
||||||
|
public class SpriteRenderer {
|
||||||
|
private static final String DESCRIPTOR_ID_PRJ = "SPRITE_DESC_ID_PRJ";
|
||||||
|
private static final String DESCRIPTOR_ID_VIEW = "SPRITE_DESC_ID_VIEW";
|
||||||
|
private static final String DESCRIPTOR_ID_TEXTURE = "SPRITE_DESC_ID_TEXT";
|
||||||
|
private static final String SPRITE_FRAGMENT_SHADER_GLSL = "resources/EngineResources/SpriteShaders/sprite_fragment.glsl";
|
||||||
|
private static final String SPRITE_FRAGMENT_SHADER_SPV = SPRITE_FRAGMENT_SHADER_GLSL + ".spv";
|
||||||
|
private static final String SPRITE_TRANSLUCENT_FRAGMENT_SHADER_GLSL = "resources/EngineResources/SpriteShaders/sprite_translucent_fragment.glsl";
|
||||||
|
private static final String SPRITE_TRANSLUCENT_FRAGMENT_SHADER_SPV = SPRITE_FRAGMENT_SHADER_GLSL + ".spv";
|
||||||
|
private static final String SPRITE_VERTEX_SHADER_GLSL = "resources/EngineResources/SpriteShaders/sprite_vertex.glsl";
|
||||||
|
private static final String SPRITE_VERTEX_SHADER_SPV = SPRITE_VERTEX_SHADER_GLSL + ".spv";
|
||||||
|
private static final int PUSH_CONSTANTS_SIZE = VulkanUtils.VEC2_SIZE + VulkanUtils.VEC2_SIZE + VulkanUtils.VEC2_SIZE + VulkanUtils.INT_SIZE;
|
||||||
|
|
||||||
|
private final VulkanBuffer[] IndexBuffers;
|
||||||
|
private final VulkanBuffer[] VertexBuffers;
|
||||||
|
private final TextureSampler TextureSampler;
|
||||||
|
private final Map<Long,Long> TexturesMap;
|
||||||
|
private Pipeline VkPipelineOpaque;
|
||||||
|
private Pipeline VkPipelineTranslucent;
|
||||||
|
private final DescriptorSetLayout TextDescriptorSetLayout;
|
||||||
|
private final DescriptorSetLayout descriptorLayoutVertexUniform;
|
||||||
|
|
||||||
|
public static final int COLOUR_FORMAT = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||||
|
public static final int DEPTH_FORMAT = VK_FORMAT_D32_SFLOAT;
|
||||||
|
private final VkClearValue ClearValueDepth;
|
||||||
|
private final ByteBuffer PushConstBuffer;
|
||||||
|
private Attachment AttachmentDepth;
|
||||||
|
private Attachment AttachmentColour;
|
||||||
|
private VkRenderingAttachmentInfo AttachmentInfoDepth;
|
||||||
|
private VkClearValue ClearValueColour;
|
||||||
|
private VkRenderingAttachmentInfo.Buffer AttachmentInfoColour;
|
||||||
|
private VkRenderingInfo RenderInfo;
|
||||||
|
private final VulkanBuffer[] BufferViewMatrices;
|
||||||
|
|
||||||
|
public SpriteRenderer(EngineInstance engineInstance, VulkanContext VkCtx, Attachment dstAttachment){
|
||||||
|
ClearValueColour = VkClearValue.calloc().color(
|
||||||
|
c -> c.float32(0, 0.0f).float32(1, 0.0f).float32(2, 0.0f).float32(3, 0.0f));
|
||||||
|
ClearValueDepth = VkClearValue.calloc().color(c -> c.float32(0, 0.0f));
|
||||||
|
// AttachmentColour = CreateColourAttachment(VkCtx);//
|
||||||
|
AttachmentInfoColour = CreateColourAttachmentInfo(dstAttachment, ClearValueColour);
|
||||||
|
AttachmentDepth = CreateDepthAttachment(VkCtx);
|
||||||
|
AttachmentInfoDepth = CreateDepthAttachmentInfo(AttachmentDepth, ClearValueDepth);
|
||||||
|
RenderInfo = CreateRenderInfo(dstAttachment,AttachmentInfoColour, AttachmentInfoDepth);
|
||||||
|
//RenderInfo = CreateRenderInfo(AttachmentColour, AttachmentInfoColour, AttachmentInfoDepth);
|
||||||
|
VertexBuffers = new VulkanBuffer[VulkanUtils.MAX_IN_FLIGHT];
|
||||||
|
IndexBuffers = new VulkanBuffer[VulkanUtils.MAX_IN_FLIGHT];
|
||||||
|
PushConstBuffer = (MemoryUtil.memAlloc(PUSH_CONSTANTS_SIZE));
|
||||||
|
var textureSamplerInfo = new TextureSamplerInfo(VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
||||||
|
VK_BORDER_COLOR_INT_OPAQUE_BLACK, 1, true);
|
||||||
|
TextureSampler = new TextureSampler(VkCtx, textureSamplerInfo);
|
||||||
|
TextDescriptorSetLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
|
0, TextureCache.MAX_TEXTURES, VK_SHADER_STAGE_FRAGMENT_BIT));
|
||||||
|
descriptorLayoutVertexUniform = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
|
0, 1, VK_SHADER_STAGE_VERTEX_BIT));
|
||||||
|
BufferViewMatrices = VulkanUtils.CreateHostVisibleBuffers(VkCtx, VulkanUtils.VEC2_SIZE * 2, VulkanUtils.MAX_IN_FLIGHT,
|
||||||
|
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, DESCRIPTOR_ID_VIEW, descriptorLayoutVertexUniform);
|
||||||
|
|
||||||
|
TexturesMap = new HashMap<>();
|
||||||
|
DescriptorSetLayout[] layouts = new DescriptorSetLayout[]{
|
||||||
|
descriptorLayoutVertexUniform,
|
||||||
|
TextDescriptorSetLayout
|
||||||
|
};
|
||||||
|
ShaderModule[] shadermodules = CreateShaderModules(VkCtx,0);
|
||||||
|
VkPipelineOpaque = CreatePipeline(VkCtx, shadermodules, layouts, true, false, true, false, 1);
|
||||||
|
shadermodules = CreateShaderModules(VkCtx,2);
|
||||||
|
VkPipelineTranslucent = CreatePipeline(VkCtx, shadermodules, layouts, false, true, true, false, 1);
|
||||||
|
Arrays.asList(shadermodules).forEach(s->s.CleanUp(VkCtx));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Attachment CreateColourAttachment(VulkanContext VkCtx){
|
||||||
|
SwapChain swapChain = VkCtx.GetSwapChain();
|
||||||
|
VkExtent2D SwapChainExtent = swapChain.GetSwapChainExtent();
|
||||||
|
return new Attachment(VkCtx, SwapChainExtent.width(), SwapChainExtent.height(), COLOUR_FORMAT,VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static VkRenderingAttachmentInfo.Buffer CreateColourAttachmentInfo(Attachment attachment, VkClearValue ClearValue){
|
||||||
|
return VkRenderingAttachmentInfo.calloc(1)
|
||||||
|
.sType$Default()
|
||||||
|
.imageView(attachment.GetVkImageView().GetVulkanImageView())
|
||||||
|
.imageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
|
||||||
|
.loadOp(VK_ATTACHMENT_LOAD_OP_LOAD)
|
||||||
|
.storeOp(VK_ATTACHMENT_STORE_OP_STORE)
|
||||||
|
.clearValue(ClearValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Attachment CreateDepthAttachment(VulkanContext VkCtx){
|
||||||
|
SwapChain swapChain = VkCtx.GetSwapChain();
|
||||||
|
VkExtent2D swapChainExtent = swapChain.GetSwapChainExtent();
|
||||||
|
return new Attachment(VkCtx, swapChainExtent.width(), swapChainExtent.height(),
|
||||||
|
DEPTH_FORMAT,VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static VkRenderingAttachmentInfo CreateDepthAttachmentInfo(Attachment DepthAttachment, VkClearValue clearValue){
|
||||||
|
return VkRenderingAttachmentInfo.calloc()
|
||||||
|
.sType$Default()
|
||||||
|
.imageView(DepthAttachment.GetVkImageView().GetVulkanImageView())
|
||||||
|
.imageLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
|
||||||
|
.loadOp(VK_ATTACHMENT_LOAD_OP_CLEAR)
|
||||||
|
.storeOp(VK_ATTACHMENT_STORE_OP_DONT_CARE)
|
||||||
|
.clearValue(clearValue);
|
||||||
|
}
|
||||||
|
private static ShaderModule[] CreateShaderModules(VulkanContext VkCtx, int Translucent){
|
||||||
|
if(EngineConfig.getInstance().RecompileShaders()){
|
||||||
|
ShaderCompiler.CompileGLSLShaderOnChange(SPRITE_VERTEX_SHADER_GLSL, Shaderc.shaderc_glsl_vertex_shader);
|
||||||
|
ShaderCompiler.CompileGLSLShaderOnChange( Translucent == 2 ? SPRITE_TRANSLUCENT_FRAGMENT_SHADER_GLSL : SPRITE_FRAGMENT_SHADER_GLSL, Shaderc.shaderc_glsl_fragment_shader);
|
||||||
|
}
|
||||||
|
return new ShaderModule[]{
|
||||||
|
new ShaderModule(VkCtx, VK_SHADER_STAGE_VERTEX_BIT, SPRITE_VERTEX_SHADER_SPV,null),
|
||||||
|
new ShaderModule(VkCtx, VK_SHADER_STAGE_FRAGMENT_BIT, Translucent == 2 ? SPRITE_TRANSLUCENT_FRAGMENT_SHADER_SPV : SPRITE_FRAGMENT_SHADER_SPV,null)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Pipeline CreatePipeline(VulkanContext VkCtx, ShaderModule[] ShaderModules, DescriptorSetLayout[] DescriptorSetLayouts, boolean DepthWrite, boolean DualRender, boolean Blending, boolean AlphaToCoverage, int BlendingMethod){
|
||||||
|
var vertexBufferStructure = new SpriteVertexBufferStructure();
|
||||||
|
var BuildInfo = new PipelineBuildInfo(ShaderModules,vertexBufferStructure.getVertexInput(),new int[]{MultiRenderTargetAttachments.ALBEDO_FORMAT})
|
||||||
|
.SetDepthFormat(MultiRenderTargetAttachments.DEPTH_FORMAT)
|
||||||
|
.SetDepthWrite(DepthWrite)
|
||||||
|
.SetPushConstantRanges(
|
||||||
|
new PushConstantsRange[]{
|
||||||
|
new PushConstantsRange(VK_SHADER_STAGE_VERTEX_BIT,0,VulkanUtils.VEC2_SIZE),
|
||||||
|
new PushConstantsRange(VK_SHADER_STAGE_VERTEX_BIT,VulkanUtils.VEC2_SIZE,VulkanUtils.VEC2_SIZE),
|
||||||
|
new PushConstantsRange(VK_SHADER_STAGE_VERTEX_BIT,VulkanUtils.VEC2_SIZE * 2,VulkanUtils.VEC2_SIZE),
|
||||||
|
new PushConstantsRange(VK_SHADER_STAGE_FRAGMENT_BIT,VulkanUtils.VEC2_SIZE * 3,VulkanUtils.INT_SIZE)
|
||||||
|
})
|
||||||
|
.SetDescriptorSetLayouts(DescriptorSetLayouts)
|
||||||
|
.SetBlendingMethod(BlendingMethod)
|
||||||
|
.BlendingIsUsed(Blending)
|
||||||
|
.SetDualPass(DualRender)
|
||||||
|
.SetAlphaToCoverage(AlphaToCoverage);
|
||||||
|
var pipeline = new DefaultPipeline(VkCtx, BuildInfo);
|
||||||
|
Logger.debug("Pipeline Created");
|
||||||
|
vertexBufferStructure.cleanup();
|
||||||
|
return pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetPushConstants(VkCommandBuffer CmdHandle, Vector2f ScreenSize, Vector2f ModelSize, Vector2f Position, int TextureIndex, Pipeline VkPipeline){
|
||||||
|
ModelSize.get(0,PushConstBuffer);
|
||||||
|
Position.get(VulkanUtils.VEC2_SIZE, PushConstBuffer);
|
||||||
|
ScreenSize.get(VulkanUtils.VEC2_SIZE * 2, PushConstBuffer);
|
||||||
|
PushConstBuffer.putInt(VulkanUtils.VEC2_SIZE * 3, TextureIndex);
|
||||||
|
vkCmdPushConstants(CmdHandle, VkPipeline.GetVulkanPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0,
|
||||||
|
PushConstBuffer.slice(0,VulkanUtils.VEC2_SIZE));
|
||||||
|
vkCmdPushConstants(CmdHandle, VkPipeline.GetVulkanPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT, VulkanUtils.VEC2_SIZE,
|
||||||
|
PushConstBuffer.slice(VulkanUtils.VEC2_SIZE,VulkanUtils.VEC2_SIZE));
|
||||||
|
vkCmdPushConstants(CmdHandle, VkPipeline.GetVulkanPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT, VulkanUtils.VEC2_SIZE * 2,
|
||||||
|
PushConstBuffer.slice(VulkanUtils.VEC2_SIZE * 2,VulkanUtils.VEC2_SIZE));
|
||||||
|
vkCmdPushConstants(CmdHandle, VkPipeline.GetVulkanPipelineLayout(), VK_SHADER_STAGE_FRAGMENT_BIT, VulkanUtils.VEC2_SIZE * 3,
|
||||||
|
PushConstBuffer.slice(VulkanUtils.VEC2_SIZE* 3, VulkanUtils.INT_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Resize(EngineInstance instance, VulkanContext VkCtx, Attachment dstAttachment){
|
||||||
|
AttachmentInfoDepth.free();
|
||||||
|
//AttachmentColour.CleanUp(VkCtx);
|
||||||
|
AttachmentDepth.CleanUp(VkCtx);
|
||||||
|
AttachmentDepth = CreateDepthAttachment(VkCtx);
|
||||||
|
AttachmentInfoDepth = CreateDepthAttachmentInfo(AttachmentDepth, ClearValueDepth);
|
||||||
|
RenderInfo.free();
|
||||||
|
AttachmentInfoColour.free();
|
||||||
|
AttachmentInfoColour = CreateColourAttachmentInfo(dstAttachment, ClearValueColour);
|
||||||
|
RenderInfo = CreateRenderInfo(dstAttachment,AttachmentInfoColour, AttachmentInfoDepth);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadMaterials(VulkanContext VkCtx, MaterialsCache materialsCache, TextureCache textureCache){
|
||||||
|
DescriptorAllocator descriptorAllocator = VkCtx.GetDescriptorAllocator();
|
||||||
|
Device device = VkCtx.GetDevice();
|
||||||
|
List<ImageView> imageViews = textureCache.GetTextureList().stream().map(ITexture::GetImageView).toList();
|
||||||
|
DescriptorSet descriptorSet = VkCtx.GetDescriptorAllocator().AddDescriptorSet(device,DESCRIPTOR_ID_TEXTURE,TextDescriptorSetLayout);
|
||||||
|
descriptorSet.SetImageArray(device,imageViews,TextureSampler,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static VkRenderingInfo CreateRenderInfo(Attachment ColourAttachment, VkRenderingAttachmentInfo.Buffer ColourAttachmentInfo, VkRenderingAttachmentInfo DepthAttachmentInfo){
|
||||||
|
VkRenderingInfo Result;
|
||||||
|
try(var MemStack = MemoryStack.stackPush()){
|
||||||
|
VkExtent2D Extent = VkExtent2D.calloc(MemStack);
|
||||||
|
Extent.width(ColourAttachment.GetVkImage().GetWidth());
|
||||||
|
Extent.height(ColourAttachment.GetVkImage().GetHeight());
|
||||||
|
var RenderArea = VkRect2D.calloc(MemStack).extent(Extent);
|
||||||
|
Result = VkRenderingInfo.calloc()
|
||||||
|
.sType$Default()
|
||||||
|
.renderArea(RenderArea)
|
||||||
|
.layerCount(1)
|
||||||
|
.pColorAttachments(ColourAttachmentInfo)
|
||||||
|
.pDepthAttachment(DepthAttachmentInfo);
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
public void cleanup(VulkanContext VkCtx){
|
||||||
|
|
||||||
|
VkPipelineTranslucent.CleanUp(VkCtx);
|
||||||
|
VkPipelineOpaque.CleanUp(VkCtx);
|
||||||
|
Arrays.asList(BufferViewMatrices).forEach(buffer -> buffer.cleanup(VkCtx));
|
||||||
|
RenderInfo.free();
|
||||||
|
AttachmentInfoColour.free();
|
||||||
|
// AttachmentColour.CleanUp(VkCtx);
|
||||||
|
AttachmentDepth.CleanUp(VkCtx);
|
||||||
|
AttachmentInfoDepth.free();
|
||||||
|
MemoryUtil.memFree(PushConstBuffer);
|
||||||
|
ClearValueDepth.free();
|
||||||
|
ClearValueColour.free();
|
||||||
|
TextDescriptorSetLayout.CleanUp(VkCtx);
|
||||||
|
descriptorLayoutVertexUniform.CleanUp(VkCtx);
|
||||||
|
TextureSampler.CleanUp(VkCtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void ForwardRender(EngineInstance engineInstance, VulkanContext vulkanContext, CommandBuffer commandBuffer, ModelsCache modelsCache, Attachment SrcAttachment, int CurrentFrame){
|
||||||
|
try(var MemStack = MemoryStack.stackPush()){
|
||||||
|
VkCommandBuffer CommandHandle = commandBuffer.GetVulkanCommandBuffer();
|
||||||
|
// VulkanUtils.ImageBarrier(MemStack, CommandHandle, AttachmentColour.GetVkImage().getVulkanImage(),
|
||||||
|
// VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||||
|
// VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||||
|
// VK_ACCESS_2_NONE, VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
|
|
||||||
|
long InitialTime = System.nanoTime();
|
||||||
|
vkCmdBeginRendering(CommandHandle, RenderInfo);
|
||||||
|
|
||||||
|
vkCmdBindPipeline(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkPipelineOpaque.GetVulkanPipeline());
|
||||||
|
|
||||||
|
Image ColourImage = SrcAttachment.GetVkImage();
|
||||||
|
int width = ColourImage.GetWidth();
|
||||||
|
int height = ColourImage.GetHeight();
|
||||||
|
var Viewport = VkViewport.calloc(1,MemStack)
|
||||||
|
.x(0)
|
||||||
|
.y(height)
|
||||||
|
.height(-height)
|
||||||
|
.width(width)
|
||||||
|
.minDepth(0.0F)
|
||||||
|
.maxDepth(1.0F);
|
||||||
|
vkCmdSetViewport(CommandHandle, 0, Viewport);
|
||||||
|
var Scissor = VkRect2D.calloc(1,MemStack)
|
||||||
|
.extent(it -> it.width(width).height(height))
|
||||||
|
.offset(it->it.x(0).y(0));
|
||||||
|
vkCmdSetScissor(CommandHandle, 0, Scissor);
|
||||||
|
|
||||||
|
VulkanUtils.CopyVector2ToBuffer(vulkanContext, BufferViewMatrices[CurrentFrame],engineInstance.scene().Get2DCamera().GetPosition(), 0);
|
||||||
|
VulkanUtils.CopyVector2ToBuffer(vulkanContext, BufferViewMatrices[CurrentFrame],engineInstance.scene().Get2DCamera().GetScale(), VulkanUtils.VEC2_SIZE);
|
||||||
|
DescriptorAllocator descriptorAllocator = vulkanContext.GetDescriptorAllocator();
|
||||||
|
LongBuffer DescriptorSets = MemStack.mallocLong(2)
|
||||||
|
.put(0,descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_VIEW, CurrentFrame).GetVkDescriptorSet())
|
||||||
|
.put(1,descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_TEXTURE).GetVkDescriptorSet());
|
||||||
|
vkCmdBindDescriptorSets(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkPipelineOpaque.GetVulkanPipelineLayout(),0,DescriptorSets,null);
|
||||||
|
RenderActors(engineInstance, CommandHandle, modelsCache, false, VkPipelineOpaque);
|
||||||
|
|
||||||
|
vkCmdBindPipeline(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkPipelineTranslucent.GetVulkanPipeline());
|
||||||
|
vkCmdBindDescriptorSets(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkPipelineTranslucent.GetVulkanPipelineLayout(), 0, DescriptorSets, null);
|
||||||
|
RenderActors(engineInstance, CommandHandle, modelsCache, true, VkPipelineTranslucent);
|
||||||
|
|
||||||
|
vkCmdEndRendering(CommandHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CompileSprites(VulkanContext VkCtx, ModelsCache modelsCache, TextureCache textureCache){
|
||||||
|
Sprite.SpriteRegistry.forEach((id, sprite) -> {
|
||||||
|
sprite.CompileSprite(textureCache,modelsCache,VkCtx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(EngineInstance engineInstance,VulkanContext vulkanContext, CommandBuffer commandBuffer, Attachment SrcAttachment, ModelsCache modelsCache, int CurrentFrame){
|
||||||
|
|
||||||
|
ForwardRender(engineInstance,vulkanContext,commandBuffer,modelsCache,SrcAttachment,CurrentFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Vector2f ScreenSize = new Vector2f(3440,1440);
|
||||||
|
|
||||||
|
private void RenderActors(EngineInstance instance, VkCommandBuffer CommandHandle, ModelsCache modelsCache, boolean Transparent, Pipeline pipeline){
|
||||||
|
try(var MemStack = MemoryStack.stackPush()){
|
||||||
|
LongBuffer offsets = MemStack.mallocLong(1).put(0,0L);
|
||||||
|
LongBuffer vertexBuffer = MemStack.mallocLong(1);
|
||||||
|
IScene scene = instance.scene();
|
||||||
|
List<Sprite> Sprites = scene.GetSprites();
|
||||||
|
int ActorCount = Sprites.size();
|
||||||
|
for(int i = 0; i < ActorCount; i++){
|
||||||
|
if(i < Sprites.size()) {
|
||||||
|
var Actor = Sprites.get(i);
|
||||||
|
if(Actor != null) {
|
||||||
|
VulkanModel model = modelsCache.GetModel(Actor.GetModelID());
|
||||||
|
List<VulkanMesh> VkMeshList = model.GetVkMeshList();
|
||||||
|
int MeshCount = VkMeshList.size();
|
||||||
|
for (int j = 0; j < MeshCount; j++) {
|
||||||
|
var VkMesh = VkMeshList.get(j);
|
||||||
|
SetPushConstants(CommandHandle, ScreenSize, Actor.GetScale(), Actor.GetPosition(),Actor.GetTexturePosition(),pipeline);
|
||||||
|
vertexBuffer.put(0, VkMesh.VerticesBuffer().GetBuffer());
|
||||||
|
vkCmdBindVertexBuffers(CommandHandle, 0, vertexBuffer, offsets);
|
||||||
|
vkCmdBindIndexBuffer(CommandHandle, VkMesh.IndicesBuffer().GetBuffer(), 0, VK_INDEX_TYPE_UINT32);
|
||||||
|
vkCmdDrawIndexed(CommandHandle, VkMesh.IndicesCount(), 1, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
package net.halbear.Terrain4J.EngineCore.Vulkan.SpriteRendering;
|
||||||
|
|
||||||
|
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_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 SpriteVertexBufferStructure {
|
||||||
|
public static final int TEXT_COORD_COMPONENTS = 2;
|
||||||
|
private static final int NUMBER_OF_ATTRIBUTES = 2;
|
||||||
|
private static final int POSITION_COMPONENTS = 2;
|
||||||
|
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 += TEXT_COORD_COMPONENTS * VulkanUtils.FLOAT_SIZE;
|
||||||
|
VertexInputSize = Offset;
|
||||||
|
return VertexInputSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpriteVertexBufferStructure(){
|
||||||
|
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(i)
|
||||||
|
.format(VK_FORMAT_R32G32B32_SFLOAT)
|
||||||
|
.offset(Offset);
|
||||||
|
i++;
|
||||||
|
Offset += POSITION_COMPONENTS * VulkanUtils.FLOAT_SIZE;
|
||||||
|
//texture coordinates
|
||||||
|
VertexInputAttributes.get(i)
|
||||||
|
.binding(0)
|
||||||
|
.location(i)
|
||||||
|
.format(VK_FORMAT_R32G32_SFLOAT)
|
||||||
|
.offset(Offset);
|
||||||
|
|
||||||
|
int Stride = Offset + TEXT_COORD_COMPONENTS * 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
package net.halbear.Terrain4J.EngineCore.Vulkan.SpriteRendering;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public final class TextureAlphaBounds {
|
||||||
|
|
||||||
|
private TextureAlphaBounds() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AlphaBounds find(ByteBuffer rgba, int width, int height, int alphaThreshold) {
|
||||||
|
int minX = width;
|
||||||
|
int minY = height;
|
||||||
|
int maxX = -1;
|
||||||
|
int maxY = -1;
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
int index = ((y * width) + x) * 4;
|
||||||
|
int alpha = rgba.get(index + 3) & 0xFF;
|
||||||
|
|
||||||
|
if (alpha >= alphaThreshold) {
|
||||||
|
if (x < minX) {
|
||||||
|
minX = x;
|
||||||
|
}
|
||||||
|
if (y < minY) {
|
||||||
|
minY = y;
|
||||||
|
}
|
||||||
|
if (x > maxX) {
|
||||||
|
maxX = x;
|
||||||
|
}
|
||||||
|
if (y > maxY) {
|
||||||
|
maxY = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxX < minX || maxY < minY) {
|
||||||
|
return new AlphaBounds(0, 0, width - 1, height - 1, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AlphaBounds(minX, minY, maxX, maxY, width, height);
|
||||||
|
}
|
||||||
|
public record AlphaBounds( int minX,int minY,int maxX, int maxY,int textureWidth,int textureHeight) {
|
||||||
|
public int width() {
|
||||||
|
return maxX - minX + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int height() {
|
||||||
|
return maxY - minY + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float u0() {
|
||||||
|
return (float) minX / (float) textureWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float v0() {
|
||||||
|
return (float) minY / (float) textureHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float u1() {
|
||||||
|
return (float) (maxX + 1) / (float) textureWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float v1() {
|
||||||
|
return (float) (maxY + 1) / (float) textureHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.DescriptorSet;
|
||||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.DescriptorSetLayout;
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.DescriptorSetLayout;
|
||||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.Device;
|
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.Device;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
|
import org.joml.Vector2f;
|
||||||
import org.lwjgl.system.MemoryStack;
|
import org.lwjgl.system.MemoryStack;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
import org.lwjgl.vulkan.*;
|
import org.lwjgl.vulkan.*;
|
||||||
|
|
@ -78,6 +79,13 @@ public class VulkanUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void CopyVector2ToBuffer(VulkanContext VkCtx, VulkanBuffer VkBuffer, Vector2f vector, int Offset){
|
||||||
|
long MappedMemory = VkBuffer.MapMemory(VkCtx);
|
||||||
|
ByteBuffer matrixBuffer = MemoryUtil.memByteBuffer(MappedMemory, (int)VkBuffer.GetRequestedSize());
|
||||||
|
vector.get(Offset, matrixBuffer);
|
||||||
|
VkBuffer.UnMapMemory(VkCtx);
|
||||||
|
}
|
||||||
|
|
||||||
public static void CopyMatrixToBuffer(VulkanContext VkCtx, VulkanBuffer VkBuffer, Matrix4f matrix, int Offset){
|
public static void CopyMatrixToBuffer(VulkanContext VkCtx, VulkanBuffer VkBuffer, Matrix4f matrix, int Offset){
|
||||||
long MappedMemory = VkBuffer.MapMemory(VkCtx);
|
long MappedMemory = VkBuffer.MapMemory(VkCtx);
|
||||||
ByteBuffer matrixBuffer = MemoryUtil.memByteBuffer(MappedMemory, (int)VkBuffer.GetRequestedSize());
|
ByteBuffer matrixBuffer = MemoryUtil.memByteBuffer(MappedMemory, (int)VkBuffer.GetRequestedSize());
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue