From c6b54f88a881ed97ebccab2ab1cb5f6ec860b064 Mon Sep 17 00:00:00 2001 From: rabbet35 Date: Tue, 15 Sep 2020 21:34:47 +1000 Subject: [PATCH] Multiple rendering related changes -Made shaders load into a list to be globally accessed instead of loaded per instance, program now accesses pre loaded shaders. -Made textures load into a list to be globally accessed instad of loaded per instance, program now accesses pre loaded textures. -Made models load into a list to be globally accessed instad of loaded per instance, program now accesses pre loaded models. -commented out unecessary unbinding code for draw calls reducing driver overhead -increased accuracy and detail of debugging screen and profiler ms averages. --- Coictus/Coictus.csproj | 6 +- Coictus/Src/Game/Debugging/DebugInfo.cs | 40 ++++++---- Coictus/Src/Game/Debugging/HitboxRenderer.cs | 6 +- Coictus/Src/Game/Debugging/Profiler.cs | 30 +++---- Coictus/Src/Game/GUIS/MainGUI.cs | 9 ++- Coictus/Src/Game/GameInstance.cs | 23 +++--- Coictus/Src/Game/PlayerController.cs | 2 +- Coictus/Src/Game/ResourceUtil.cs | 12 ++- Coictus/Src/Game/TicksAndFps.cs | 50 +++++++----- .../Rendering/GUIComponents/GUICrosshair.cs | 13 +-- .../Models/EntityModels/EntityCactusModel.cs | 8 +- .../Models/EntityModels/EntityModel.cs | 22 +++-- .../EntityModels/Tank/EntityTankModel.cs | 14 ++-- .../Tank/EntityTankProjectileModel.cs | 12 ++- Coictus/Src/Rendering/Models/ModelDrawable.cs | 59 +++++++------- .../Rendering/Models/ModelDrawableDynamic.cs | 2 +- .../ModelDrawableDynamicInterpolated.cs | 6 +- .../Models/ModelDrawableInstanced.cs | 80 ++++++++++++++++++- .../ModelDrawableInstancedInterpolated.cs | 7 ++ Coictus/Src/Rendering/Models/ModelUtil.cs | 78 +++++++++++++++++- .../Models/{OBJProcessing => }/OBJLoader.cs | 34 ++++++++ .../Rendering/Models/Prefabs/CubePrefab.cs | 18 ++--- .../Models/Prefabs/DefaultDebugModel.cs | 12 +-- .../Rendering/Models/Prefabs/PlanePrefab.cs | 19 ++--- .../Rendering/Models/Prefabs/QuadPrefab.cs | 15 +--- Coictus/Src/Rendering/Renderer.cs | 26 +++++- Coictus/Src/Rendering/Shader.cs | 1 + Coictus/Src/Rendering/ShaderUtil.cs | 56 ++++++++++++- .../SubRendering/Batching/QuadBatcher.cs | 4 +- .../Rendering/SubRendering/GUI/GUIScreen.cs | 2 +- .../SubRendering/GUI/Text/TextUtil.cs | 10 +-- .../Src/Rendering/SubRendering/OffScreen.cs | 6 +- Coictus/Src/Rendering/TextureUtil.cs | 71 +++++++++++++++- Coictus/Src/Rendering/VFX/VFXBase.cs | 13 +-- Coictus/Src/Rendering/VFX/VFXExplosion.cs | 8 +- .../Src/Rendering/VFX/VFXPointParticles.cs | 11 +-- Coictus/Src/World/Collisions/CollisionUtil.cs | 1 + Coictus/Src/World/Entity/Entity.cs | 6 +- Coictus/Src/World/World.cs | 38 +++++---- 39 files changed, 580 insertions(+), 250 deletions(-) rename Coictus/Src/Rendering/Models/{OBJProcessing => }/OBJLoader.cs (83%) diff --git a/Coictus/Coictus.csproj b/Coictus/Coictus.csproj index f3f8f02..d83867f 100644 --- a/Coictus/Coictus.csproj +++ b/Coictus/Coictus.csproj @@ -76,15 +76,19 @@ + + - + + + diff --git a/Coictus/Src/Game/Debugging/DebugInfo.cs b/Coictus/Src/Game/Debugging/DebugInfo.cs index 7e49b01..198d730 100644 --- a/Coictus/Src/Game/Debugging/DebugInfo.cs +++ b/Coictus/Src/Game/Debugging/DebugInfo.cs @@ -1,6 +1,5 @@ using Coictus.GUI; using Coictus.GUI.Text; -using System; namespace Coictus.Debugging { @@ -8,7 +7,9 @@ namespace Coictus.Debugging public static class DebugInfo { public static readonly string debugInfoPanelName = "debugInfo"; - + private static float collisionsAverage; + private static float gameLoopAverage; + private static float renderAverage; /*Initialize the text panel for the debug info, can only be done if the mainGUI panel is created first*/ public static void init() { @@ -17,7 +18,7 @@ public static void init() { ("press F3 to hide debug screen.") } - ).setPanelColor(CustomColor.grey))); + ).setPanelColor(CustomColor.black))); } /*Shows and updates the debug info on the screen, Can be called every tick (Do not call every frame, too expensive)*/ @@ -26,23 +27,32 @@ public static void displayOrClearDebugInfo() if (GameSettings.debugScreen && GameInstance.get.thePlayer != null) { GUIHandler.unHideTextPanelInGUI(MainGUI.mainGUIName, debugInfoPanelName); + collisionsAverage = Profiler.getAveragesForProfile(Profiler.collisionsName); + gameLoopAverage = Profiler.getAveragesForProfile(Profiler.gameLoopName); + renderAverage = Profiler.getAveragesForProfile(Profiler.renderingName); GUIHandler.getTextPanelFormatFromGUI(MainGUI.mainGUIName, debugInfoPanelName).setLines( new string[] { ("Player Name: " + GameInstance.get.thePlayer.getName()), - ("X: " + GameInstance.get.thePlayer.getPosition().X.ToString("0.##")), - ("Y: " + GameInstance.get.thePlayer.getPosition().Y.ToString("0.##")), - ("Z: " + GameInstance.get.thePlayer.getPosition().Z.ToString("0.##")), - ("Velocity X: " + GameInstance.get.thePlayer.getVelocity().X.ToString("0.##")), - ("Velocity Y: " + GameInstance.get.thePlayer.getVelocity().Y.ToString("0.##")), - ("Velocity Z: " + GameInstance.get.thePlayer.getVelocity().Z.ToString("0.##")), - ("Head Pitch: " + GameInstance.get.thePlayer.getHeadPitch().ToString("0.##")), - ("Yaw: " + GameInstance.get.thePlayer.getYaw().ToString("0.##")), + ("X: " + GameInstance.get.thePlayer.getPosition().X.ToString("0.00")), + ("Y: " + GameInstance.get.thePlayer.getPosition().Y.ToString("0.00")), + ("Z: " + GameInstance.get.thePlayer.getPosition().Z.ToString("0.00")), + ("Velocity X: " + GameInstance.get.thePlayer.getVelocity().X.ToString("0.00")), + ("Velocity Y: " + GameInstance.get.thePlayer.getVelocity().Y.ToString("0.00 ")), + ("Velocity Z: " + GameInstance.get.thePlayer.getVelocity().Z.ToString("0.00")), + ("Head Pitch: " + GameInstance.get.thePlayer.getHeadPitch().ToString("0.00")), + ("Yaw: " + GameInstance.get.thePlayer.getYaw().ToString("0.00")), ("Profiler ms averages: "), - ("Render: " + Profiler.getAveragesForProfile(Profiler.renderingName).ToString("0.##") + " ms."), - ("Game loop: " + Profiler.getAveragesForProfile(Profiler.gameLoopName).ToString("0.##") + " ms."), - ("Collisions: " + Profiler.getAveragesForProfile(Profiler.collisionsName).ToString("0.##") + " ms."), - ("Entities: " + GameInstance.get.currentPlanet.getEntityCount()) + ("{"), + (" [Per Frame]Render: " + renderAverage.ToString("0.00 ms")), + (" [Per Tick]Game loop: " + gameLoopAverage.ToString("0.00 ms") + (gameLoopAverage / TicksAndFps.tps).ToString(" (0.00 ms per frame)")), + (" {"), + (" Collisions: " + collisionsAverage.ToString("0.00 ms") + (collisionsAverage / TicksAndFps.tps).ToString(" (0.00 ms per frame)")), + (" }Residual: " + (gameLoopAverage - collisionsAverage).ToString("0.00 ms") + ((gameLoopAverage - collisionsAverage) / TicksAndFps.tps).ToString(" (0.00 ms per frame)")), + ("}"), + ("Entities: " + GameInstance.get.currentPlanet.getEntityCount()), + ("VFX's: " + GameInstance.get.currentPlanet.getVFXCount()), + ("Draw Calls: " + Renderer.getAndResetTotalDrawCount()), }); } else diff --git a/Coictus/Src/Game/Debugging/HitboxRenderer.cs b/Coictus/Src/Game/Debugging/HitboxRenderer.cs index 896d5f9..fbee4a0 100644 --- a/Coictus/Src/Game/Debugging/HitboxRenderer.cs +++ b/Coictus/Src/Game/Debugging/HitboxRenderer.cs @@ -10,7 +10,7 @@ namespace Coictus.Debugging /*This class handles the rendering of hitboxes for debugging purposes.*/ public static class HitboxRenderer { - private static string linesShader = ResourceUtil.getShaderFileDir("Color3D.shader"); + public static readonly string linesShaderName = "Color3D.shader"; public static readonly int maxAABBRenderCount = 512; @@ -27,9 +27,9 @@ public static void init() /*Builds the prefab model for an AABB, basically a cube made of lines*/ private static void buildAABBModel() { - aabbDynamicModel = new ModelDrawableDynamic(linesShader, "none", LineBatcher.getIndicesForLineQuadCount(maxAABBRenderCount * 6), maxAABBRenderCount * 48 /*aabb models have 48 vertices*/);//initializing dynamic model for drawing aabb + aabbDynamicModel = new ModelDrawableDynamic(linesShaderName, "none", LineBatcher.getIndicesForLineQuadCount(maxAABBRenderCount * 6), maxAABBRenderCount * 48 /*aabb models have 48 vertices*/);//initializing dynamic model for drawing aabb - aabbModelPrefab = CubePrefab.getNewModel(); + aabbModelPrefab = CubePrefab.copyModel(); } /*called on tick. Adds all of the provided colliders to a list of hitboxes to be dynamically batched and drawn.*/ diff --git a/Coictus/Src/Game/Debugging/Profiler.cs b/Coictus/Src/Game/Debugging/Profiler.cs index 9789462..f012aa4 100644 --- a/Coictus/Src/Game/Debugging/Profiler.cs +++ b/Coictus/Src/Game/Debugging/Profiler.cs @@ -48,10 +48,11 @@ public static float getAveragesForProfile(string profileName) /*private class for profiles.*/ private class Profile { + private int[] recordedTimes = new int[100]; private long startTime; private string name; - private int totalUpdates; - private long combinedTimePassed; + private int updateIndex; + private int combinedTimePassed; public bool hasEnded = false; public Profile(string name) @@ -61,38 +62,31 @@ public Profile(string name) public Profile begin() { - startTime = TicksAndFps.getMiliseconds(); + startTime = TicksAndFps.getCurrentTime(); hasEnded = false; return this; } public void end() { - combinedTimePassed += (TicksAndFps.getMiliseconds() - startTime); - totalUpdates++; + int time = (int)(TicksAndFps.getCurrentTime() - startTime); + combinedTimePassed -= recordedTimes[updateIndex]; + combinedTimePassed += time; + recordedTimes[updateIndex++] = time; + updateIndex %= 100;//keep update index within 100 hasEnded = true; } public float getAverageCompletionTime() { - if(totalUpdates < 1) - { - return (float)combinedTimePassed; - } - float result = (float)combinedTimePassed / (float)totalUpdates; - - if(totalUpdates >= 100)//resetting after 100 updates to give a more accurate result - { - totalUpdates = 0; - combinedTimePassed = 0; - } - return result; + return (float)combinedTimePassed / 100F; } + private void printInfo() { Console.BackgroundColor = ConsoleColor.Cyan; Console.ForegroundColor = ConsoleColor.Black; - Console.WriteLine("Profile: \"" + name + "\" measured " + (TicksAndFps.getMiliseconds() - startTime) + " miliseconds from start to finish."); + Console.WriteLine("Profile: \"" + name + "\" measured " + (TicksAndFps.getCurrentTime() - startTime) + " miliseconds from start to finish."); Console.BackgroundColor = ConsoleColor.White; Console.ForegroundColor = ConsoleColor.White; } diff --git a/Coictus/Src/Game/GUIS/MainGUI.cs b/Coictus/Src/Game/GUIS/MainGUI.cs index 2a74eb8..4d367b6 100644 --- a/Coictus/Src/Game/GUIS/MainGUI.cs +++ b/Coictus/Src/Game/GUIS/MainGUI.cs @@ -48,6 +48,7 @@ public static void init() /*Called every tick*/ public static void onTick() { + displayFps(); /*Temporary, for arcade popups.*/ if (showingDirectHitPopup) { @@ -127,17 +128,17 @@ public static void onAirShot() } /*Called every second by the TicksAndFps class to display new fps if setting is on*/ - public static void displayFps(int fps) + public static void displayFps() { if (GameSettings.displayFps) { GUIHandler.unHideTextPanelInGUI(mainGUIName, fpsPanelName); - string fpsstring = fps.ToString(); - if (fps < 75) + string fpsstring = TicksAndFps.fps.ToString(); + if (TicksAndFps.fps < 75) { GUIHandler.getTextPanelFormatFromGUI(mainGUIName, fpsPanelName).setLine(fpsstring).setPanelColor(CustomColor.red); } - else if (fps < 120) + else if (TicksAndFps.fps < 120) { GUIHandler.getTextPanelFormatFromGUI(mainGUIName, fpsPanelName).setLine(fpsstring).setPanelColor(CustomColor.yellow); } diff --git a/Coictus/Src/Game/GameInstance.cs b/Coictus/Src/Game/GameInstance.cs index 5f56b77..2f02d60 100644 --- a/Coictus/Src/Game/GameInstance.cs +++ b/Coictus/Src/Game/GameInstance.cs @@ -4,6 +4,7 @@ using OpenTK; using OpenTK.Graphics; using System; +using System.ComponentModel; using System.Drawing; namespace Coictus @@ -39,7 +40,6 @@ public GameInstance(int screenWidth, int screenHeight, int initialWindowWidth, i protected override void OnLoad(EventArgs e) { - base.OnLoad(e); GameInstance.instance = this; GameInstance.privateRand = new Random(); GameInstance.mouseCenterX = this.X + this.Width / 2; @@ -48,7 +48,7 @@ protected override void OnLoad(EventArgs e) TextUtil.loadAllFoundTextFiles(); setDPIScale(); Renderer.init(); - TicksAndFps.init(30.0F); + TicksAndFps.init(30); MainGUI.init(); DebugInfo.init(); HitboxRenderer.init(); @@ -65,20 +65,14 @@ protected override void OnLoad(EventArgs e) //center mouse in preperation for first person Input.centerMouse(); Input.toggleHideMouse(); - } - - - /*overriding OpenTk game update function, called every frame.*/ - protected override void OnUpdateFrame(FrameEventArgs args) - { - base.OnUpdateFrame(args); - + base.OnLoad(e); } /*overriding OpenTk render update function, called every frame.*/ protected override void OnRenderFrame(FrameEventArgs args) { base.OnRenderFrame(args); + for (int i = 0; i < TicksAndFps.getTicksElapsed(); i++)//for each tick that has elapsed since the start of last update, run the games logic enough times to catch up. { onTick(); @@ -119,17 +113,19 @@ private void onTick() Profiler.beginEndProfile(Profiler.gameLoopName); } - //TODO: Create event system for handling these events + /*Called when player lands direct hit on a cactus, TEMPORARY!*/ public static void onDirectHit() { MainGUI.onDirectHit(); } + /*Called when player lands air shot on a cactus, TEMPORARY!*/ public static void onAirShot() { MainGUI.onAirShot(); } + public static void pauseGame() { Input.centerMouse(); // center the mouse cursor when closing or opening menu @@ -137,6 +133,11 @@ public static void pauseGame() GameInstance.get.thePlayer.togglePause(); } + protected override void OnClosing(CancelEventArgs e) + { + Renderer.onClosing(); + base.OnClosing(e); + } private void setDPIScale() { Graphics g = Graphics.FromHwnd(this.WindowInfo.Handle); diff --git a/Coictus/Src/Game/PlayerController.cs b/Coictus/Src/Game/PlayerController.cs index 91a51b4..1cb446f 100644 --- a/Coictus/Src/Game/PlayerController.cs +++ b/Coictus/Src/Game/PlayerController.cs @@ -5,7 +5,7 @@ namespace Coictus /*This class is responsable for detecting input which changes the players state. Such as movement, inventory use, attacking etc*/ - public static class PlayerController//TODO: impliment custom bindings in gamesettings + public static class PlayerController { private static KeyboardState currentKeyboardState; private static MouseState currentMouseState; diff --git a/Coictus/Src/Game/ResourceUtil.cs b/Coictus/Src/Game/ResourceUtil.cs index 528135c..5caf436 100644 --- a/Coictus/Src/Game/ResourceUtil.cs +++ b/Coictus/Src/Game/ResourceUtil.cs @@ -1,25 +1,23 @@ -using System; - -namespace Coictus +namespace Coictus { /*A class containing functions to gelp find resources. This class will make it much easier to change resource directories.*/ public static class ResourceUtil { - public static string getTextureFileDir(string fileName) + public static string getTextureFileDir(string fileName = "") { return @"..\..\Res\Texture\" + fileName; } - public static string getFontFileDir(string fileName) + public static string getFontFileDir(string fileName = "") { return @"..\..\Res\Font\" + fileName; } - public static string getShaderFileDir(string shaderName) + public static string getShaderFileDir(string shaderName = "") { return @"..\..\Res\Shaders\" + shaderName; } - public static string getOBJFileDir(string modelName) + public static string getOBJFileDir(string modelName = "") { return @"..\..\Res\OBJ\" + modelName; } diff --git a/Coictus/Src/Game/TicksAndFps.cs b/Coictus/Src/Game/TicksAndFps.cs index 85df806..a2bcdc1 100644 --- a/Coictus/Src/Game/TicksAndFps.cs +++ b/Coictus/Src/Game/TicksAndFps.cs @@ -9,20 +9,20 @@ public static class TicksAndFps private static Stopwatch stopwatch = new Stopwatch(); private static long currentTime = 0; private static long lastTime = 0; - private static double timer = 0; - private static int fps = 1; - private static int frames; private static double deltaTime = 0.005D; - private static double ticksPerSecond = 0; + private static int ticksPerSecond; private static int ticksElapsed = 0; private static double timePerTick; private static double percentToNextTick; //a decimal value between 0 and 1 which can be used as a percentage of progress towards next tick, usefull for interpolation. private static bool paused = false; //true when game is paused - public static void init(float tps) + private static float[] recordedFrameTimes = new float[100];//used for calculating average FPS per frame + private static float combinedFrameTimes = 0; + private static int frameUpdateIndex = 0; + public static void init(int tps) { ticksPerSecond = tps; - timePerTick = 1 / ticksPerSecond; + timePerTick = 1 / (double)ticksPerSecond; stopwatch.Start(); lastTime = stopwatch.ElapsedMilliseconds; } @@ -34,15 +34,12 @@ public static void update() lastTime = currentTime; currentTime = stopwatch.ElapsedMilliseconds; deltaTime = (currentTime - lastTime) / 1000.0F; - timer += deltaTime; - if (timer >= 1) - { - fps = frames; - frames = 0; - timer -= 1; - MainGUI.displayFps(fps); - } - frames++; + + combinedFrameTimes -= recordedFrameTimes[frameUpdateIndex]; + combinedFrameTimes += (float)deltaTime; + recordedFrameTimes[frameUpdateIndex++] = (float)deltaTime; + frameUpdateIndex %= 100; + if (paused) { @@ -68,12 +65,12 @@ public static void update() /*ticksElapsed is equal to the number of times the passed time has reached the full duration of one tick (at 30 ticks per second, thats 0.0333333)*/ ticksElapsed = (int)percentToNextTick; - /*limit ticks elapsed to Half a second's worth, so the game does not speed out of control in some laggy circumstances + /*limit ticks elapsed to a second's worth, so the game does not speed out of control in some laggy circumstances In other words, the game will only "catch up" by half a second at a time. Any hangs more than half a second will not be corrected for.*/ if (ticksElapsed > ticksPerSecond) { - ticksElapsed = (int)ticksPerSecond; + ticksElapsed = ticksPerSecond; } } } @@ -106,13 +103,22 @@ public static float getPercentageToNextTick() return (float)percentToNextTick; } - public static long getMiliseconds() + public static long getCurrentTime() { return stopwatch.ElapsedMilliseconds; } - public static int getFps() - { - return fps; - } + + /*ticks per second*/ + public static int tps { get => ticksPerSecond; } + + /*seconds per tick*/ + public static float spt { get => 1F / (float)ticksPerSecond; } + + /*frames per second*/ + public static int fps { get => (int)( 1F / (combinedFrameTimes / 100F)); } + + /*seconds per frame*/ + public static float spf { get => 1F / (float)fps; } + } } diff --git a/Coictus/Src/Rendering/GUIComponents/GUICrosshair.cs b/Coictus/Src/Rendering/GUIComponents/GUICrosshair.cs index bc85578..e411a4e 100644 --- a/Coictus/Src/Rendering/GUIComponents/GUICrosshair.cs +++ b/Coictus/Src/Rendering/GUIComponents/GUICrosshair.cs @@ -1,7 +1,6 @@ using Coictus.Models; using Coictus.SubRendering.GUI; using OpenTK; -using System; namespace Coictus.GUI { public enum CrosshairType//enum for all different types of crosshairs @@ -13,7 +12,7 @@ public enum CrosshairType//enum for all different types of crosshairs crosshair texture will be gotten.*/ public class GUICrosshair : GUIScreenComponent { - private static string shaderDir = ResourceUtil.getShaderFileDir(@"GUI\GuiStencilShader.shader"); + private Shader crosshairShader; private Texture crosshairTexture; private float texutrePixelWidth = 0F; private float texutrePixelHeight = 0F; @@ -21,15 +20,17 @@ public class GUICrosshair : GUIScreenComponent public GUICrosshair(CustomColor color,float crosshairSize = 2.0F, CrosshairType crosshairType = CrosshairType.normal) : base(new Vector2(0.5F, 0.5F)) { + ShaderUtil.tryGetShader("GUI\\GuiStencilShader.shader", out crosshairShader); crosshairColor = color; setCrosshairTextureAndSize(crosshairType, crosshairSize); - setModel(new ModelDrawable(shaderDir, crosshairTexture, QuadPrefab.getNewModel().setColor(crosshairColor).vertices, QuadPrefab.quadIndices)); + setModel(new ModelDrawable(crosshairShader, crosshairTexture, QuadPrefab.getNewModel().setColor(crosshairColor).vertices, QuadPrefab.quadIndices)); } public GUICrosshair(float crosshairSize = 2.0F, CrosshairType crosshairType = CrosshairType.normal) : base(new Vector2(0.5F, 0.5F)) { + ShaderUtil.tryGetShader("GUI\\GuiStencilShader.shader", out crosshairShader); setCrosshairTextureAndSize(crosshairType, crosshairSize); - setModel(new ModelDrawable(shaderDir, crosshairTexture, QuadPrefab.getNewModel().setColor(crosshairColor).vertices, QuadPrefab.quadIndices)); + setModel(new ModelDrawable(crosshairShader, crosshairTexture, QuadPrefab.getNewModel().setColor(crosshairColor).vertices, QuadPrefab.quadIndices)); } protected virtual void setCrosshairTextureAndSize(CrosshairType type, float crosshairSize) @@ -37,13 +38,13 @@ protected virtual void setCrosshairTextureAndSize(CrosshairType type, float cros switch(type) { case CrosshairType.normal: - crosshairTexture = new Texture(ResourceUtil.getTextureFileDir(@"GUI\Crosshairs\CrosshairNormal.png"), false); + TextureUtil.tryGetTexture("GUI\\Crosshairs\\CrosshairNormal.png", out crosshairTexture); texutrePixelWidth = crosshairTexture.getWidth() * crosshairSize; texutrePixelHeight = crosshairTexture.getHeight() * crosshairSize; break; default: - crosshairTexture = new Texture(); + TextureUtil.tryGetTexture("debug", out crosshairTexture); texutrePixelWidth = crosshairTexture.getWidth() * crosshairSize; texutrePixelHeight = crosshairTexture.getHeight() * crosshairSize; break; diff --git a/Coictus/Src/Rendering/Models/EntityModels/EntityCactusModel.cs b/Coictus/Src/Rendering/Models/EntityModels/EntityCactusModel.cs index 8e07350..936f1a0 100644 --- a/Coictus/Src/Rendering/Models/EntityModels/EntityCactusModel.cs +++ b/Coictus/Src/Rendering/Models/EntityModels/EntityCactusModel.cs @@ -2,11 +2,11 @@ { public class EntityCactusModel : EntityModel { - private static string shaderDir = ResourceUtil.getShaderFileDir(@"VFX\PointParticleFog.shader"); - private static string textureDir = ResourceUtil.getTextureFileDir("EntityCactus.png"); - private static string modelPath = ResourceUtil.getOBJFileDir("Cactus.obj"); + private static string shaderName = "ColorTextureFog3D.shader"; + private static string textureName = "EntityCactus.png"; + private static string modelName = "Cactus.obj"; - public EntityCactusModel(Entity parent) : base(parent, shaderDir, textureDir, modelPath) + public EntityCactusModel(Entity parent) : base(parent, shaderName, textureName, modelName) { } diff --git a/Coictus/Src/Rendering/Models/EntityModels/EntityModel.cs b/Coictus/Src/Rendering/Models/EntityModels/EntityModel.cs index b9d19d2..45c5ed6 100644 --- a/Coictus/Src/Rendering/Models/EntityModels/EntityModel.cs +++ b/Coictus/Src/Rendering/Models/EntityModels/EntityModel.cs @@ -1,5 +1,4 @@ using OpenTK; -using System; namespace Coictus.Models { @@ -20,6 +19,7 @@ protected EntityModel() modelMatrix = Matrix4.Identity; prevTickModelMatrix = Matrix4.Identity; } + public EntityModel(Entity parent) { this.parent = parent; @@ -29,10 +29,21 @@ public EntityModel(Entity parent) onTick();//updating model twice to set first frame render position to the entity position. onTick(); } - public EntityModel(Entity parent,string shaderDir, string textureDir, string modelPath) + public EntityModel(Entity parent, string shaderName, string textureName, string modelName) { this.parent = parent; - theModel = OBJLoader.loadModelDrawableFromObjFile(shaderDir, textureDir, modelPath);//TODO: Inefficient. This will mean we have to load model data each time a model for an entity etc is spawned!, maybe make a list of pre loaded models? + + if(ModelUtil.tryGetModel(modelName, out theModel)) + { + Shader shader; + ShaderUtil.tryGetShader(shaderName, out shader); + theModel.setShader(shader); + + Texture texture; + TextureUtil.tryGetTexture(textureName, out texture); + theModel.setTexture(texture); + } + modelMatrix = Matrix4.Identity; prevTickModelMatrix = Matrix4.Identity; onTick();//updating model twice to set first frame render position to the entity position. @@ -76,11 +87,6 @@ public virtual void draw(Matrix4 viewMatrix, Matrix4 projectionMatrix, Vector3 f public virtual void delete() { - if (theModel != null) - { - theModel.delete(); - theModel = null; - } } public virtual bool exists() diff --git a/Coictus/Src/Rendering/Models/EntityModels/Tank/EntityTankModel.cs b/Coictus/Src/Rendering/Models/EntityModels/Tank/EntityTankModel.cs index 3bf1455..075990b 100644 --- a/Coictus/Src/Rendering/Models/EntityModels/Tank/EntityTankModel.cs +++ b/Coictus/Src/Rendering/Models/EntityModels/Tank/EntityTankModel.cs @@ -1,5 +1,4 @@ using OpenTK; -using System; namespace Coictus.Models { @@ -15,16 +14,19 @@ public class EntityTankModel : EntityModel private Matrix4 tankWheelsModelMatrix = Matrix4.Identity; private Matrix4 tankBodyModelMatrix = Matrix4.Identity; private Matrix4 tankBarrelModelMatrix = Matrix4.Identity; - private string shaderDir = ResourceUtil.getShaderFileDir("ColorTextureFog3D.shader"); - private string textureDir = ResourceUtil.getTextureFileDir("Camo.png"); + private string shaderName = "ColorTextureFog3D.shader"; + private string textureName = "Camo.png"; + private string wheelModelName = @"Tank\TankWheels.obj"; + private string bodyModelName = @"Tank\TankBody.obj"; + private string barrelModelName = @"Tank\TankBarrel.obj"; public EntityTankModel(EntityTank parent)//dont want to call the base constructor for this model { this.parent = parent; - tankWheelModel = OBJLoader.loadModelDrawableFromObjFile(shaderDir, textureDir, ResourceUtil.getOBJFileDir(@"Tank\TankWheels.obj")); - tankBodyModel = OBJLoader.loadModelDrawableFromObjFile(shaderDir, textureDir, ResourceUtil.getOBJFileDir(@"Tank\TankBody.obj")); - tankBarrelModel = OBJLoader.loadModelDrawableFromObjFile(shaderDir, textureDir, ResourceUtil.getOBJFileDir(@"Tank\TankBarrel.obj")); + tankWheelModel = ModelUtil.createModelDrawable(shaderName, textureName, wheelModelName); + tankBodyModel = ModelUtil.createModelDrawable(shaderName, textureName, bodyModelName); + tankBarrelModel = ModelUtil.createModelDrawable(shaderName, textureName, barrelModelName); onTick(); onTick(); } diff --git a/Coictus/Src/Rendering/Models/EntityModels/Tank/EntityTankProjectileModel.cs b/Coictus/Src/Rendering/Models/EntityModels/Tank/EntityTankProjectileModel.cs index 58fa4c1..40982cc 100644 --- a/Coictus/Src/Rendering/Models/EntityModels/Tank/EntityTankProjectileModel.cs +++ b/Coictus/Src/Rendering/Models/EntityModels/Tank/EntityTankProjectileModel.cs @@ -1,14 +1,12 @@ -using System; - -namespace Coictus.Models +namespace Coictus.Models { public class EntityTankProjectileModel : EntityModel { - private static string shaderDir = ResourceUtil.getShaderFileDir("ColorTextureFog3D.shader"); - private static string textureDir = ResourceUtil.getTextureFileDir("Camo.png"); - private static string modelPath = ResourceUtil.getOBJFileDir(@"Tank\TankProjectile.obj"); + private static string shaderName = "ColorTextureFog3D.shader"; + private static string textureName = "Camo.png"; + private static string modelName = @"Tank\TankProjectile.obj"; - public EntityTankProjectileModel(Entity parent) : base (parent, shaderDir, textureDir, modelPath) + public EntityTankProjectileModel(Entity parent) : base (parent, shaderName, textureName, modelName) { } } diff --git a/Coictus/Src/Rendering/Models/ModelDrawable.cs b/Coictus/Src/Rendering/Models/ModelDrawable.cs index 1c7912b..814321b 100644 --- a/Coictus/Src/Rendering/Models/ModelDrawable.cs +++ b/Coictus/Src/Rendering/Models/ModelDrawable.cs @@ -13,8 +13,10 @@ public enum ModelDrawType { trangles, points, - singlePoint, - lines + singlePoint,//for drawing single points, should use vector3 as transform single point shader + lines, + billboardSphere,//for drawing a mesh that looks at camera in any direction. i.e, sprites. Should use a shader that removes rotational info from viewmatrix. Can use any mesh and matrix transforms. + billboardCylindrical//for drawing a mesh that looks at camera in any cylindrical direction. i.e, sprites. But not vertically. should use a shader that removes horizontal rotations from view matrix. Can use any mesh and matrix transforms. }; /*Base class for models that can be drawn individually with additional draw calls and have @@ -30,25 +32,20 @@ public class ModelDrawable : Model protected int VAO; protected Texture texture; protected Shader shader; - protected string shaderDir; - protected string textureDir; private bool drawErrorPrinted = false; - - /*takes in directory for the shader and texture for this model, indices can be null if they wont be used*/ - public ModelDrawable(string shaderFile, string textureFile, Vertex[] vertices, uint[] indices = null, bool filtering = false) : base(vertices) + /*takes in the shader and texture for this model, indices can be null if they wont be used*/ + public ModelDrawable(string shader, string texture, Vertex[] vertices, uint[] indices = null) : base(vertices) { - shaderDir = shaderFile; - textureDir = textureFile; + ShaderUtil.tryGetShader(shader, out this.shader); + TextureUtil.tryGetTexture(texture, out this.texture); this.indices = indices; - texture = new Texture(textureFile, filtering); - shader = new Shader(shaderFile); } - public ModelDrawable(string shaderFile, Texture tex, Vertex[] vertices, uint[] indices) : base(vertices) + public ModelDrawable(Shader shader, Texture texture, Vertex[] vertices, uint[] indices = null) : base(vertices) { + this.shader = shader; + this.texture = texture; this.indices = indices; - texture = tex; - shader = new Shader(shaderFile); } public virtual void setIndices(uint[] newind) @@ -56,21 +53,13 @@ public virtual void setIndices(uint[] newind) indices = newind; } - public virtual void setNewTexture(Texture tex) + public virtual void setTexture(Texture tex) { - if(this.texture != null) - { - this.texture.Dispose(); - } this.texture = tex; } - public virtual void setNewShader(Shader shad) + public virtual void setShader(Shader shad) { - if (this.shader != null) - { - this.shader.Dispose(); - } this.shader = shad; } @@ -129,6 +118,7 @@ public virtual void bind(bool useTexture = true, bool useShader = true) shader.setUniformVec3F("skyHorizon", skyHorizonColor); GL.DrawElements(PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedInt, 0); unBind(); + Renderer.totalDraws++; } public virtual void draw(Matrix4 viewMatrix, Matrix4 projectionMatrix, Vector3 fogColour) { @@ -139,6 +129,7 @@ public virtual void draw(Matrix4 viewMatrix, Matrix4 projectionMatrix, Vector3 f shader.setUniformVec3F("fogColour", fogColour); GL.DrawElements(PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedInt, 0); unBind(); + Renderer.totalDraws++; } public virtual void draw(Matrix4 viewMatrix, Matrix4 projectionMatrix, Matrix4 modelMatrix, Vector3 fogColor) { @@ -150,6 +141,7 @@ public virtual void draw(Matrix4 viewMatrix, Matrix4 projectionMatrix, Matrix4 m GL.DrawElements(PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedInt, 0); unBind(); + Renderer.totalDraws++; } public virtual void draw(Matrix4 viewMatrix, Matrix4 projectionMatrix, Matrix4 modelMatrix, PrimitiveType primitive) { @@ -160,6 +152,7 @@ public virtual void draw(Matrix4 viewMatrix, Matrix4 projectionMatrix, Matrix4 m GL.DrawElements(primitive, indices.Length, DrawElementsType.UnsignedInt, 0); unBind(); + Renderer.totalDraws++; } public virtual void draw(Matrix4 viewMatrix, Matrix4 projectionMatrix, Matrix4 modelMatrix) { @@ -170,6 +163,7 @@ public virtual void draw(Matrix4 viewMatrix, Matrix4 projectionMatrix, Matrix4 m GL.DrawElements(PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedInt, 0); unBind(); + Renderer.totalDraws++; } public virtual void draw(Matrix4 projectionMatrix, Matrix4 modelMatrix) @@ -179,6 +173,7 @@ public virtual void draw(Matrix4 projectionMatrix, Matrix4 modelMatrix) shader.setUniformMat4F("modelMatrix", modelMatrix); GL.DrawElements(PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedInt, 0); unBind(); + Renderer.totalDraws++; } public virtual void draw(Matrix4 modelMatrix) { @@ -186,6 +181,7 @@ public virtual void draw(Matrix4 modelMatrix) shader.setUniformMat4F("modelMatrix", modelMatrix); GL.DrawElements(PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedInt, 0); unBind(); + Renderer.totalDraws++; } public virtual void draw(int textureID) @@ -194,18 +190,21 @@ public virtual void draw(int textureID) shader.setUniform1I("renderedTexture", textureID); GL.DrawElements(PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedInt, 0); unBind(); + Renderer.totalDraws++; } public virtual void draw(bool useTex = true) { bind(useTex); GL.DrawElements(PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedInt, 0); unBind(); + Renderer.totalDraws++; } public virtual void draw(PrimitiveType primType, bool useTex = true) { bind(useTex); GL.DrawElements(primType, indices.Length, DrawElementsType.UnsignedInt, 0); unBind(); + Renderer.totalDraws++; } public virtual void drawPoints(Matrix4 viewMatrix, Matrix4 projectionMatrix, Matrix4 modelMatrix, Vector3 fogColor, float pointRadius, bool ambientOcclusion) @@ -226,6 +225,7 @@ public virtual void drawPoints(Matrix4 viewMatrix, Matrix4 projectionMatrix, Mat //shader.setUniform1I("renderPass", pass); GL.DrawArrays(PrimitiveType.Points, 0, vertices.Length); unBind(); + Renderer.totalDraws++; } #endregion drawMethods @@ -233,11 +233,11 @@ public virtual void drawPoints(Matrix4 viewMatrix, Matrix4 projectionMatrix, Mat /*Unbinds this model so the renderer can render different things.*/ public virtual void unBind() { - GL.BindBuffer(BufferTarget.ArrayBuffer, 0); + /* GL.BindBuffer(BufferTarget.ArrayBuffer, 0); GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0); GL.BindTexture(TextureTarget.Texture2D, 0); GL.UseProgram(0); - GL.BindVertexArray(0); + GL.BindVertexArray(0);*/ } /*Binds the indicie buffer to the VAO*/ @@ -300,13 +300,14 @@ public ModelDrawable copyModelDrawable() uint[] indicesCopy = new uint[indices.Length]; Array.Copy(vertices, verticesCopy, vertices.Length); Array.Copy(indices, indicesCopy, indices.Length); - return new ModelDrawable(shaderDir, textureDir, verticesCopy, indicesCopy); + return new ModelDrawable(shader, texture, verticesCopy, indicesCopy); } Vertex[] verticesCopy2 = new Vertex[vertices.Length]; Array.Copy(vertices, verticesCopy2, vertices.Length); - return new ModelDrawable(shaderDir, textureDir, verticesCopy2, null); + return new ModelDrawable(shader, texture, verticesCopy2, null); } + /*Called when this model is no longer needed and will be replaced*/ public virtual void delete() { @@ -315,8 +316,6 @@ public virtual void delete() { GL.DeleteBuffer(vbo); } - shader.Dispose(); - texture.Dispose(); } } } diff --git a/Coictus/Src/Rendering/Models/ModelDrawableDynamic.cs b/Coictus/Src/Rendering/Models/ModelDrawableDynamic.cs index 8a61ef0..0c2a581 100644 --- a/Coictus/Src/Rendering/Models/ModelDrawableDynamic.cs +++ b/Coictus/Src/Rendering/Models/ModelDrawableDynamic.cs @@ -8,7 +8,7 @@ public class ModelDrawableDynamic : ModelDrawable { private int maxVertexCount; /*ModelDrawableDynamics must be initialized at construction because they can not have data submittied to them unless the VBO's are made*/ - public ModelDrawableDynamic(string shaderFile, string textureFile, uint[] indices, int maxVertexCount = 4000, bool textureFiltering = false) : base( shaderFile, textureFile, null, indices, textureFiltering) + public ModelDrawableDynamic(string shaderFile, string textureFile, uint[] indices, int maxVertexCount = 4000) : base( shaderFile, textureFile, null, indices) { this.maxVertexCount = maxVertexCount; init(); diff --git a/Coictus/Src/Rendering/Models/ModelDrawableDynamicInterpolated.cs b/Coictus/Src/Rendering/Models/ModelDrawableDynamicInterpolated.cs index 8841412..d434bcb 100644 --- a/Coictus/Src/Rendering/Models/ModelDrawableDynamicInterpolated.cs +++ b/Coictus/Src/Rendering/Models/ModelDrawableDynamicInterpolated.cs @@ -11,12 +11,12 @@ public class ModelDrawableDynamicInterpolated : ModelDrawableDynamic /*this array of shader directories can be indexed with the ModelDrawType enum. each shader in this array must be a shader specifically made for interpolating a dynamic model. */ - private static string[] shaders = new string[] { + /* private static string[] shaders = new string[] { ResourceUtil.getShaderFileDir(""),//ModelDrawType.triangles ResourceUtil.getShaderFileDir(""),//ModelDrawType.points ResourceUtil.getShaderFileDir(""),//ModelDrawType.singlePoint ResourceUtil.getShaderFileDir("")//ModelDrawType.lines - }; + };*/ private ModelDrawType drawType; private uint maxInstanceCount; @@ -30,7 +30,7 @@ public class ModelDrawableDynamicInterpolated : ModelDrawableDynamic parameter maxInstanceCount is the maximum number of models to be combined into this dynamic model. Determines the max number of model matrices to be sent to GPU and interpolated.*/ - public ModelDrawableDynamicInterpolated(uint maxInstanceCount, ModelDrawType drawType, string textureFile, uint[] indices, int maxVertexCount = 4000) : base(shaders[(int)drawType], textureFile, indices, maxVertexCount) + public ModelDrawableDynamicInterpolated(uint maxInstanceCount, ModelDrawType drawType, string textureFile, uint[] indices, int maxVertexCount = 4000) : base(null, textureFile, indices, maxVertexCount) { this.maxInstanceCount = maxInstanceCount; this.drawType = drawType; diff --git a/Coictus/Src/Rendering/Models/ModelDrawableInstanced.cs b/Coictus/Src/Rendering/Models/ModelDrawableInstanced.cs index 609e02a..6b80558 100644 --- a/Coictus/Src/Rendering/Models/ModelDrawableInstanced.cs +++ b/Coictus/Src/Rendering/Models/ModelDrawableInstanced.cs @@ -1,9 +1,87 @@ -namespace Coictus.Models +using OpenTK; +using System.Collections.Generic; + +namespace Coictus.Models { /*This class is for rendering the same model data many times with different transforms, colors and textures. It is more efficient to use this instead of ModelDrawableDynamic if its just multiple instances of one mesh.*/ public class ModelDrawableInstanced { + /*this array of shader directories can be indexed with the ModelDrawType enum. + each shader in this array must be a shader specifically made for interpolating a dynamic + model. */ + /* private static string[] shaders = new string[] { + ResourceUtil.getShaderFileDir(""),//ModelDrawType.triangles + ResourceUtil.getShaderFileDir(""),//ModelDrawType.points + ResourceUtil.getShaderFileDir(""),//ModelDrawType.singlePoint + ResourceUtil.getShaderFileDir(""),//ModelDrawType.lines + ResourceUtil.getShaderFileDir(""),//ModelDrawType.billboardSpherical + ResourceUtil.getShaderFileDir("")//ModelDrawType.billboardCylindrical + };*/ + + protected Model instance; + protected uint[] indices; + protected ModelDrawType drawType; + protected List transforms = null; + protected List vecTransforms = null;//for when this model is for instancing points/sprites + + /*the provided model instance will be re-drawn at each transform*/ + public ModelDrawableInstanced(Model instance, uint[] indices, ModelDrawType drawType) + { + this.instance = instance; + this.indices = indices; + this.drawType = drawType; + if(drawType == ModelDrawType.singlePoint) + { + vecTransforms = new List(); + } + else + { + transforms = new List(); + } + } + + /*the provided model instance will be re-drawn at each transform*/ + public ModelDrawableInstanced(ModelDrawable instance, ModelDrawType drawType) + { + this.instance = instance; + this.indices = instance.indices; + this.drawType = drawType; + if (drawType == ModelDrawType.singlePoint) + { + vecTransforms = new List(); + } + else + { + transforms = new List(); + } + } + + /*when called adds a transform to the list and when this model is drawn, an + instance will be drawn with the provided transform.*/ + public void addRenderAt(Matrix4 transform) + { + if (drawType == ModelDrawType.singlePoint) + { + Application.error("ModelDrawableInstanced was requested to add a matrix4 as a transform forsingle point drawing!"); + } + else + { + transforms.Add(transform); + } + } + + public void addRenderAt(Vector3 transform)//for use with single points + { + if (drawType != ModelDrawType.singlePoint) + { + Application.error("ModelDrawableInstanced was requested to add a vector3 as a transform for non single point drawing!"); + } + else + { + vecTransforms.Add(transform); + } + } //TODO: impliment (ModelDrawableInstanced) } } diff --git a/Coictus/Src/Rendering/Models/ModelDrawableInstancedInterpolated.cs b/Coictus/Src/Rendering/Models/ModelDrawableInstancedInterpolated.cs index 7179e78..ef49b52 100644 --- a/Coictus/Src/Rendering/Models/ModelDrawableInstancedInterpolated.cs +++ b/Coictus/Src/Rendering/Models/ModelDrawableInstancedInterpolated.cs @@ -4,5 +4,12 @@ Uses two matrices for each instance, and a interpolation factor passed to shader each draw call.*/ public class ModelDrawableInstancedInterpolated : ModelDrawableInstanced { + public ModelDrawableInstancedInterpolated(Model instance, uint[] indices, ModelDrawType drawType) : base(instance, indices, drawType) + { + } + + public ModelDrawableInstancedInterpolated(ModelDrawable instance, ModelDrawType drawType) : base(instance, drawType) + { + } } } diff --git a/Coictus/Src/Rendering/Models/ModelUtil.cs b/Coictus/Src/Rendering/Models/ModelUtil.cs index 0ee2791..6cd74f1 100644 --- a/Coictus/Src/Rendering/Models/ModelUtil.cs +++ b/Coictus/Src/Rendering/Models/ModelUtil.cs @@ -1,9 +1,83 @@ -namespace Coictus.Models +using System.Collections.Generic; +using System.IO; + +namespace Coictus.Models { /*This class is for loading and providing model data to be used throughout the game, without having to re-load them each time they are used.*/ public static class ModelUtil { - //TODO: impliment (ModelUtil) + + private static Dictionary models = null; + public static void loadAllFoundModelFiles() + { + models = new Dictionary(); + loadAllModelsRecursive(ResourceUtil.getOBJFileDir()); + } + + private static void loadAllModelsRecursive(string directory) + { + string[] allFiles = Directory.GetFiles(directory); + string[] allDirectories = Directory.GetDirectories(directory); + foreach (string file in allFiles) + { + if (file.Contains(".obj")) + { + tryAddNewModel(file); + } + } + + foreach (string dir in allDirectories) + { + loadAllModelsRecursive(dir); + } + } + + private static void tryAddNewModel(string modelDir) + { + string shaderName = modelDir.Replace(ResourceUtil.getOBJFileDir(), "");//removes directory + ModelDrawable addingModel = OBJLoader.loadModelDrawableFromObjFile(modelDir); + models.Add(shaderName, addingModel); + } + + /*Returns true if the requested Model was found in the global list*/ + public static bool tryGetModel(string name, out ModelDrawable model) + { + bool success = models.TryGetValue(name, out model); + if (!success) + { + Application.error("ModelUtil could not find Model named: " + name + " in global list, returning null."); + } + return success; + } + + /*attempts to create a modeldrawable from the provided names*/ + public static ModelDrawable createModelDrawable(string shaderName, string textureName, string modelName) + { + if(modelName == "none") + { + return null; + } + ModelDrawable result; + if(tryGetModel(modelName, out result)) + { + Shader shader; + ShaderUtil.tryGetShader(shaderName, out shader); + result.setShader(shader); + + Texture tex; + TextureUtil.tryGetTexture(textureName, out tex); + result.setTexture(tex); + } + return result; + } + + public static void deleteAll() + { + foreach(ModelDrawable model in models.Values) + { + model.delete(); + } + } } } diff --git a/Coictus/Src/Rendering/Models/OBJProcessing/OBJLoader.cs b/Coictus/Src/Rendering/Models/OBJLoader.cs similarity index 83% rename from Coictus/Src/Rendering/Models/OBJProcessing/OBJLoader.cs rename to Coictus/Src/Rendering/Models/OBJLoader.cs index 2b3cbc3..b6efd64 100644 --- a/Coictus/Src/Rendering/Models/OBJProcessing/OBJLoader.cs +++ b/Coictus/Src/Rendering/Models/OBJLoader.cs @@ -53,6 +53,40 @@ public static ModelDrawable loadModelDrawableFromObjFile(string shaderDir, strin } + /*Takes in a obj file and returns a model. indices will be assigned the read indices. If processing fails, will return a default debug model*/ + public static ModelDrawable loadModelDrawableFromObjFile(string objFilePath) + { + if (objFilePath == "none") + { + return null; + } + + try + { + reader = new StreamReader(objFilePath); + } + catch (Exception e) + { + Application.error("Could not load OBJ File!\nFile Path: " + objFilePath + "\nException: " + e.Message); + return DefaultDebugModel.getNewModelDrawable();//returns model by defualt or failing + } + successfullyLoaded = false; + vertexResult = new List(); + positions = new List(); + unorderedUVs = new List(); + OBJLoader.indices = new List(); + + processAllLines(); + + if (!successfullyLoaded) + { + return DefaultDebugModel.getNewModelDrawable();//returns model by defualt or failing + } + reader.Close(); + return new ModelDrawable("ColorTexture3D.shader", "debug", vertexResult.ToArray(), indices.ToArray()); + + } + /*reads each line and processes it based on its tag, v is vertex position, vt is uv, and f is a face*/ private static void processAllLines() { diff --git a/Coictus/Src/Rendering/Models/Prefabs/CubePrefab.cs b/Coictus/Src/Rendering/Models/Prefabs/CubePrefab.cs index abb1808..f1c55f8 100644 --- a/Coictus/Src/Rendering/Models/Prefabs/CubePrefab.cs +++ b/Coictus/Src/Rendering/Models/Prefabs/CubePrefab.cs @@ -5,6 +5,9 @@ namespace Coictus.Models { public static class CubePrefab { + public static readonly string shaderName = "ColorTextureFog.shader"; + public static readonly string textureName = "Explosion.png"; + public static readonly Vertex[] cubeVertices; public static readonly uint[] cubeIndices; @@ -30,29 +33,20 @@ static CubePrefab() } /*generates a new model using copies of this models arrays.*/ - public static Model getNewModel() + public static Model copyModel() { Vertex[] verticesCopy = new Vertex[cubeVertices.Length]; Array.Copy(cubeVertices, verticesCopy, cubeVertices.Length); return new Model(verticesCopy); } - public static ModelDrawable getNewModelDrawable() + public static ModelDrawable copyModelDrawable() { Vertex[] verticesCopy = new Vertex[cubeVertices.Length]; uint[] indicesCopy = new uint[cubeIndices.Length]; Array.Copy(cubeVertices, verticesCopy, cubeVertices.Length); Array.Copy(cubeIndices, indicesCopy, cubeIndices.Length); - return new ModelDrawable(getShaderDir(), getTextureDir(), verticesCopy, indicesCopy); - } - - public static string getShaderDir() - { - return ResourceUtil.getShaderFileDir("ColorTextureFog3D.shader"); + return new ModelDrawable(shaderName, textureName, verticesCopy, indicesCopy); } - public static string getTextureDir() - { - return ResourceUtil.getTextureFileDir("EntityCactus.png"); - } } } diff --git a/Coictus/Src/Rendering/Models/Prefabs/DefaultDebugModel.cs b/Coictus/Src/Rendering/Models/Prefabs/DefaultDebugModel.cs index 238ca3a..8747944 100644 --- a/Coictus/Src/Rendering/Models/Prefabs/DefaultDebugModel.cs +++ b/Coictus/Src/Rendering/Models/Prefabs/DefaultDebugModel.cs @@ -8,6 +8,7 @@ namespace Coictus.Models //just an ugly cube for when a model fails to load public static class DefaultDebugModel { + public static string shaderName = "ColorTexture3D.shader"; public static readonly Vertex[] vertices = new Vertex[] { //zPos @@ -57,18 +58,9 @@ public static ModelDrawable getNewModelDrawable() uint[] indicesCopy = new uint[indices.Length]; Array.Copy(vertices, verticesCopy, vertices.Length); Array.Copy(indices, indicesCopy, indices.Length); - return (ModelDrawable)new ModelDrawable(getShaderDir(), new Texture(), verticesCopy, indicesCopy).translateVertices(new Vector3(0, 0.5F, 0)); + return (ModelDrawable)new ModelDrawable(shaderName, "debug", verticesCopy, indicesCopy).translateVertices(new Vector3(0, 0.5F, 0)); } - public static string getShaderDir() - { - return ResourceUtil.getShaderFileDir("ColorTexture3D.shader"); - } - - public static string getTextureDir() - { - return ""; - } } } diff --git a/Coictus/Src/Rendering/Models/Prefabs/PlanePrefab.cs b/Coictus/Src/Rendering/Models/Prefabs/PlanePrefab.cs index afd4b71..cdc953a 100644 --- a/Coictus/Src/Rendering/Models/Prefabs/PlanePrefab.cs +++ b/Coictus/Src/Rendering/Models/Prefabs/PlanePrefab.cs @@ -4,6 +4,9 @@ namespace Coictus.Models { public static class PlanePrefab { + public static readonly string shaderName = "ColorTextureFog.shader"; + public static readonly string textureName = "Explosion.png"; + public static readonly Vertex[] quadVertices = new Vertex[] { new Vertex(-0.5F, 0, 0.5F, 1.0F, 1.0F, 1.0F, 1.0F, 0.0F, 0.0F),//0 @@ -19,29 +22,19 @@ public static class PlanePrefab }; /*generates a new model using copies of this models arrays.*/ - public static Model getNewModel() + public static Model copyModel() { Vertex[] verticesCopy = new Vertex[quadVertices.Length]; Array.Copy(quadVertices, verticesCopy, quadVertices.Length); return new Model(verticesCopy); } - public static ModelDrawable getNewModelDrawable() + public static ModelDrawable copyModelDrawable() { Vertex[] verticesCopy = new Vertex[quadVertices.Length]; uint[] indicesCopy = new uint[quadIndices.Length]; Array.Copy(quadVertices, verticesCopy, quadVertices.Length); Array.Copy(quadIndices, indicesCopy, quadIndices.Length); - return new ModelDrawable(getShaderDir(), getTextureDir(), verticesCopy, indicesCopy); - } - - public static string getShaderDir() - { - return ResourceUtil.getShaderFileDir("ColorTextureFog3D.shader"); - } - - public static string getTextureDir() - { - return ResourceUtil.getTextureFileDir("sand.png"); + return new ModelDrawable(shaderName, textureName, verticesCopy, indicesCopy); } } } diff --git a/Coictus/Src/Rendering/Models/Prefabs/QuadPrefab.cs b/Coictus/Src/Rendering/Models/Prefabs/QuadPrefab.cs index b70ed47..7d83694 100644 --- a/Coictus/Src/Rendering/Models/Prefabs/QuadPrefab.cs +++ b/Coictus/Src/Rendering/Models/Prefabs/QuadPrefab.cs @@ -4,6 +4,9 @@ namespace Coictus.Models { public static class QuadPrefab { + public static readonly string shaderName = "ColorTextureFog.shader"; + public static readonly string textureName = "Explosion.png"; + public static readonly Vertex[] quadVertices = new Vertex[] { new Vertex(-0.5F, -0.5F, 0.0F, 1.0F, 1.0F, 1.0F, 1.0F, 0.0F, 0.0F),//0 @@ -31,17 +34,7 @@ public static ModelDrawable getNewModelDrawable() uint[] indicesCopy = new uint[quadIndices.Length]; Array.Copy(quadVertices, verticesCopy, quadVertices.Length); Array.Copy(quadIndices, indicesCopy, quadIndices.Length); - return new ModelDrawable(getShaderDir(), getTextureDir(), verticesCopy, indicesCopy); - } - - public static string getShaderDir() - { - return ResourceUtil.getShaderFileDir("ColorTextureFog3D.shader"); - } - - public static string getTextureDir() - { - return ResourceUtil.getTextureFileDir("EntityCactus.png"); + return new ModelDrawable(shaderName, textureName, verticesCopy, indicesCopy); } } } diff --git a/Coictus/Src/Rendering/Renderer.cs b/Coictus/Src/Rendering/Renderer.cs index 40d2839..027b693 100644 --- a/Coictus/Src/Rendering/Renderer.cs +++ b/Coictus/Src/Rendering/Renderer.cs @@ -1,5 +1,6 @@ using Coictus.Debugging; using Coictus.GUI; +using Coictus.Models; using Coictus.SubRendering; using OpenTK; using OpenTK.Graphics.OpenGL; @@ -13,6 +14,7 @@ namespace Coictus This class also contains the projection matrix.*/ public static class Renderer//TODO: Reduce driver overhead closer to zero { + private static int privateTotalDrawCallCount; private static Matrix4 projectionMatrix; public static readonly bool useOffScreenBuffer = false; /*Called before any rendering is done*/ @@ -29,6 +31,10 @@ public static void init() GL.LineWidth(3); projectionMatrix = Matrix4.CreatePerspectiveFieldOfView((float)MathUtil.radians(GameSettings.fov), GameInstance.aspectRatio, 0.1F, 1000.0F); if(useOffScreenBuffer) OffScreen.init(); + + ShaderUtil.loadAllFoundShaderFiles(); + TextureUtil.loadAllFoundTextureFiles(); + ModelUtil.loadAllFoundModelFiles(); } /*Called each time the game window is resized*/ @@ -57,21 +63,39 @@ public static void renderAll() } private static void renderWorld() { + privateTotalDrawCallCount = 0; GameInstance.get.currentPlanet.drawEntities(GameInstance.get.thePlayer.getViewMatrix(), projectionMatrix); GameInstance.get.currentPlanet.drawVFX(GameInstance.get.thePlayer.getViewMatrix(), projectionMatrix); GameInstance.get.currentPlanet.getGroundModel().draw(GameInstance.get.thePlayer.getViewMatrix(), projectionMatrix, GameInstance.get.currentPlanet.getFogColor()); GameInstance.get.currentPlanet.getWallsModel().draw(GameInstance.get.thePlayer.getViewMatrix(), projectionMatrix, GameInstance.get.currentPlanet.getFogColor()); GameInstance.get.currentPlanet.getSkyboxModel().draw(GameInstance.get.thePlayer.getViewMatrix(), projectionMatrix, GameInstance.get.currentPlanet.getSkyColor(), GameInstance.get.currentPlanet.getFogColor()); if(GameSettings.drawHitboxes)HitboxRenderer.renderAll(GameInstance.get.thePlayer.getViewMatrix(), projectionMatrix); - } + /*Called after all draw calls*/ private static void postRender() { if (useOffScreenBuffer) OffScreen.renderOffScreenTexture(); GameInstance.get.SwapBuffers(); } + + public static int getAndResetTotalDrawCount() + { + int result = privateTotalDrawCallCount; + privateTotalDrawCallCount = 0; + return result; + } + + /*deletes all loaded opengl assets*/ + public static void onClosing() + { + ShaderUtil.deleteAll(); + TextureUtil.deleteAll(); + ModelUtil.deleteAll(); + } + public static Matrix4 projMatrix { get => projectionMatrix; } + public static int totalDraws { get { return privateTotalDrawCallCount; } set { privateTotalDrawCallCount = value; } } } } \ No newline at end of file diff --git a/Coictus/Src/Rendering/Shader.cs b/Coictus/Src/Rendering/Shader.cs index d213186..5dbb95c 100644 --- a/Coictus/Src/Rendering/Shader.cs +++ b/Coictus/Src/Rendering/Shader.cs @@ -160,6 +160,7 @@ protected virtual void Dispose(bool disposing) disposed = true; } } + public void Dispose() { Dispose(true); diff --git a/Coictus/Src/Rendering/ShaderUtil.cs b/Coictus/Src/Rendering/ShaderUtil.cs index 037ce30..e62e88b 100644 --- a/Coictus/Src/Rendering/ShaderUtil.cs +++ b/Coictus/Src/Rendering/ShaderUtil.cs @@ -1,9 +1,61 @@ -namespace Coictus +using System.Collections.Generic; +using System.IO; + +namespace Coictus { /*Class for pre-loading all Shaders found on file at launch so they can be used throughout the game without having to be re-loaded and re-allocated.*/ public static class ShaderUtil { - //TODO: Impliment (ShaderUtil) + private static Dictionary shaders = null; + public static void loadAllFoundShaderFiles() + { + shaders = new Dictionary(); + loadAllShadersRecursive(ResourceUtil.getShaderFileDir()); + } + + private static void loadAllShadersRecursive(string directory) + { + string[] allFiles = Directory.GetFiles(directory); + string[] allDirectories = Directory.GetDirectories(directory); + foreach (string file in allFiles) + { + if (file.Contains(".shader")) + { + tryAddNewShader(file); + } + } + + foreach (string dir in allDirectories) + { + loadAllShadersRecursive(dir); + } + } + + private static void tryAddNewShader(string shaderDir) + { + string shaderName = shaderDir.Replace(ResourceUtil.getShaderFileDir(), "");//removes directory + Shader addingShader = new Shader(shaderDir); + shaders.Add(shaderName, addingShader); + } + + /*Returns true if the requested shader was found in the global list*/ + public static bool tryGetShader(string name, out Shader shader) + { + bool success = shaders.TryGetValue(name, out shader); + if (!success) + { + Application.error("ShaderUtil could not find shader named: " + name + " in global list, returning null."); + } + return success; + } + + public static void deleteAll() + { + foreach(Shader shader in shaders.Values) + { + shader.Dispose(); + } + } } } diff --git a/Coictus/Src/Rendering/SubRendering/Batching/QuadBatcher.cs b/Coictus/Src/Rendering/SubRendering/Batching/QuadBatcher.cs index 0f014d0..71b60fb 100644 --- a/Coictus/Src/Rendering/SubRendering/Batching/QuadBatcher.cs +++ b/Coictus/Src/Rendering/SubRendering/Batching/QuadBatcher.cs @@ -14,12 +14,12 @@ static class QuadBatcher /*Batches together models made of quads for being rendered in 3D*/ - public static ModelDrawable batchQuadModels(Model[] quadModels, string shaderFile, string textureFile) + public static ModelDrawable batchQuadModels(Model[] quadModels, string shaderName, string textureName) { Vertex[] newVertices; combineData(quadModels, out newVertices); - return new ModelDrawable(shaderFile, textureFile, newVertices, indices); + return new ModelDrawable(shaderName, textureName, newVertices, indices); } /*Combines all the data in the model array and outputs the combined ordered arrays.*/ diff --git a/Coictus/Src/Rendering/SubRendering/GUI/GUIScreen.cs b/Coictus/Src/Rendering/SubRendering/GUI/GUIScreen.cs index c4edaf8..580270e 100644 --- a/Coictus/Src/Rendering/SubRendering/GUI/GUIScreen.cs +++ b/Coictus/Src/Rendering/SubRendering/GUI/GUIScreen.cs @@ -27,7 +27,7 @@ public GUIScreen(string screenName, string textFont, uint maxCharCount = 1024) } this.screenName = screenName; this.maxCharCount = maxCharCount; - screenTextModel = new ModelDrawableDynamic(TextUtil.textShaderDir, TextUtil.getTextureDirForFont(screenFont), QuadBatcher.getIndicesForQuadCount((int)maxCharCount), (int)maxCharCount * 4, true); + screenTextModel = new ModelDrawableDynamic(TextUtil.textShaderName, TextUtil.getTextureNameForScreenFont(screenFont), QuadBatcher.getIndicesForQuadCount((int)maxCharCount), (int)maxCharCount * 4); } public void buildScreenTextModel() diff --git a/Coictus/Src/Rendering/SubRendering/GUI/Text/TextUtil.cs b/Coictus/Src/Rendering/SubRendering/GUI/Text/TextUtil.cs index d176dfc..fc7db8c 100644 --- a/Coictus/Src/Rendering/SubRendering/GUI/Text/TextUtil.cs +++ b/Coictus/Src/Rendering/SubRendering/GUI/Text/TextUtil.cs @@ -8,7 +8,7 @@ namespace Coictus.GUI.Text public enum TextAlign { LEFT, CENTER, RIGHT }; public static class TextUtil { - public static readonly string textShaderDir = ResourceUtil.getShaderFileDir(@"GUI\GuiTextShader.shader"); + public static readonly string textShaderName = @"GUI\GuiTextShader.shader"; public static readonly float defaultFontSize = 0.02F; public static readonly int defaultScreenEdgePadding = 5; //5 pixels @@ -28,12 +28,12 @@ public static bool tryGetFont(string name, out FontFace font) /*Goes through the font file directory and adds all fonts*/ public static void loadAllFoundTextFiles() { - string[] allFileDirectoriesAndName = Directory.GetFiles(ResourceUtil.getFontFileDir("")); + string[] allFileDirectoriesAndName = Directory.GetFiles(ResourceUtil.getFontFileDir()); foreach(string dir in allFileDirectoriesAndName) { if (dir.Contains(".fnt")) { - string fontName = dir.Replace(ResourceUtil.getFontFileDir(""), "").Replace(".fnt", "");//removes directory and file extension + string fontName = dir.Replace(ResourceUtil.getFontFileDir(), "").Replace(".fnt", "");//removes directory and file extension tryAddNewFontToGlobalList(fontName); } } @@ -52,9 +52,9 @@ private static void tryAddNewFontToGlobalList(string fontName) } } - public static string getTextureDirForFont(FontFace font) + public static string getTextureNameForScreenFont(FontFace font) { - return ResourceUtil.getFontFileDir(font.getFontName() + ".png"); + return font.getFontName() + ".png"; } } } diff --git a/Coictus/Src/Rendering/SubRendering/OffScreen.cs b/Coictus/Src/Rendering/SubRendering/OffScreen.cs index 08a503b..d1cea64 100644 --- a/Coictus/Src/Rendering/SubRendering/OffScreen.cs +++ b/Coictus/Src/Rendering/SubRendering/OffScreen.cs @@ -10,7 +10,7 @@ public static class OffScreen { private static ModelDrawable screenQuad; private static Shader screenShader; - private static readonly string screenShaderDir = ResourceUtil.getShaderFileDir("Offscreen.shader"); + private static readonly string screenShaderName = "Offscreen.shader"; private static int texColorBuffer; private static int depthBuffer; private static int frameBuffer; @@ -36,7 +36,7 @@ public static void init(float superSamplingMultiplyer = 1.0F) GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMinFilter.Nearest); GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba16, width, height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero); - screenShader = new Shader(screenShaderDir); + screenShader = new Shader(screenShaderName); GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, depthBuffer); GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.DepthComponent32, width, height); @@ -60,7 +60,7 @@ public static void init(float superSamplingMultiplyer = 1.0F) } screenQuad = (ModelDrawable)QuadPrefab.getNewModelDrawable().scaleVertices(new Vector3(2.0F, 2.0F, 1.0F));//scale quad to fit screen - screenQuad.setNewShader(screenShader); + screenQuad.setShader(screenShader); } public static void prepareToRenderToOffScreenTexture() diff --git a/Coictus/Src/Rendering/TextureUtil.cs b/Coictus/Src/Rendering/TextureUtil.cs index 9d25928..4ca7d8b 100644 --- a/Coictus/Src/Rendering/TextureUtil.cs +++ b/Coictus/Src/Rendering/TextureUtil.cs @@ -1,9 +1,76 @@ -namespace Coictus +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Coictus { /*Class for pre-loading all textures found on file at launch so they can be used throughout the game without having to be re-loaded and re-allocated.*/ public static class TextureUtil { - //TODO: impliment (TextureUtil) + private static Dictionary textures = null; + public static void loadAllFoundTextureFiles() + { + textures = new Dictionary(); + textures.Add("none", new Texture("none", false));//first texture will be the null texture + textures.Add("debug", new Texture());//second texture will be the debug texture + loadAllTexturesRecursive(ResourceUtil.getTextureFileDir()); + loadAllTexturesRecursive(ResourceUtil.getFontFileDir()); + } + + private static void loadAllTexturesRecursive(string directory) + { + string[] allFiles = Directory.GetFiles(directory); + string[] allDirectories = Directory.GetDirectories(directory); + foreach (string file in allFiles) + { + if (file.Contains(".png")) + { + tryAddNewTexture(file); + } + } + + foreach (string dir in allDirectories) + { + loadAllTexturesRecursive(dir); + } + } + + private static void tryAddNewTexture(string textureDir) + { + string shaderName = textureDir.Replace(ResourceUtil.getTextureFileDir(), "").Replace(ResourceUtil.getFontFileDir(), "");//removes directory + Texture addingTexture = new Texture(textureDir, false); + textures.Add(shaderName, addingTexture); + } + + /*Returns true if the requested texture was found in the global list*/ + public static bool tryGetTexture(string name, out Texture texture) + { + if(name == "none") + { + texture = textures.ElementAt(0).Value; + return false; + } + if(name == "debug") + { + texture = textures.ElementAt(1).Value; + return true; + } + + bool success = textures.TryGetValue(name, out texture); + if (!success) + { + Application.error("TextureUtil could not find texture named: " + name + " in global list, returning null."); + } + return success; + } + + public static void deleteAll() + { + foreach (Texture tex in textures.Values) + { + tex.Dispose(); + } + } } } diff --git a/Coictus/Src/Rendering/VFX/VFXBase.cs b/Coictus/Src/Rendering/VFX/VFXBase.cs index 90d44bb..595606d 100644 --- a/Coictus/Src/Rendering/VFX/VFXBase.cs +++ b/Coictus/Src/Rendering/VFX/VFXBase.cs @@ -31,12 +31,13 @@ public class VFXBase : PositionalObject, IDisposable protected Matrix4 prevTickModelMatrix; protected Matrix4 modelMatrix; protected bool removalFlag = false;// true if this entity should be removed in the next tick + protected bool shouldDeleteModel = false;// true if this vfx is using a model loaded from file. If so, it should NOT be deleted! protected VFXRenderType renderType; public VFXBase(Vector3 pos, float initialScale, string shaderDir, string textureDir, string modelDir, float maxExistingSeconds = 1, VFXRenderType renderType = VFXRenderType.tirangles) : base(pos) { this.scale = initialScale; - this.vfxModel = OBJLoader.loadModelDrawableFromObjFile(shaderDir, textureDir, modelDir, renderType == VFXRenderType.points ? false : true);//TODO:Inneficcient. This will mean we have to load the data every time a VFX is spawned. maybe a list of pre loaded models is needed? + this.vfxModel = ModelUtil.createModelDrawable(shaderDir, textureDir, modelDir); maxExistingTicks = TicksAndFps.getNumOfTicksForSeconds(maxExistingSeconds); updateVFXModel(); updateVFXModel(); @@ -114,15 +115,17 @@ protected virtual void Dispose(bool disposing) { if (!removalFlag) { - if (vfxModel != null) + removalFlag = true; + if(shouldDeleteModel) { vfxModel.delete(); } - - removalFlag = true; } } - + protected virtual void setShouldDeleteModelOnDeath(bool flag) + { + shouldDeleteModel = flag; + } public void Dispose() { Dispose(true); diff --git a/Coictus/Src/Rendering/VFX/VFXExplosion.cs b/Coictus/Src/Rendering/VFX/VFXExplosion.cs index a43bc27..36f0f61 100644 --- a/Coictus/Src/Rendering/VFX/VFXExplosion.cs +++ b/Coictus/Src/Rendering/VFX/VFXExplosion.cs @@ -4,13 +4,13 @@ namespace Coictus.VFX { public class VFXExplosion : VFXBase { - protected static readonly string shaderDir = ResourceUtil.getShaderFileDir("ColorTextureFog3D.shader"); - protected static readonly string textureDir = ResourceUtil.getTextureFileDir("Explosion.png"); - protected static readonly string modelDir = ResourceUtil.getOBJFileDir("IcoSphere.obj"); + protected static readonly string shaderName = "ColorTextureFog3D.shader"; + protected static readonly string textureName = "Explosion.png"; + protected static readonly string modelname = "IcoSphere.obj"; private static Random rand = new Random(); [Obsolete("This vfx was used for explosions before the addition of point particle vfx")] - public VFXExplosion(Vector3 pos) : base(pos, 1.0F, shaderDir, textureDir, modelDir, 0.5F, VFXRenderType.tirangles) + public VFXExplosion(Vector3 pos) : base(pos, 1.0F, shaderName, textureName, modelname, 0.5F, VFXRenderType.tirangles) { scale = 3.0F; setPitch((float)(rand.NextDouble() * 180D)); diff --git a/Coictus/Src/Rendering/VFX/VFXPointParticles.cs b/Coictus/Src/Rendering/VFX/VFXPointParticles.cs index a623e2b..1b50e3d 100644 --- a/Coictus/Src/Rendering/VFX/VFXPointParticles.cs +++ b/Coictus/Src/Rendering/VFX/VFXPointParticles.cs @@ -1,13 +1,12 @@ using Coictus.Models; using OpenTK; -using System; namespace Coictus.VFX { /*Base class for any VFX using point particles*/ public class VFXPointParticles : VFXBase { - private static string defaultShaderDir = ResourceUtil.getShaderFileDir(@"VFX\PointParticleFog.shader"); + private static string defaultShaderName = @"VFX\PointParticleFog.shader"; protected CustomColor pointColor; protected float randomPointPositionSpread;//the maximum distance between points when randomizing a point cloud (e.g, a puff of smoke) protected float pointRadius; @@ -18,16 +17,17 @@ public class VFXPointParticles : VFXBase /*this constructor is for creating a point particle based VFX which does not create a random point cloud. maybe you will want to construct the points in a specific manner with colors or use a model.*/ - public VFXPointParticles(Vector3 pos, CustomColor color, float radius, bool ambientOcclusion, float maxExistingSeconds = 2F, float alpha = 1) : base(pos, 1.0F, defaultShaderDir, "none", "none", maxExistingSeconds, VFXRenderType.points) + public VFXPointParticles(Vector3 pos, CustomColor color, float radius, bool ambientOcclusion, float maxExistingSeconds = 2F, float alpha = 1) : base(pos, 1.0F, defaultShaderName, "none", "none", maxExistingSeconds, VFXRenderType.points) { colorAlpha = alpha; pointColor = color; pointRadius = radius; pointAmbientOcclusion = ambientOcclusion; + setShouldDeleteModelOnDeath(true); } /*this constructor is for creating a randomized particle cloud at the position using the provided parameters*/ - public VFXPointParticles(Vector3 pos, CustomColor color, int particleCount, float randomPointPositionSpread, float radius, bool randomBrightness, bool ambientOcclusion, float maxExistingSeconds = 2F, float alpha = 1) : base(pos, 1.0F, defaultShaderDir, "none", "none", maxExistingSeconds, VFXRenderType.points) + public VFXPointParticles(Vector3 pos, CustomColor color, int particleCount, float randomPointPositionSpread, float radius, bool randomBrightness, bool ambientOcclusion, float maxExistingSeconds = 2F, float alpha = 1) : base(pos, 1.0F, defaultShaderName, "none", "none", maxExistingSeconds, VFXRenderType.points) { colorAlpha = alpha; this.randomBrightness = randomBrightness; @@ -37,6 +37,7 @@ public VFXPointParticles(Vector3 pos, CustomColor color, int particleCount, floa pointRadius = radius; pointAmbientOcclusion = ambientOcclusion; constructPointCloudModel(); + setShouldDeleteModelOnDeath(true); } /*Builds the vertices for the point cloud to be rendered. By default this method will build a randomized point cloud @@ -50,7 +51,7 @@ protected virtual void constructPointCloudModel() points[i] = new Vertex(getRandomParticleOffset(), getPointColor(), Vector2.Zero); } - vfxModel = new ModelDrawable(defaultShaderDir, "none", points); + vfxModel = new ModelDrawable(defaultShaderName, "none", points); } protected Vector3 getRandomParticleOffset() diff --git a/Coictus/Src/World/Collisions/CollisionUtil.cs b/Coictus/Src/World/Collisions/CollisionUtil.cs index 005d7f1..b026732 100644 --- a/Coictus/Src/World/Collisions/CollisionUtil.cs +++ b/Coictus/Src/World/Collisions/CollisionUtil.cs @@ -12,6 +12,7 @@ public enum ColliderType//used for detecting which type a collider is } //TODO: make collision resolution more accurate, i.e, make collisions compensate for high velocities pushing colliders to wrong side of objects. //TODO: make colliders on moving objects work with interpolation. + //TODO: make collisions calculate faster at high numbers. public static class CollisionUtil { public static bool getOverlapAndDirectionForColliderTypes(ICollider colliderA, ICollider colliderB, out Vector3 direction, out float overlap) diff --git a/Coictus/Src/World/Entity/Entity.cs b/Coictus/Src/World/Entity/Entity.cs index 5eebeb4..59d0624 100644 --- a/Coictus/Src/World/Entity/Entity.cs +++ b/Coictus/Src/World/Entity/Entity.cs @@ -126,10 +126,8 @@ public virtual void setCurrentPlanet(World p) //removes this entity from existance public virtual void ceaseToExist() { - if (hasModel && entityModel != null) - { - entityModel.delete(); - } + hasModel = false; + entityModel = null; removalFlag = true; } diff --git a/Coictus/Src/World/World.cs b/Coictus/Src/World/World.cs index 06ebab4..345a3e7 100644 --- a/Coictus/Src/World/World.cs +++ b/Coictus/Src/World/World.cs @@ -11,8 +11,6 @@ namespace Coictus /*This class will be the abstraction of any environment constructed for the player and entities to exist in.*/ public class World { - private static ModelDrawable testCube = (ModelDrawable)CubePrefab.getNewModelDrawable().setColor(CustomColor.white).scaleVertices(new Vector3(5, 5, 5)).rotateVertices(new Vector3(15,0,0)); - private ModelDrawable groundModel; private ModelDrawable wallsModel; private ModelDrawable skyboxModel; @@ -23,7 +21,8 @@ public class World public Dictionary entityColliders = new Dictionary();// the int is the given ID for the parent entity public List worldColliders = new List();//list of colliders with no parent, ie, walls, ground planes. public List vfxList = new List(); - private string wallTextureDir = ResourceUtil.getTextureFileDir("plasterwall.png"); + private string wallTextureName = "plasterwall.png"; + private string terrainShaderName = "ColorTextureFog3D.shader"; public World() @@ -32,7 +31,6 @@ public World() skyColor = CustomColor.skyBlue.toNormalVec3(); buildSkyBox(); generateWorld(); - testCube.setNewTexture(new Texture(512)); } public void setSkyColor(Vector3 skyColor) @@ -51,7 +49,7 @@ public Vector3 getSkyColor() { return fogColor; } - + /*TODO: INNEFICIENT, loops through each entitiy and draws their model with a seperate call*/ public void drawEntities(Matrix4 viewMatrix, Matrix4 projectionMatrix) { @@ -62,7 +60,7 @@ public void drawEntities(Matrix4 viewMatrix, Matrix4 projectionMatrix) ent.Value.getEntityModel().draw(viewMatrix, projectionMatrix, fogColor); } } - testCube.draw(viewMatrix, projectionMatrix, fogColor); + } /*TODO: INNEFICIENT, loops through each VFX and draws their model with a seperate call*/ @@ -88,7 +86,7 @@ private void buildSkyBox() temp[3] = QuadPrefab.getNewModel().transformVertices(new Vector3(1, 1, 1), new Vector3(0, 0, 0), new Vector3(0, 0, -0.5F));//negZ temp[4] = QuadPrefab.getNewModel().transformVertices(new Vector3(1, 1, 1), new Vector3(-90, 0, 0), new Vector3(0, 0.5F, 0));//top temp[5] = QuadPrefab.getNewModel().transformVertices(new Vector3(1, 1, 1), new Vector3(90, 0, 0), new Vector3(0, -0.5F, 0));//bottom - skyboxModel = QuadBatcher.batchQuadModels(temp, ResourceUtil.getShaderFileDir("SkyboxShader3D.shader"), "none"); + skyboxModel = QuadBatcher.batchQuadModels(temp, "SkyboxShader3D.shader", "none"); } private void generateWorld()//creates the playground and world colliders @@ -105,27 +103,27 @@ private void buildSkyBox() { for(int z = 0; z < 64; z++) { - unbatchedGroundQuads[x * 64 + z] = PlanePrefab.getNewModel().scaleVertices(new Vector3(20,1,20)).scaleUV(new Vector2(5F,5F)).translateVertices(new Vector3((x-32)*20, groundHeight, (z-32)*20)); + unbatchedGroundQuads[x * 64 + z] = PlanePrefab.copyModel().scaleVertices(new Vector3(20,1,20)).scaleUV(new Vector2(5F,5F)).translateVertices(new Vector3((x-32)*20, groundHeight, (z-32)*20)); } } //building the lump in middle of map, quads added after all the flat plane quads. //top face - unbatchedGroundQuads[4096] = PlanePrefab.getNewModel().scaleVerticesAndUV(new Vector3(2,1,2)).translateVertices(new Vector3(0, 1F, 0)); + unbatchedGroundQuads[4096] = PlanePrefab.copyModel().scaleVerticesAndUV(new Vector3(2,1,2)).translateVertices(new Vector3(0, 1F, 0)); //negZ face - unbatchedGroundQuads[4097] = PlanePrefab.getNewModel().scaleVerticesAndUV(new Vector3(2, 1, 1)).rotateVertices(new Vector3(90,0,0)).translateVertices(new Vector3(0, 0.5F, -1F)).setColor(new Vector4(0.8F, 0.8F, 0.8F, 1.0F));//pseudoLighting + unbatchedGroundQuads[4097] = PlanePrefab.copyModel().scaleVerticesAndUV(new Vector3(2, 1, 1)).rotateVertices(new Vector3(90,0,0)).translateVertices(new Vector3(0, 0.5F, -1F)).setColor(new Vector4(0.8F, 0.8F, 0.8F, 1.0F));//pseudoLighting //posZ face - unbatchedGroundQuads[4098] = PlanePrefab.getNewModel().scaleVerticesAndUV(new Vector3(2, 1, 1)).rotateVertices(new Vector3(-90,0,0)).translateVertices(new Vector3(0, 0.5F, 1F)).setColor(new Vector4(0.7F, 0.7F, 0.7F, 1.0F)); + unbatchedGroundQuads[4098] = PlanePrefab.copyModel().scaleVerticesAndUV(new Vector3(2, 1, 1)).rotateVertices(new Vector3(-90,0,0)).translateVertices(new Vector3(0, 0.5F, 1F)).setColor(new Vector4(0.7F, 0.7F, 0.7F, 1.0F)); //negX face - unbatchedGroundQuads[4099] = PlanePrefab.getNewModel().scaleVerticesAndUV(new Vector3(1, 1, 2)).rotateVertices(new Vector3(0,0,-90)).translateVertices(new Vector3(-1f, 0.5F, 0)).setColor(new Vector4(0.9F, 0.9F, 0.9F, 1.0F)); + unbatchedGroundQuads[4099] = PlanePrefab.copyModel().scaleVerticesAndUV(new Vector3(1, 1, 2)).rotateVertices(new Vector3(0,0,-90)).translateVertices(new Vector3(-1f, 0.5F, 0)).setColor(new Vector4(0.9F, 0.9F, 0.9F, 1.0F)); //posX face - unbatchedGroundQuads[4100] = PlanePrefab.getNewModel().scaleVerticesAndUV(new Vector3(1, 1, 2)).rotateVertices(new Vector3(0,0,90)).translateVertices(new Vector3(1f, 0.5F, 0)).setColor(new Vector4(0.65F, 0.65F, 0.65F, 1.0F)); - groundModel = QuadBatcher.batchQuadModels(unbatchedGroundQuads, PlanePrefab.getShaderDir(), PlanePrefab.getTextureDir()); + unbatchedGroundQuads[4100] = PlanePrefab.copyModel().scaleVerticesAndUV(new Vector3(1, 1, 2)).rotateVertices(new Vector3(0,0,90)).translateVertices(new Vector3(1f, 0.5F, 0)).setColor(new Vector4(0.65F, 0.65F, 0.65F, 1.0F)); + groundModel = QuadBatcher.batchQuadModels(unbatchedGroundQuads, terrainShaderName, "sand.png"); //build negZ wall @@ -153,7 +151,7 @@ private void buildSkyBox() } - wallsModel = QuadBatcher.batchQuadModels(unbatchedWallQuads, QuadPrefab.getShaderDir(), wallTextureDir); + wallsModel = QuadBatcher.batchQuadModels(unbatchedWallQuads, terrainShaderName, wallTextureName); //adding all world collider planes this.addWorldCollider(new PlaneCollider(new Vector3(0, 1, 0), groundHeight));//ground plane at y groundHeight, facing positive Y this.addWorldCollider(new PlaneCollider(new Vector3(0,0,1), -playgroundLength / 2));//Wall at negZ, playgroundLength / 2 units away, facing pos Z @@ -191,13 +189,9 @@ public void onFrame() private void tickEntities() { - for (int i = 0; i < entities.Count; i++) - { - entities.Values.ElementAt(i).preTick(); - } - for (int i = 0; i < entities.Count; i++) { + entities.Values.ElementAt(i).preTick(); entities.Values.ElementAt(i).onTick(); } @@ -356,5 +350,9 @@ public int getEntityCount() { return entities.Count; } + public int getVFXCount() + { + return vfxList.Count; + } } }