2D rendering (big feature)
This commit is contained in:
parent
6d7ea4ebc5
commit
5a05b9d65e
21 changed files with 1075 additions and 22 deletions
|
|
@ -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.PostProcessing.PostProcess;
|
||||
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.CommandPool;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.GPUSynchronisation.Fence;
|
||||
|
|
@ -47,6 +48,7 @@ public class Render {
|
|||
private final Queue.PresentQueue PresentQueue;
|
||||
private final Semaphore[] RenderCompleteSemaphores;
|
||||
private final SceneRenderer sceneRender;
|
||||
private final SpriteRenderer spriteRenderer;
|
||||
private final LightRenderer lightRenderer;
|
||||
private final PostProcess PostProcessor;
|
||||
private final SwapChainRender swapChainRender;
|
||||
|
|
@ -102,6 +104,7 @@ public class Render {
|
|||
PostProcessor = new PostProcess(RendererContext, sceneRender.GetAttachmentColour());
|
||||
lightRenderer = null;
|
||||
}
|
||||
spriteRenderer= new SpriteRenderer(engineInstance, RendererContext, PostProcessor.GetAttachment());
|
||||
GuiRender = new GuiRenderer(engineInstance, RendererContext, GraphicsQueue, PostProcessor.GetAttachment());
|
||||
swapChainRender = new SwapChainRender(RendererContext,PostProcessor.GetAttachment());
|
||||
textureCache = new TextureCache();
|
||||
|
|
@ -147,6 +150,8 @@ public class Render {
|
|||
Logger.debug("Loaded {} models", Models.size());
|
||||
|
||||
sceneRender.LoadMaterials(RendererContext,materialsCache,textureCache);
|
||||
spriteRenderer.CompileSprites(RendererContext,modelsCache, textureCache);
|
||||
spriteRenderer.LoadMaterials(RendererContext,materialsCache,textureCache);
|
||||
GuiRender.LoadTextures(RendererContext,initData.GuiTextures(),textureCache);
|
||||
}
|
||||
|
||||
|
|
@ -169,6 +174,7 @@ public class Render {
|
|||
if(lightRenderer != null)lightRenderer.cleanup(RendererContext);
|
||||
PostProcessor.CleanUp(RendererContext);
|
||||
swapChainRender.CleanUp(RendererContext);
|
||||
spriteRenderer.cleanup(RendererContext);
|
||||
GuiRender.CleanUp(RendererContext);
|
||||
modelsCache.CleanUp(RendererContext);
|
||||
materialsCache.CleanUp(RendererContext);
|
||||
|
|
@ -200,6 +206,7 @@ public class Render {
|
|||
sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame);
|
||||
lightRenderer.render(engineInstance, RendererContext, CommandBuffer, sceneRender.GetMRTAttachments(), CurrentFrame);
|
||||
PostProcessor.Render(RendererContext,CommandBuffer,lightRenderer.getAttachment());
|
||||
spriteRenderer.Render(engineInstance,RendererContext,CommandBuffer,PostProcessor.GetAttachment(),modelsCache,CurrentFrame);
|
||||
GuiRender.Render(RendererContext,CommandBuffer,CurrentFrame,PostProcessor.GetAttachment());
|
||||
|
||||
int ImageIndex;
|
||||
|
|
@ -226,6 +233,7 @@ public class Render {
|
|||
|
||||
sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame);
|
||||
PostProcessor.Render(RendererContext,CommandBuffer,sceneRender.GetAttachmentColour());
|
||||
spriteRenderer.Render(engineInstance,RendererContext,CommandBuffer,PostProcessor.GetAttachment(),modelsCache,CurrentFrame);
|
||||
GuiRender.Render(RendererContext,CommandBuffer,CurrentFrame,PostProcessor.GetAttachment());
|
||||
|
||||
int ImageIndex;
|
||||
|
|
@ -275,6 +283,7 @@ public class Render {
|
|||
} else{
|
||||
PostProcessor.Resize(RendererContext, sceneRender.GetAttachmentColour());
|
||||
}
|
||||
spriteRenderer.Resize(engineInstance,RendererContext,PostProcessor.GetAttachment());
|
||||
GuiRender.Resize(RendererContext,PostProcessor.GetAttachment());
|
||||
swapChainRender.Resize(RendererContext,PostProcessor.GetAttachment());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,10 +80,10 @@ public class EngineConfig {
|
|||
public boolean RenderCollisionMesh = true;
|
||||
public float PhysicsSpeed = 1.0f;
|
||||
|
||||
public float MusicVolume = 1.0f;
|
||||
public float SoundVolume = 1.0f;
|
||||
public float WeaponVolume = 1.0f;
|
||||
public float AmbientVolume = 1.0f;
|
||||
public float MusicVolume = 0.0f;
|
||||
public float SoundVolume = 0.0f;
|
||||
public float WeaponVolume = 0.0f;
|
||||
public float AmbientVolume = 0.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) {
|
||||
Scene scene = (Scene) engineInstance.scene();
|
||||
List<ModelData> models = new ArrayList<>();
|
||||
|
||||
MelonaData = ModelLoader.LoadModel("resources/models/cube/Cube.json");
|
||||
CubeModelID = MelonaData.ID();
|
||||
List<MaterialData> MelonaMat = ModelLoader.LoadMaterials("resources/models/cube/Cube_mat.json");
|
||||
|
|
@ -112,6 +111,13 @@ public class GameCore implements GameLogic {
|
|||
scene.MusketItem = MusketItem;
|
||||
scene.RevolverItem = RevolverItem;
|
||||
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;
|
||||
|
||||
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 DynamicTerrainMesh GetTerrainMesh();
|
||||
public void CreateTerrainMesh();
|
||||
public List<Sprite> GetSprites();
|
||||
public Camera2D Get2DCamera();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,8 +42,14 @@ public class Scene implements IScene {
|
|||
public static long LastGunFire = 0;
|
||||
private static final float MOUSE_SENSITIVITY = 0.1f;
|
||||
private static final float MOVEMENT_SPEED = 0.025f;
|
||||
|
||||
private final Map<String, Actor> Actors;
|
||||
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 Project3D Projection;
|
||||
private final Camera camera;
|
||||
|
|
@ -101,16 +107,43 @@ public class Scene implements IScene {
|
|||
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 Scene(Window window) {
|
||||
// CreateTerrainMesh();
|
||||
lightingManager = new SceneLightingManager(1000,new Vector3f(1f,1f,1f), 0.5f);
|
||||
Actors = new HashMap<>();
|
||||
Sprites = new HashMap<>();
|
||||
audioInstances = new HashMap<>();
|
||||
ActiveActors = new ArrayList<>();
|
||||
ActiveSprites = new ArrayList<>();
|
||||
CameraFrames = new HashMap<>();
|
||||
var EngConfig = EngineConfig.getInstance();
|
||||
camera2D = new Camera2D();
|
||||
camera = new Camera("DebugCamera");
|
||||
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;
|
||||
}
|
||||
|
||||
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){
|
||||
if(!IncomingPacketQueue.isEmpty()){
|
||||
Packet packet;
|
||||
|
|
@ -90,31 +102,26 @@ public class ClientConnectionThread implements Runnable{
|
|||
vector3f = Packet.DecodeAsVector3f(packet.Data);
|
||||
}
|
||||
|
||||
if(Target == null
|
||||
&& packet.PacketTypeByte != Packet.PACKET_CREATE_ACTOR
|
||||
&& 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) {
|
||||
if(Target == null &&
|
||||
(!BypassNullTargets.containsKey(packet.PacketTypeByte) || !BypassNullTargets.get(packet.PacketTypeByte))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (packet.PacketTypeByte) {
|
||||
case 0:
|
||||
case Packet.PACKET_UPDATE_LOCATION:
|
||||
Target.SetNewPosition(vector3f);
|
||||
break;
|
||||
case 1:
|
||||
case Packet.PACKET_UPDATE_ROTATION:
|
||||
quaternionfdata = Packet.DecodeAsQuaternation(packet.Data);
|
||||
Target.SetNewRotation(quaternionfdata);
|
||||
break;
|
||||
case 2:
|
||||
case Packet.PACKET_UPDATE_LINEAR_VELOCITY:
|
||||
Target.SetNewVelocity(vector3f);
|
||||
break;
|
||||
case 3:
|
||||
case Packet.PACKET_UPDATE_ANGULAR_VELOCITY:
|
||||
Target.SetNewAngularVelocity(vector3f);
|
||||
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 {
|
||||
stringdata = Packet.DecodeAsString(packet.Data);
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
case Packet.PACKET_MOVEMENT_UPDATE:
|
||||
MovementUpdate = Packet.DecodeAsMovementUpdate(packet.Data);
|
||||
|
||||
if(packet.TargetID.equals(OwnedActorID)) {
|
||||
|
|
@ -230,16 +237,16 @@ public class ClientConnectionThread implements Runnable{
|
|||
Target.SetNewVelocity(MovementUpdate.LinearVelocity);
|
||||
Target.SetNewAngularVelocity(MovementUpdate.AngularVelocity);
|
||||
break;
|
||||
case 8:
|
||||
case Packet.PACKET_POSSESS_ACTOR:
|
||||
TryPossessActor(packet.TargetID, gameCore, scene);
|
||||
break;
|
||||
case 9:
|
||||
case Packet.PACKET_DESTROY_ACTOR:
|
||||
Actor actorToDestroy = Actor.Actors.get(packet.TargetID);
|
||||
if(actorToDestroy != null) {
|
||||
scene.RemoveActor(actorToDestroy);
|
||||
}
|
||||
break;
|
||||
case 11:
|
||||
case Packet.PACKET_UPDATE_MODEL_ID:
|
||||
Logger.debug("Rebound packet received for actor [{}]", packet.TargetID);
|
||||
stringdata = Packet.DecodeAsString(packet.Data);
|
||||
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 org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.Socket;
|
||||
|
|
@ -248,6 +249,7 @@ public class ServerConnectionThread implements Runnable{
|
|||
} else {
|
||||
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);
|
||||
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.Vulkan.Rendering.Shader.DescriptorAllocator;
|
||||
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.CommandPool;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.GPUSynchronisation.TransferBuffer;
|
||||
|
|
@ -18,6 +19,7 @@ import org.lwjgl.vulkan.VkCommandBuffer;
|
|||
import org.tinylog.Logger;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
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){
|
||||
try {
|
||||
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.Structure.DeviceLayers.Device;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector2f;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
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){
|
||||
long MappedMemory = VkBuffer.MapMemory(VkCtx);
|
||||
ByteBuffer matrixBuffer = MemoryUtil.memByteBuffer(MappedMemory, (int)VkBuffer.GetRequestedSize());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue