Merge pull request 'framebufferBugHunt' (#3) from framebufferBugHunt into master
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

Fix opengl state caching framebuffer in junit context, integrate par_shapes, work on directed graph implementation
This commit is contained in:
railgun 2024-09-09 12:48:32 -04:00
commit be229ffeed
30 changed files with 927 additions and 157 deletions

View File

@ -1,3 +1,3 @@
#maven.buildNumber.plugin properties file
#Wed Sep 04 09:33:29 EDT 2024
buildNumber=320
#Sun Sep 08 21:41:56 EDT 2024
buildNumber=325

View File

@ -693,6 +693,16 @@ Update human collidable data
(09/05/2024)
Fix AI tracking deleted entity
(09/06/2024)
work on debugging framebuffer bug
(09/07/2024)
par_shapes integration
(09/08/2024)
Directed graph datastructure
Framebuffer + RenderingEngine tests
# TODO

14
pom.xml
View File

@ -125,6 +125,20 @@
<version>${lwjgl.version}</version>
<classifier>${lwjgl.natives}</classifier>
</dependency>
<!--par_shapes-->
<!--License: MIT-->
<dependency>
<groupId>org.lwjgl</groupId>
<artifactId>lwjgl-par</artifactId>
<version>${lwjgl.version}</version>
</dependency>
<dependency>
<groupId>org.lwjgl</groupId>
<artifactId>lwjgl-par</artifactId>
<version>${lwjgl.version}</version>
<classifier>${lwjgl.natives}</classifier>
</dependency>
<!--JOML-->
<!--License: MIT-->

View File

@ -602,13 +602,9 @@ public class Globals {
//init fluid shader program
FluidChunkModelGeneration.fluidChunkShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/entities/fluid2/fluid2.vs", "/Shaders/entities/fluid2/fluid2.fs");
//init models
assetManager.addModelPathToQueue("Models/basic/geometry/unitsphere.glb");
assetManager.addModelPathToQueue("Models/basic/geometry/unitsphere.fbx");
assetManager.addModelPathToQueue("Models/basic/geometry/unitsphere_1.fbx");
assetManager.addModelPathToQueue("Models/basic/geometry/unitsphere_grey.fbx");
assetManager.registerModelToSpecificString(RenderUtils.createUnitsphere(), AssetDataStrings.UNITSPHERE);
assetManager.registerModelToSpecificString(RenderUtils.createUnitCylinder(), AssetDataStrings.UNITCYLINDER);
assetManager.addModelPathToQueue("Models/basic/geometry/SmallCube.fbx");
assetManager.addModelPathToQueue("Models/basic/geometry/unitcylinder.fbx");
assetManager.addModelPathToQueue("Models/basic/geometry/unitcylinder.glb");
assetManager.addModelPathToQueue("Models/basic/geometry/unitcapsule.glb");
assetManager.addModelPathToQueue("Models/basic/geometry/unitplane.fbx");
assetManager.addModelPathToQueue("Models/basic/geometry/unitcube.fbx");
@ -673,6 +669,12 @@ public class Globals {
Globals.server = null;
Globals.serverSynchronizationManager = null;
Globals.javaPID = null;
Globals.RENDER_FLAG_RENDER_SHADOW_MAP = true;
Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT = false;
Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER = false;
Globals.RENDER_FLAG_RENDER_UI = false;
Globals.RENDER_FLAG_RENDER_BLACK_BACKGROUND = false;
Globals.RENDER_FLAG_RENDER_WHITE_BACKGROUND = false;
LoggerInterface.destroyLoggers();
}

View File

@ -156,7 +156,7 @@ public class Main {
Globals.controlHandler.hintUpdateControlState(ControlsState.TITLE_MENU);
//start initial asset loading
Globals.threadManager.start(ThreadLabel.ASSET_LOADING, new Thread(Globals.initialAssetLoadingThread));
Globals.threadManager.start(new LoadingThread(LoadingThreadType.INIT_ASSETS));
}
//Sets a hook that fires when the engine process stops
@ -434,8 +434,6 @@ public class Main {
//
//Terminate the program.
if(Globals.renderingEngine != null){
glfwTerminate();
Globals.renderingEngine.clearGlobalState();
Globals.renderingEngine.destroy();
}
//used to signal threads to stop

View File

@ -8,4 +8,12 @@ public class AssetDataStrings {
public static final String ASSET_STRING_SKYBOX_BASIC = "skyboxBasic";
public static final String BITMAP_CHARACTER_MODEL = "bitmapCharacterModel";
public static final String LEAVES_MODEL = "leaves";
/**
* The basic geometry of the engine
*/
public static final String UNITSPHERE = "unitSphere";
public static final String UNITCYLINDER = "unitCylinder";
}

View File

@ -11,6 +11,7 @@ import electrosphere.client.targeting.crosshair.Crosshair;
import electrosphere.client.terrain.cells.DrawCellManager;
import electrosphere.controls.ControlHandler;
import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.engine.signal.Signal.SignalType;
import electrosphere.engine.threads.LabeledThread.ThreadLabel;
import electrosphere.entity.DrawableUtils;
@ -244,7 +245,7 @@ public class ClientLoading {
//player's cursor
Globals.playerCursor = EntityCreationUtils.createClientSpatialEntity();
EntityCreationUtils.makeEntityDrawable(Globals.playerCursor, "Models/basic/geometry/unitsphere_1.fbx");
EntityCreationUtils.makeEntityDrawable(Globals.playerCursor, AssetDataStrings.UNITSPHERE);
DrawableUtils.makeEntityTransparent(Globals.playerCursor);
EntityUtils.getScale(Globals.playerCursor).set(30f);
}
@ -257,7 +258,7 @@ public class ClientLoading {
*/
static void initDrawCellManager(boolean blockForInit){
int iterations = 0;
while(blockForInit && (Globals.clientWorldData == null || Globals.initialAssetLoadingThread.isLoading())){
while(blockForInit && (Globals.clientWorldData == null || InitialAssetLoading.atlasQueuedTexture == null || !InitialAssetLoading.atlasQueuedTexture.hasLoaded())){
try {
TimeUnit.MILLISECONDS.sleep(10);
iterations++;
@ -267,7 +268,7 @@ public class ClientLoading {
if(iterations > MAX_DRAW_CELL_WAIT){
String message = "Draw cell took too long to init!\n" +
Globals.clientWorldData + "\n" +
Globals.initialAssetLoadingThread.isLoading();
InitialAssetLoading.atlasQueuedTexture.hasLoaded();
throw new IllegalStateException(message);
}
}

View File

@ -21,35 +21,27 @@ import electrosphere.util.FileUtils;
* - Texture Atlas for terrain
* - Icons for items
*/
public class InitialAssetLoading implements Runnable {
//tracks whether this thread is still doing work or not
boolean loading = true;
public class InitialAssetLoading {
/**
* The queued atlas texture
*/
static QueuedTexture atlasQueuedTexture = null;
/**
* Loads basic data
*/
public void LoadData(){
protected static void loadData(){
loadTextureAtlas();
LoggerInterface.loggerEngine.INFO("Finished loading texture atlas");
loading = false;
}
/**
* Gets whether the thread is still loading or not
* @return true if loading, false otherwise
*/
public boolean isLoading(){
return loading;
}
/**
* Loads the texture atlas
*/
private void loadTextureAtlas(){
private static void loadTextureAtlas(){
//terrain texture atlas
Globals.profiler.beginCpuSample("createVoxelTextureAtlas");
VoxelData data = Globals.gameConfigCurrent.getVoxelData();
@ -78,7 +70,7 @@ public class InitialAssetLoading implements Runnable {
Globals.profiler.endCpuSample();
//queue to asset manager
QueuedTexture atlasQueuedTexture = new QueuedTexture(image);
atlasQueuedTexture = new QueuedTexture(image);
Globals.assetManager.queuedAsset(atlasQueuedTexture);
@ -97,10 +89,12 @@ public class InitialAssetLoading implements Runnable {
Globals.voxelTextureAtlas.setNormal(atlasQueuedTexture.getTexture());
}
@Override
public void run(){
this.LoadData();
/**
* Gets the queued texture
*/
protected static QueuedTexture getQueuedTexture(){
return atlasQueuedTexture;
}
}

View File

@ -65,6 +65,11 @@ public class LoadingThread extends Thread {
*/
LOAD_VIEWPORT,
/**
* Loads initial assets
*/
INIT_ASSETS,
}
/**
@ -152,6 +157,11 @@ public class LoadingThread extends Thread {
case LOAD_VIEWPORT: {
ViewportLoading.loadViewport(params);
} break;
//Load the initial assets
case INIT_ASSETS: {
InitialAssetLoading.loadData();
} break;
}
}

View File

@ -10,7 +10,8 @@ import org.lwjgl.util.remotery.Remotery;
public class Profiler {
//controls whether to profile or not
public static boolean PROFILE = true;
//!!WARNING!!: when this is turned on, testing can behave weirdly!! IE GET STUCK!
public static boolean PROFILE = false;
//pointer to the global instance
long pointer = -1;

View File

@ -111,8 +111,7 @@ public class ThreadManager {
if(thread.getThread().isAlive()){
String errorMessage = "Failed to interrupt thread! " + thread.getLabel();
System.err.println(errorMessage);
new IllegalStateException().printStackTrace();
System.exit(1);
throw new IllegalStateException();
}
} catch (InterruptedException e) {
CodeUtils.todo(e, "Think about how to handle this");

View File

@ -21,44 +21,62 @@ public class OpenGLState {
private static final boolean DISABLE_CACHING = false;
//the max texture allowed by the current environment
int MAX_TEXTURE_WIDTH = 0;
int MAX_TEXTURE_WIDTH;
//the current viewport dimensions
private Vector2i viewport = new Vector2i(0,0);
private Vector2i viewport;
//whether depth test is enabled or not
boolean depthTest = false;
boolean depthTest;
//the current depth function
int depthFunction = -1;
int depthFunction;
//whether to blend or nit
boolean blendTest = false;
boolean blendTest;
//the current blend func
//map is (texture unit) -> [sfactor,dfactor]
Map<Integer,int[]> blendFuncMap = new HashMap<Integer,int[]>();
Map<Integer,int[]> blendFuncMap;
//the key that contains the value of glBlendFunc (which would affect all buffers)
static final int ALL_BUFFERS_KEY = -1;
//the currently active texture
int activeTexture = 0;
int activeTexture;
//the currently bound framebuffer
int framebufferType = 0;
int framebufferPointer = 0;
int framebufferType;
int framebufferPointer;
//active shader
ShaderProgram activeShader = null;
ShaderProgram activeShader;
//map of texture units and their corresponding texture pointers
Map<Integer,Integer> unitToPointerMap = new HashMap<Integer,Integer>();
Map<Integer,Integer> unitToPointerMap;
/**
* Initializes the opengl state
*/
public void init(){
this.MAX_TEXTURE_WIDTH = 0;
this.viewport = new Vector2i(0,0);
this.depthTest = false;
this.depthFunction = -1;
this.blendTest = false;
this.blendFuncMap = new HashMap<Integer,int[]>();
activeTexture = 0;
framebufferType = 0;
framebufferPointer = 0;
activeShader = null;
unitToPointerMap = new HashMap<Integer,Integer>();
this.storeCurrentEnvironmentContraints();
}
/**
* Gets the constraints of the current environment (ie how large can the max texture be)
*/
public void storeCurrentEnvironmentContraints(){
private void storeCurrentEnvironmentContraints(){
//the array used to store values fetched from opengl
int[] intFetchArray = new int[1];
@ -67,6 +85,9 @@ public class OpenGLState {
GL40.glGetIntegerv(GL40.GL_MAX_TEXTURE_SIZE, intFetchArray);
MAX_TEXTURE_WIDTH = intFetchArray[0];
//get current framebuffer data
GL40.glGetIntegerv(GL40.GL_DRAW_FRAMEBUFFER_BINDING, intFetchArray);
this.framebufferPointer = intFetchArray[0];
}
@ -153,6 +174,21 @@ public class OpenGLState {
}
}
/**
* Binds a texture to a given texture unit if the texture hasn't already been bound to that unit
* @param textureUnit The texture unit
* @param texturePointer The texture pointer
* @param textureType the type of texture (2d, 3d, etc)
*/
public void glBindTextureUnitForce(int textureUnit, int texturePointer, int textureType){
unitToPointerMap.put(textureUnit,texturePointer);
this.activeTexture = textureUnit;
GL40.glActiveTexture(this.activeTexture);
Globals.renderingEngine.checkError();
GL40.glBindTexture(textureType,texturePointer);
Globals.renderingEngine.checkError();
}
/**
* Binds a framebuffer
* @param framebufferType the type of framebuffer (vanilla, renderbuffer, etc)

View File

@ -20,6 +20,8 @@ import org.lwjgl.BufferUtils;
import static org.lwjgl.opengl.GL11.GL_FLOAT;
import org.lwjgl.opengl.GL40;
import org.lwjgl.util.par.ParShapes;
import org.lwjgl.util.par.ParShapesMesh;
/**
* Utilities to assist with rendering
@ -339,6 +341,64 @@ public class RenderUtils {
return rVal;
}
/**
* Generates a unit sphere model
* @return The model
*/
public static Model createUnitsphere(){
Model model = new Model();
Mesh sphereMesh = new Mesh("sphere");
sphereMesh.generateVAO();
//buffer coords
ParShapesMesh data = ParShapes.par_shapes_create_parametric_sphere(10, 5);
int numPoints = data.npoints();
FloatBuffer verts = data.points(numPoints * 3);
sphereMesh.bufferVertices(verts, 3);
FloatBuffer texCoords = data.tcoords(numPoints * 3);
sphereMesh.bufferTextureCoords(texCoords, 2);
//setup extra structures
Material mat = new Material();
mat.set_diffuse("Textures/color/transparent_teal.png");
sphereMesh.setMaterial(mat);
sphereMesh.setShader(ShaderProgram.smart_assemble_shader(false, true));
GL40.glBindVertexArray(0);
sphereMesh.setParent(model);
model.getMeshes().add(sphereMesh);
return model;
}
/**
* Creates a unit cylinder model
* @return The model
*/
public static Model createUnitCylinder(){
Model model = new Model();
Mesh sphereMesh = new Mesh("cylinder");
sphereMesh.generateVAO();
//buffer coords
ParShapesMesh data = ParShapes.par_shapes_create_cylinder(10, 2);
int numPoints = data.npoints();
FloatBuffer verts = data.points(numPoints * 3);
sphereMesh.bufferVertices(verts, 3);
FloatBuffer texCoords = data.tcoords(numPoints * 2);
sphereMesh.bufferTextureCoords(texCoords, 2);
//setup extra structures
Material mat = new Material();
mat.set_diffuse("Textures/color/transparent_teal.png");
sphereMesh.setMaterial(mat);
sphereMesh.setShader(ShaderProgram.smart_assemble_shader(false, true));
GL40.glBindVertexArray(0);
sphereMesh.setParent(model);
model.getMeshes().add(sphereMesh);
return model;
}
@Deprecated
public static Model createBitmapDisplay(){

View File

@ -38,6 +38,10 @@ import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GL45;
import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.opengl.GLDebugMessageCallback;
import org.lwjgl.system.MemoryStack;
import electrosphere.engine.Globals;
import electrosphere.logger.LoggerInterface;
@ -186,12 +190,18 @@ public class RenderingEngine {
//
//set error callback
GLFW.glfwSetErrorCallback(GLFWErrorCallback.createThrow());
// GLFWErrorCallback
GLFW.glfwSetErrorCallback((int error, long descriptionPtr) -> {
String description = GLFWErrorCallback.getDescription(descriptionPtr);
System.err.println(description);
});
//Initializes opengl
boolean glfwInited = glfwInit();
if(!glfwInited){
throw new IllegalStateException("Failed to initialize glfw!");
String message = "Failed to initialize glfw!\n" +
"Error code: " + this.getGLFWErrorMessage(this.getGLFWError());
throw new IllegalStateException(message);
}
//Gives hints to glfw to control how opengl will be used
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
@ -216,9 +226,13 @@ public class RenderingEngine {
}
// Errors for failure to create window (IE: No GUI mode on linux ?)
if (Globals.window == NULL) {
LoggerInterface.loggerEngine.ERROR("Failed to make window.", new Exception("Renderer Creation Failure"));
String message = "Failed to create window!\n" +
"Error code: " + this.getGLFWErrorMessage(this.getGLFWError());
;
LoggerInterface.loggerEngine.ERROR(new Exception(message));
glfwTerminate();
}
//set resize callback
GLFW.glfwSetWindowSizeCallback(Globals.window, (long window, int width, int height) -> {
Globals.WINDOW_HEIGHT = height;
@ -228,6 +242,7 @@ public class RenderingEngine {
glfwMakeContextCurrent(Globals.window);
//Maximize it
glfwMaximizeWindow(Globals.window);
GLFW.glfwPollEvents();
//grab actual framebuffer
IntBuffer xBuffer = BufferUtils.createIntBuffer(1);
IntBuffer yBuffer = BufferUtils.createIntBuffer(1);
@ -255,11 +270,20 @@ public class RenderingEngine {
//get title bar dimensions
// setTitleBarDimensions();
//Creates the OpenGL capabilities for the program.
GL.createCapabilities();
//Creates the OpenGL capabilities for the program.)
GLCapabilities glCapabilities = GL.createCapabilities();
GL45.glEnable(GL45.GL_DEBUG_OUTPUT);
//register error callback
GL45.glDebugMessageCallback((int source, int type, int id, int severity, int length, long messagePtr, long userParam) -> {
if(type == GL45.GL_DEBUG_TYPE_ERROR){
String message = GLDebugMessageCallback.getMessage(length, messagePtr);
System.err.println(message);
}
}, bufferHeight);
//get environment constraints
openGLState.storeCurrentEnvironmentContraints();
openGLState.init();
//init imgui pipeline
imGuiPipeline = new ImGuiPipeline(Globals.window, glslVersion);
@ -290,11 +314,20 @@ public class RenderingEngine {
//default framebuffer
defaultFramebuffer = new Framebuffer(GL_DEFAULT_FRAMEBUFFER);
defaultFramebuffer.bind(openGLState);
//generate framebuffers
screenTextureColor = FramebufferUtils.generateScreenTextureColorAlpha(openGLState, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
screenTextureDepth = FramebufferUtils.generateScreenTextureDepth(openGLState, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
screenFramebuffer = FramebufferUtils.generateScreenTextureFramebuffer(openGLState, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, screenTextureColor, screenTextureDepth);
Texture screenTextureColor = FramebufferUtils.generateScreenTextureColorAlpha(openGLState, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
RenderingEngine.screenTextureColor = screenTextureColor;
Texture screenTextureDepth = FramebufferUtils.generateScreenTextureDepth(openGLState, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
RenderingEngine.screenTextureDepth = screenTextureDepth;
try {
Framebuffer screenFramebuffer = FramebufferUtils.generateScreenTextureFramebuffer(openGLState, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, screenTextureColor, screenTextureDepth);
RenderingEngine.screenFramebuffer = screenFramebuffer;
} catch (Exception e){
LoggerInterface.loggerRenderer.ERROR(e);
}
defaultFramebuffer.bind(openGLState);
glBindRenderbuffer(GL_RENDERBUFFER, GL_DEFAULT_RENDERBUFFER);
Globals.renderingEngine.checkError();
@ -309,18 +342,28 @@ public class RenderingEngine {
//
lightDepthShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/core/lightDepth/lightDepth.vs", "/Shaders/core/lightDepth/lightDepth.fs");
Globals.depthMapShaderProgramLoc = lightDepthShaderProgram.getShaderId();
lightDepthBuffer = FramebufferUtils.generateDepthBuffer(openGLState);
lightBufferDepthTexture = lightDepthBuffer.getDepthTexture();
try {
Framebuffer lightDepthBuffer = FramebufferUtils.generateDepthBuffer(openGLState);
RenderingEngine.lightDepthBuffer = lightDepthBuffer;
} catch(Exception e){
LoggerInterface.loggerRenderer.ERROR(e);
}
Texture lightBufferDepthTexture = lightDepthBuffer.getDepthTexture();
RenderingEngine.lightBufferDepthTexture = lightBufferDepthTexture;
// glEnable(GL_CULL_FACE); // enabled for shadow mapping
//
//create volume depth framebuffer/shader for volumetric rendering
//
volumeDepthShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/core/volumeBuffer/volumetric.vs", "/Shaders/core/volumeBuffer/volumetric.fs");
volumeDepthBackfaceTexture = FramebufferUtils.generateDepthBufferTexture(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY());
volumeDepthBackfaceFramebuffer = FramebufferUtils.generateDepthBuffer(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY(), volumeDepthBackfaceTexture);
volumeDepthFrontfaceTexture = FramebufferUtils.generateDepthBufferTexture(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY());
volumeDepthFrontfaceFramebuffer = FramebufferUtils.generateDepthBuffer(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY(), volumeDepthFrontfaceTexture);
try {
volumeDepthShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/core/volumeBuffer/volumetric.vs", "/Shaders/core/volumeBuffer/volumetric.fs");
volumeDepthBackfaceTexture = FramebufferUtils.generateDepthBufferTexture(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY());
volumeDepthBackfaceFramebuffer = FramebufferUtils.generateDepthBuffer(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY(), volumeDepthBackfaceTexture);
volumeDepthFrontfaceTexture = FramebufferUtils.generateDepthBufferTexture(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY());
volumeDepthFrontfaceFramebuffer = FramebufferUtils.generateDepthBuffer(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY(), volumeDepthFrontfaceTexture);
} catch(Exception e){
LoggerInterface.loggerRenderer.ERROR(e);
}
//
//Game normals
@ -330,20 +373,28 @@ public class RenderingEngine {
static Framebuffer gameImageNormalsFramebuffer;
static ShaderProgram renderNormalsShader;
*/
gameImageNormalsTexture = FramebufferUtils.generateScreenTextureColorAlpha(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY());
Texture gameImageNormalsDepthTexture = FramebufferUtils.generateScreenTextureDepth(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY());
gameImageNormalsFramebuffer = FramebufferUtils.generateScreenTextureFramebuffer(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY(), gameImageNormalsTexture, gameImageNormalsDepthTexture);
renderNormalsShader = ShaderProgram.loadSpecificShader("Shaders/core/anime/renderNormals.vs", "Shaders/core/anime/renderNormals.fs");
try {
gameImageNormalsTexture = FramebufferUtils.generateScreenTextureColorAlpha(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY());
Texture gameImageNormalsDepthTexture = FramebufferUtils.generateScreenTextureDepth(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY());
gameImageNormalsFramebuffer = FramebufferUtils.generateScreenTextureFramebuffer(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY(), gameImageNormalsTexture, gameImageNormalsDepthTexture);
renderNormalsShader = ShaderProgram.loadSpecificShader("Shaders/core/anime/renderNormals.vs", "Shaders/core/anime/renderNormals.fs");
} catch(Exception e){
LoggerInterface.loggerRenderer.ERROR(e);
}
//
//Transparency framebuffers
//
transparencyAccumulatorClear = new float[]{0.0f, 0.0f, 0.0f, 0.0f};
transparencyAccumulatorTexture = FramebufferUtils.generateOITAccumulatorTexture(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY());
transparencyRevealageClear = new float[]{1.0f, 1.0f, 1.0f, 1.0f};
transparencyRevealageTexture = FramebufferUtils.generateOITRevealageTexture(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY());
transparencyBuffer = FramebufferUtils.generateOITFramebuffer(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY(), transparencyAccumulatorTexture, transparencyRevealageTexture, screenTextureDepth);
oitCompositeProgram = ShaderProgram.loadSpecificShader("Shaders/core/oit/composite.vs", "Shaders/core/oit/composite.fs");
try {
transparencyAccumulatorClear = new float[]{0.0f, 0.0f, 0.0f, 0.0f};
transparencyAccumulatorTexture = FramebufferUtils.generateOITAccumulatorTexture(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY());
transparencyRevealageClear = new float[]{1.0f, 1.0f, 1.0f, 1.0f};
transparencyRevealageTexture = FramebufferUtils.generateOITRevealageTexture(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY());
transparencyBuffer = FramebufferUtils.generateOITFramebuffer(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY(), transparencyAccumulatorTexture, transparencyRevealageTexture, screenTextureDepth);
oitCompositeProgram = ShaderProgram.loadSpecificShader("Shaders/core/oit/composite.vs", "Shaders/core/oit/composite.fs");
} catch(Exception e){
LoggerInterface.loggerRenderer.ERROR(e);
}
//projection matrices
nearVolumeProjectionMatrix.setPerspective((float)(Globals.verticalFOV * Math.PI /180.0f), (float)Globals.WINDOW_WIDTH / (float)Globals.WINDOW_HEIGHT, 0.1f, 100);
@ -356,10 +407,14 @@ public class RenderingEngine {
static Framebuffer normalsOutlineFrambuffer;
static ShaderProgram normalsOutlineShader;
*/
normalsOutlineTexture = FramebufferUtils.generateScreenTextureColorAlpha(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY());
normalsOutlineFrambuffer = FramebufferUtils.generateScreenTextureFramebuffer(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY(), normalsOutlineTexture);
// normalsOutlineShader = ShaderProgram.loadSpecificShader("Shaders/anime/outlineNormals.vs", "Shaders/anime/outlineNormals.fs");
Globals.assetManager.addShaderToQueue("Shaders/core/anime/outlineNormals.vs", "Shaders/core/anime/outlineNormals.fs");
try {
normalsOutlineTexture = FramebufferUtils.generateScreenTextureColorAlpha(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY());
normalsOutlineFrambuffer = FramebufferUtils.generateScreenTextureFramebuffer(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY(), normalsOutlineTexture);
// normalsOutlineShader = ShaderProgram.loadSpecificShader("Shaders/anime/outlineNormals.vs", "Shaders/anime/outlineNormals.fs");
Globals.assetManager.addShaderToQueue("Shaders/core/anime/outlineNormals.vs", "Shaders/core/anime/outlineNormals.fs");
} catch(Exception e){
LoggerInterface.loggerRenderer.ERROR(e);
}
//
//Compositing shaders
@ -409,15 +464,6 @@ public class RenderingEngine {
Globals.projectionMatrix.setPerspective(verticalFOV, Globals.aspectRatio, nearClip, Globals.userSettings.getGraphicsViewDistance());
Globals.viewMatrix.translation(new Vector3f(0.0f,0.0f,-3.0f));
}
/**
* Clears global, static state
*/
public void clearGlobalState(){
screenTextureColor = null;
screenTextureDepth = null;
screenFramebuffer = null;
}
/**
@ -637,7 +683,7 @@ public class RenderingEngine {
public boolean checkError(){
int error = this.getError();
if(error != GL11.GL_NO_ERROR){
LoggerInterface.loggerRenderer.ERROR("checkError - " + getErrorInEnglish(error), new IllegalStateException("OpenGL Error"));
LoggerInterface.loggerRenderer.ERROR("checkError - " + getErrorInEnglish(error), new Exception("OpenGL Error"));
return true;
}
return false;
@ -656,6 +702,34 @@ public class RenderingEngine {
return lastCode;
}
/**
* Gets the most recent GLFW Error
* @return The most recent GLFW error
*/
public int getGLFWError(){
int lastCode = 0;
try (MemoryStack stack = MemoryStack.stackPush()){
lastCode = GLFW.glfwGetError(stack.callocPointer(1));
}
return lastCode;
}
/**
* Decodes the glfw error code
* @param code The code
* @return The decoded message
*/
public String getGLFWErrorMessage(int code){
switch(code){
case GLFW.GLFW_INVALID_ENUM:
return "GLFW_INVALID_ENUM";
case GLFW.GLFW_INVALID_VALUE:
return "GLFW_INVALID_VALUE";
default:
return "Unhandled value!";
}
}
/**
* Checks if pipelines should run
* @return true if should render, false otherwise
@ -671,7 +745,83 @@ public class RenderingEngine {
* Destroys the rendering engine
*/
public void destroy(){
//free framebuffers
if(screenFramebuffer != null){
screenFramebuffer.free();
}
if(screenRenderbuffer != null){
screenRenderbuffer.free();
}
if(gameImageNormalsFramebuffer != null){
gameImageNormalsFramebuffer.free();
}
if(lightDepthBuffer != null){
lightDepthBuffer.free();
}
if(transparencyBuffer != null){
transparencyBuffer.free();
}
if(volumeDepthBackfaceFramebuffer != null){
volumeDepthBackfaceFramebuffer.free();
}
if(volumeDepthFrontfaceFramebuffer != null){
volumeDepthFrontfaceFramebuffer.free();
}
if(normalsOutlineFrambuffer != null){
normalsOutlineFrambuffer.free();
}
//null out
screenFramebuffer = null;
screenRenderbuffer = null;
gameImageNormalsFramebuffer = null;
lightDepthBuffer = null;
transparencyBuffer = null;
volumeDepthBackfaceFramebuffer = null;
volumeDepthFrontfaceFramebuffer = null;
normalsOutlineFrambuffer = null;
//free textures
if(screenTextureColor != null){
screenTextureColor.free();
}
if(screenTextureDepth != null){
screenTextureDepth.free();
}
if(gameImageNormalsTexture != null){
gameImageNormalsTexture.free();
}
if(lightBufferDepthTexture != null){
lightBufferDepthTexture.free();
}
if(transparencyRevealageTexture != null){
transparencyRevealageTexture.free();
}
if(volumeDepthBackfaceTexture != null){
volumeDepthBackfaceTexture.free();
}
if(volumeDepthFrontfaceTexture != null){
volumeDepthFrontfaceTexture.free();
}
if(normalsOutlineTexture != null){
normalsOutlineTexture.free();
}
//null out
screenTextureColor = null;
screenTextureDepth = null;
gameImageNormalsTexture = null;
lightBufferDepthTexture = null;
transparencyRevealageTexture = null;
volumeDepthBackfaceTexture = null;
volumeDepthFrontfaceTexture = null;
normalsOutlineTexture = null;
//end glfw
GLFW.glfwDestroyWindow(Globals.window);
GLFW.glfwTerminate();
}
/**

View File

@ -14,8 +14,12 @@ import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.lwjgl.opengl.GL40;
import org.lwjgl.opengl.GL45;
import org.lwjgl.system.MemoryUtil;
import static org.lwjgl.opengl.GL11.GL_NONE;
import static org.lwjgl.opengl.GL11.GL_TEXTURE;
import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER;
import static org.lwjgl.opengl.GL45.glCheckNamedFramebufferStatus;
/**
@ -91,29 +95,47 @@ public class Framebuffer {
* Checks if the framebuffer compiled correctly
* @return true if compiled correctly, false otherwise
*/
public boolean isComplete(){
return glCheckNamedFramebufferStatus(framebufferPointer,GL40.GL_FRAMEBUFFER) == GL40.GL_FRAMEBUFFER_COMPLETE;
public boolean isComplete(OpenGLState openGLState){
if(this.framebufferPointer == DEFAULT_FRAMEBUFFER_POINTER){
throw new Error("Pointer is the default framebuffer!");
}
return glCheckNamedFramebufferStatus(this.framebufferPointer,GL40.GL_FRAMEBUFFER) == GL40.GL_FRAMEBUFFER_COMPLETE;
}
/**
* Checks if the framebuffer has an error
* @return true if error, false otherwise
*/
public boolean isError(){
return glCheckNamedFramebufferStatus(framebufferPointer,GL40.GL_FRAMEBUFFER) == 0;
}
/**
* Checks the status of the framebuffer
* @param openGLState The opengl state
* @throws Exception
*/
public void checkStatus(){
if(this.isError()){
LoggerInterface.loggerRenderer.WARNING("Framebuffer [glError] - " + RenderingEngine.getErrorInEnglish(Globals.renderingEngine.getError()));
LoggerInterface.loggerRenderer.WARNING("Framebuffer [status] - " + this.getStatus());
} else if(!this.isComplete()){
LoggerInterface.loggerRenderer.WARNING("Framebuffer [glError] - " + RenderingEngine.getErrorInEnglish(Globals.renderingEngine.getError()));
LoggerInterface.loggerRenderer.WARNING("Framebuffer [status] - " + this.getStatus());
LoggerInterface.loggerRenderer.ERROR("Failed to build framebuffer", new IllegalStateException("Framebuffer failed to build."));
public void shouldBeComplete(OpenGLState openGLState) throws Exception{
if(!this.isComplete(openGLState)){
int colorAttach0 = GL45.glGetFramebufferAttachmentParameteri(GL_FRAMEBUFFER, GL45.GL_COLOR_ATTACHMENT0, GL45.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
String attach0Type = "";
switch(colorAttach0){
case GL_NONE: {
attach0Type = "GL_NONE";
} break;
case GL_TEXTURE: {
attach0Type = " GL_TEXTURE";
} break;
}
this.texture.bind(openGLState);
int[] storage = new int[1];
int width = 0;
int height = 0;
GL45.glGetTexLevelParameteriv(GL45.GL_TEXTURE_2D, 0, GL45.GL_TEXTURE_WIDTH, storage);
width = storage[0];
GL45.glGetTexLevelParameteriv(GL45.GL_TEXTURE_2D, 0, GL45.GL_TEXTURE_HEIGHT, storage);
height = storage[0];
String message = "Framebuffer failed to build.\n" +
"Framebuffer [status] - " + this.getStatus() + "\n" +
"Texture: " + this.texture + "\n" +
"attach0Type: " + attach0Type + "\n" +
"attach0 Dims: " + width + "," + height + "\n" +
"Depth: " + this.depthTexture + "\n"
;
throw new Exception(message);
}
}
@ -136,7 +158,7 @@ public class Framebuffer {
* Blocks the thread until the framebuffer has compiled
*/
public void blockUntilCompiled(){
while(glCheckNamedFramebufferStatus(framebufferPointer,GL40.GL_FRAMEBUFFER) != GL40.GL_FRAMEBUFFER_UNDEFINED){
while(glCheckNamedFramebufferStatus(this.framebufferPointer,GL40.GL_FRAMEBUFFER) != GL40.GL_FRAMEBUFFER_UNDEFINED){
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException ex) {
@ -150,7 +172,7 @@ public class Framebuffer {
* @return The status
*/
public String getStatus(){
switch(glCheckNamedFramebufferStatus(framebufferPointer,GL40.GL_FRAMEBUFFER)){
switch(glCheckNamedFramebufferStatus(this.framebufferPointer,GL40.GL_FRAMEBUFFER)){
case GL40.GL_FRAMEBUFFER_UNDEFINED: {
return "The specified framebuffer is the default read or draw framebuffer, but the default framebuffer does not exist.";
}
@ -220,6 +242,15 @@ public class Framebuffer {
openGLState.glBindFramebuffer(GL40.GL_FRAMEBUFFER, this.framebufferPointer);
GL40.glFramebufferTexture2D(GL40.GL_FRAMEBUFFER, GL40.GL_COLOR_ATTACHMENT0 + attachmentNum, GL40.GL_TEXTURE_2D, texture.getTexturePointer(), 0);
Globals.renderingEngine.checkError();
// check the attachment slot
int colorAttach0 = GL45.glGetFramebufferAttachmentParameteri(GL40.GL_FRAMEBUFFER, GL45.GL_COLOR_ATTACHMENT0 + attachmentNum, GL45.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
switch(colorAttach0){
case GL_NONE: {
throw new Error("Failed to attach!");
}
case GL_TEXTURE: {
} break;
}
Globals.renderingEngine.defaultFramebuffer.bind(openGLState);
}

View File

@ -9,6 +9,7 @@ import java.nio.IntBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL40;
import org.lwjgl.opengl.GL45;
import static org.lwjgl.opengl.GL11.GL_DEPTH_COMPONENT;
import static org.lwjgl.opengl.GL11.GL_FLOAT;
@ -46,6 +47,7 @@ public class FramebufferUtils {
public static Texture generateScreenTextureColor(OpenGLState openGLState, int width, int height){
Texture texture = new Texture();
texture.bind(openGLState);
texture.glTexImage2D(openGLState, width, height, GL_RGB, GL_UNSIGNED_BYTE);
texture.setMinFilter(openGLState, GL_LINEAR);
texture.setMagFilter(openGLState, GL_LINEAR);
@ -64,7 +66,8 @@ public class FramebufferUtils {
public static Texture generateScreenTextureColorAlpha(OpenGLState openGLState, int width, int height){
Texture texture = new Texture();
texture.glTexImage2D(openGLState, width, height, GL_RGBA, GL_UNSIGNED_BYTE);
texture.bind(openGLState);
texture.glTexImage2D(openGLState, width, height, GL_RGBA, GL45.GL_UNSIGNED_INT_8_8_8_8);
texture.setMinFilter(openGLState, GL_LINEAR);
texture.setMagFilter(openGLState, GL_LINEAR);
//these make sure the texture actually clamps to the borders of the quad
@ -74,7 +77,7 @@ public class FramebufferUtils {
//guarantees that the texture object has actually been created (calling gen buffers does not guarantee object creation)
texture.bind(openGLState);
openGLState.glBindTexture(GL40.GL_TEXTURE_2D, Texture.DEFAULT_TEXTURE);
openGLState.glBindTextureUnitForce(GL45.GL_TEXTURE0, Texture.DEFAULT_TEXTURE, GL40.GL_TEXTURE_2D);
texture.checkStatus(openGLState);
return texture;
@ -82,6 +85,7 @@ public class FramebufferUtils {
public static Texture generateScreenTextureDepth(OpenGLState openGLState, int width, int height){
Texture texture = new Texture();
texture.bind(openGLState);
texture.glTexImage2D(openGLState, width, height, GL_DEPTH_COMPONENT, GL_FLOAT);
texture.setMinFilter(openGLState, GL_LINEAR);
@ -93,36 +97,37 @@ public class FramebufferUtils {
//guarantees that the texture object has actually been created (calling gen buffers does not guarantee object creation)
texture.bind(openGLState);
openGLState.glBindTexture(GL40.GL_TEXTURE_2D, Texture.DEFAULT_TEXTURE);
openGLState.glBindTextureUnitForce(GL45.GL_TEXTURE0, Texture.DEFAULT_TEXTURE, GL40.GL_TEXTURE_2D);
texture.checkStatus(openGLState);
return texture;
}
public static Framebuffer generateScreenTextureFramebuffer(OpenGLState openGLState, int width, int height, Texture colorTexture, Texture depthTexture){
public static Framebuffer generateScreenTextureFramebuffer(OpenGLState openGLState, int width, int height, Texture colorTexture, Texture depthTexture) throws Exception {
Framebuffer buffer = new Framebuffer();
//bind texture to fbo
buffer.setMipMapLevel(0);
buffer.attachTexture(openGLState,colorTexture);
buffer.setDepthAttachment(openGLState,depthTexture);
buffer.bind(openGLState);
//check make sure compiled
buffer.checkStatus();
buffer.shouldBeComplete(openGLState);
Globals.renderingEngine.defaultFramebuffer.bind(openGLState);
return buffer;
}
public static Framebuffer generateScreenTextureFramebuffer(OpenGLState openGLState, int width, int height, Texture colorTexture){
public static Framebuffer generateScreenTextureFramebuffer(OpenGLState openGLState, int width, int height, Texture colorTexture) throws Exception {
Framebuffer buffer = new Framebuffer();
//bind texture to fbo
buffer.setMipMapLevel(0);
buffer.attachTexture(openGLState,colorTexture);
//check make sure compiled
buffer.checkStatus();
buffer.shouldBeComplete(openGLState);
return buffer;
}
public static Framebuffer generateScreensizeTextureFramebuffer(OpenGLState openGLState){
public static Framebuffer generateScreensizeTextureFramebuffer(OpenGLState openGLState) throws Exception {
Framebuffer buffer = new Framebuffer();
buffer.bind(openGLState);
//texture
@ -147,12 +152,12 @@ public class FramebufferUtils {
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderBuffer);
Globals.renderingEngine.checkError();
//check make sure compiled
buffer.checkStatus();
buffer.shouldBeComplete(openGLState);
Globals.renderingEngine.defaultFramebuffer.bind(openGLState);
return buffer;
}
public static Framebuffer generateTextureFramebuffer(OpenGLState openGLState, int width, int height){
public static Framebuffer generateTextureFramebuffer(OpenGLState openGLState, int width, int height) throws Exception {
Framebuffer buffer = new Framebuffer();
buffer.bind(openGLState);
//texture
@ -178,7 +183,7 @@ public class FramebufferUtils {
GL40.glFramebufferRenderbuffer(GL40.GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderBuffer);
Globals.renderingEngine.checkError();
//check make sure compiled
buffer.checkStatus();
buffer.shouldBeComplete(openGLState);
//re-bind default buffer
Globals.renderingEngine.defaultFramebuffer.bind(openGLState);
return buffer;
@ -197,7 +202,7 @@ public class FramebufferUtils {
}
public static Framebuffer generateDepthBuffer(OpenGLState openGLState){
public static Framebuffer generateDepthBuffer(OpenGLState openGLState) throws Exception {
Framebuffer buffer = new Framebuffer();
buffer.bind(openGLState);
@ -223,7 +228,7 @@ public class FramebufferUtils {
//check make sure compiled
buffer.checkStatus();
buffer.shouldBeComplete(openGLState);
Globals.renderingEngine.defaultFramebuffer.bind(openGLState);
return buffer;
}
@ -241,7 +246,7 @@ public class FramebufferUtils {
return texture;
}
public static Framebuffer generateDepthBuffer(OpenGLState openGLState, int width, int height, Texture texture){
public static Framebuffer generateDepthBuffer(OpenGLState openGLState, int width, int height, Texture texture) throws Exception {
Framebuffer buffer = new Framebuffer();
buffer.bind(openGLState);
@ -257,7 +262,7 @@ public class FramebufferUtils {
//check make sure compiled
buffer.checkStatus();
buffer.shouldBeComplete(openGLState);
Globals.renderingEngine.defaultFramebuffer.bind(openGLState);
return buffer;
}
@ -280,7 +285,7 @@ public class FramebufferUtils {
return texture;
}
public static Framebuffer generateOITFramebuffer(OpenGLState openGLState, int width, int height, Texture accumulatorTex, Texture revealageTex, Texture depthTexture){
public static Framebuffer generateOITFramebuffer(OpenGLState openGLState, int width, int height, Texture accumulatorTex, Texture revealageTex, Texture depthTexture) throws Exception {
Framebuffer buffer = new Framebuffer();
buffer.bind(openGLState);
@ -301,7 +306,7 @@ public class FramebufferUtils {
Globals.renderingEngine.checkError();
//check make sure compiled
buffer.checkStatus();
buffer.shouldBeComplete(openGLState);
Globals.renderingEngine.defaultFramebuffer.bind(openGLState);
return buffer;
}

View File

@ -7,6 +7,7 @@ import org.joml.Vector3f;
import org.lwjgl.opengl.GL40;
import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.camera.CameraEntityUtils;
@ -68,7 +69,7 @@ public class DebugBonesPipeline implements RenderPipeline {
//Get target data
//
Actor targetActor = EntityUtils.getActor(targetEntity);
Model boneModel = Globals.assetManager.fetchModel("Models/basic/geometry/unitcylinder.fbx");
Model boneModel = Globals.assetManager.fetchModel(AssetDataStrings.UNITCYLINDER);
boneModel.getMaterials().get(0).set_diffuse(Globals.textureDiffuseDefault);
for(Bone bone : targetActor.getBoneValues()){
Vector3d bonePos = MathBones.getBoneWorldPosition(targetEntity, bone.boneID);

View File

@ -13,6 +13,7 @@ import org.ode4j.ode.DSphere;
import electrosphere.collision.PhysicsUtils;
import electrosphere.collision.collidable.Collidable;
import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
@ -78,7 +79,7 @@ public class DebugContentPipeline implements RenderPipeline {
if(geom instanceof DSphere){
DSphere sphereView = (DSphere)geom;
HitboxState shapeStatus = hitboxState.getShapeStatus(geom);
if((hitboxModel = Globals.assetManager.fetchModel("Models/basic/geometry/unitsphere.glb")) != null){
if((hitboxModel = Globals.assetManager.fetchModel(AssetDataStrings.UNITSPHERE)) != null){
//set color based on collision status, type, etc
Texture texture = Globals.assetManager.fetchTexture(getHitboxColor(shapeStatus,shapeStatus.getHitboxData()));
if(texture != null){
@ -133,7 +134,7 @@ public class DebugContentPipeline implements RenderPipeline {
if(geom instanceof DSphere){
DSphere sphereView = (DSphere)geom;
HitboxState shapeStatus = hitboxState.getShapeStatus(geom);
if((hitboxModel = Globals.assetManager.fetchModel("Models/basic/geometry/unitsphere.glb")) != null){
if((hitboxModel = Globals.assetManager.fetchModel(AssetDataStrings.UNITSPHERE)) != null){
//set color based on collision status, type, etc
Texture texture = Globals.assetManager.fetchTexture(getHitboxColor(shapeStatus,shapeStatus.getHitboxData()));
if(texture != null){

View File

@ -390,13 +390,27 @@ public class Texture {
this.height = height;
this.pixelFormat = format;
this.datatype = datatype;
int internalFormat = format;
if(internalFormat == GL45.GL_DEPTH_COMPONENT){
internalFormat = GL45.GL_DEPTH_COMPONENT24;
}
//static values going into call
int level = 0;
int border = 0; //this must be 0 according to docs
openGLState.glBindTexture(GL_TEXTURE_2D,texturePointer);
Globals.renderingEngine.checkError();
GL40.glTexImage2D(GL_TEXTURE_2D, level, format, width, height, border, format, datatype, MemoryUtil.NULL);
GL40.glTexImage2D(GL_TEXTURE_2D, level, internalFormat, width, height, border, format, datatype, MemoryUtil.NULL);
Globals.renderingEngine.checkError();
int[] storage = new int[1];
int discoveredWidth = 0;
int discoveredHeight = 0;
GL45.glGetTexLevelParameteriv(GL45.GL_TEXTURE_2D, 0, GL45.GL_TEXTURE_WIDTH, storage);
discoveredWidth = storage[0];
GL45.glGetTexLevelParameteriv(GL45.GL_TEXTURE_2D, 0, GL45.GL_TEXTURE_HEIGHT, storage);
discoveredHeight = storage[0];
if(width != discoveredWidth || height != discoveredHeight){
throw new Error("Found dims aren't the same! " + width + "," + height + " vs " + discoveredWidth + "," + discoveredHeight);
}
}
/**
@ -528,6 +542,13 @@ public class Texture {
}
}
/**
* Frees the texture
*/
public void free(){
GL40.glDeleteTextures(this.texturePointer);
}
@Override
public String toString(){
String rVal = "" +

View File

@ -58,7 +58,11 @@ public class ActorPanel extends StandardElement implements DrawableElement, Drag
public ActorPanel(OpenGLState openGLState, int x, int y, int width, int height, Actor actor){
super();
elementBuffer = FramebufferUtils.generateTextureFramebuffer(openGLState, width, height);
try {
elementBuffer = FramebufferUtils.generateTextureFramebuffer(openGLState, width, height);
} catch(Exception e){
LoggerInterface.loggerRenderer.ERROR(e);
}
customMat.setTexturePointer(elementBuffer.getTexture().getTexturePointer());
this.actor = actor;
this.internalPositionX = x;

View File

@ -37,7 +37,11 @@ public class ScrollableContainer extends StandardContainerElement implements Dra
public ScrollableContainer(OpenGLState openGLState, int positionX, int positionY, int width, int height){
super();
widgetBuffer = FramebufferUtils.generateTextureFramebuffer(openGLState, width, height);
try {
widgetBuffer = FramebufferUtils.generateTextureFramebuffer(openGLState, width, height);
} catch(Exception e){
LoggerInterface.loggerRenderer.ERROR(e);
}
// widgetBuffer = FramebufferUtils.generateScreensizeTextureFramebuffer();
customMat.setTexturePointer(widgetBuffer.getTexture().getTexturePointer());
// customMat.setTexturePointer(Globals.assetManager.fetchTexture("Textures/Testing1.png").getTexturePointer());

View File

@ -71,7 +71,11 @@ public class Window implements DrawableElement, ContainerElement, NavigableEleme
* @param height
*/
public Window(OpenGLState openGLState, int positionX, int positionY, int width, int height, boolean showDecorations){
widgetBuffer = FramebufferUtils.generateTextureFramebuffer(openGLState, width, height);
try {
widgetBuffer = FramebufferUtils.generateTextureFramebuffer(openGLState, width, height);
} catch(Exception e){
LoggerInterface.loggerRenderer.ERROR(e);
}
customMat.setTexturePointer(widgetBuffer.getTexture().getTexturePointer());
float ndcWidth = (float)width/Globals.WINDOW_WIDTH;
float ndcHeight = (float)height/Globals.WINDOW_HEIGHT;

View File

@ -0,0 +1,10 @@
package electrosphere.server.gen;
/**
* Generates dungeons
*/
public class DungeonGen {
}

View File

@ -0,0 +1,161 @@
package electrosphere.util.ds;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* A directed graph
*/
public class DirectedGraph {
/**
* The list of nodes in the graph
*/
List<GraphNode> nodes;
/**
* Constructor
*/
public DirectedGraph(){
this.nodes = new LinkedList<GraphNode>();
}
/**
* Creates a node in the graph
* @param data The data in the node
* @return The node
*/
public GraphNode createNode(Object data){
GraphNode rVal = new GraphNode();
this.nodes.add(rVal);
return rVal;
}
/**
* Adds direction as a neighbor of source. Does not create a connection from direction to source
* @param source The source node
* @param direction The destination node
*/
public void pointNode(GraphNode source, GraphNode direction){
if(!source.containsNeighbor(direction)){
source.addNeighbor(direction);
}
}
/**
* Mutually connects two nodes
* @param node1 Node 1
* @param node2 Node 2
*/
public void connectNodes(GraphNode node1, GraphNode node2){
if(!node1.containsNeighbor(node2)){
node1.addNeighbor(node2);
}
if(!node2.containsNeighbor(node1)){
node2.addNeighbor(node1);
}
}
/**
* Destroys a node
* @param node The node to destroy
*/
public void destroyNode(GraphNode node){
for(GraphNode toEval : this.nodes){
if(toEval != node){
if(toEval.containsNeighbor(node)){
toEval.removeNeighbor(node);
}
}
}
this.nodes.remove(node);
}
/**
* Gets the nodes in the graph
* @return The list of all nodes in the graph
*/
public List<GraphNode> getNodes(){
return Collections.unmodifiableList(this.nodes);
}
/**
* A node in a graph
*/
public static class GraphNode {
/**
* The data at the node
*/
Object data;
/**
* The neighbors of this graph node
*/
List<GraphNode> neighbors;
/**
* Creates a graph node
* @param data The data to put in the node
*/
public GraphNode(Object data){
this.data = data;
this.neighbors = new LinkedList<GraphNode>();
}
/**
* Creates an empty graph node
*/
public GraphNode(){
this.data = null;
this.neighbors = new LinkedList<GraphNode>();
}
/**
* Gets the data at this node
* @return The data
*/
public Object getData(){
return this.data;
}
/**
* Gets the neighbors of this node
* @return The list of neighbors
*/
public List<GraphNode> getNeighbors(){
return this.neighbors;
}
/**
* Adds a neighbor to this node
* @param neighbor The neighbor
*/
public void addNeighbor(GraphNode neighbor){
this.neighbors.add(neighbor);
}
/**
* Removes a neighbor from this node
* @param neighbor THe neighbor
*/
public void removeNeighbor(GraphNode neighbor){
this.neighbors.remove(neighbor);
}
/**
* Checks if this node contains a given node as a neighbor
* @param node The potential neighbor to check
* @return true if the node is a neighbor, false otherwise
*/
public boolean containsNeighbor(GraphNode node){
return this.neighbors.contains(node);
}
}
}

View File

@ -0,0 +1,38 @@
package electrosphere.engine;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import org.junit.jupiter.api.extension.ExtendWith;
import electrosphere.test.annotations.IntegrationTest;
import electrosphere.test.template.extensions.EntityExtension;
import electrosphere.test.template.extensions.StateCleanupCheckerExtension;
/**
* Tests for startup extensions
*/
@ExtendWith(StateCleanupCheckerExtension.class)
public class StartupExtensionTests {
@IntegrationTest
public void test_EntityExtension_Startup(){
assertDoesNotThrow(() -> {
EntityExtension ext = new EntityExtension();
ext.beforeEach(null);
ext.afterEach(null);
});
}
@IntegrationTest
public void test_EntityExtension_RepeatStartup(){
assertDoesNotThrow(() -> {
EntityExtension ext = new EntityExtension();
int someNumberOfTests = 3;
for(int i = 0; i < someNumberOfTests; i++){
ext.beforeEach(null);
ext.afterEach(null);
}
});
}
}

View File

@ -0,0 +1,30 @@
package electrosphere.renderer;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import electrosphere.engine.Globals;
import electrosphere.test.template.extensions.StateCleanupCheckerExtension;
/**
* Tests for the core rendering engine
*/
@ExtendWith(StateCleanupCheckerExtension.class)
public class RenderingEngineTests {
@Test
public void testRenderingEngineResetsAllState(){
assertDoesNotThrow(() -> {
for(int i = 0; i < 5; i++){
Globals.initGlobals();
Globals.renderingEngine = new RenderingEngine();
Globals.renderingEngine.createOpenglContext();
Globals.renderingEngine.destroy();
Globals.resetGlobals();
}
});
}
}

View File

@ -0,0 +1,59 @@
package electrosphere.renderer.framebuffer;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import electrosphere.engine.Globals;
import electrosphere.renderer.RenderingEngine;
import electrosphere.renderer.texture.Texture;
import electrosphere.test.template.extensions.StateCleanupCheckerExtension;
/**
* Tests for framebuffer creation utilities
*/
@ExtendWith(StateCleanupCheckerExtension.class)
public class FramebufferUtilsTests {
@Test
public void testCreateScreenFramebuffer(){
Globals.initGlobals();
Globals.renderingEngine = new RenderingEngine();
Globals.renderingEngine.createOpenglContext();
assertDoesNotThrow(() -> {
Texture screenTextureColor = FramebufferUtils.generateScreenTextureColorAlpha(Globals.renderingEngine.getOpenGLState(), Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
RenderingEngine.screenTextureColor = screenTextureColor;
Texture screenTextureDepth = FramebufferUtils.generateScreenTextureDepth(Globals.renderingEngine.getOpenGLState(), Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
RenderingEngine.screenTextureDepth = screenTextureDepth;
Framebuffer screenFramebuffer = FramebufferUtils.generateScreenTextureFramebuffer(Globals.renderingEngine.getOpenGLState(), Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, screenTextureColor, screenTextureDepth);
RenderingEngine.screenFramebuffer = screenFramebuffer;
});
Globals.renderingEngine.destroy();
Globals.resetGlobals();
}
@Test
public void testCreateScreenFramebufferRepeat(){
assertDoesNotThrow(() -> {
Globals.initGlobals();
Globals.renderingEngine = new RenderingEngine();
Globals.renderingEngine.createOpenglContext();
Texture screenTextureColor = FramebufferUtils.generateScreenTextureColorAlpha(Globals.renderingEngine.getOpenGLState(), Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
Texture screenTextureDepth = FramebufferUtils.generateScreenTextureDepth(Globals.renderingEngine.getOpenGLState(), Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
FramebufferUtils.generateScreenTextureFramebuffer(Globals.renderingEngine.getOpenGLState(), Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, screenTextureColor, screenTextureDepth);
Globals.renderingEngine.destroy();
Globals.resetGlobals();
Globals.initGlobals();
Globals.renderingEngine = new RenderingEngine();
Globals.renderingEngine.createOpenglContext();
screenTextureColor = FramebufferUtils.generateScreenTextureColorAlpha(Globals.renderingEngine.getOpenGLState(), Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
screenTextureDepth = FramebufferUtils.generateScreenTextureDepth(Globals.renderingEngine.getOpenGLState(), Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
FramebufferUtils.generateScreenTextureFramebuffer(Globals.renderingEngine.getOpenGLState(), Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, screenTextureColor, screenTextureDepth);
Globals.renderingEngine.destroy();
Globals.resetGlobals();
});
}
}

View File

@ -10,8 +10,6 @@ import electrosphere.engine.loadingthreads.LoadingThread;
import electrosphere.engine.loadingthreads.LoadingThread.LoadingThreadType;
import electrosphere.engine.profiler.Profiler;
import electrosphere.net.NetUtils;
import electrosphere.renderer.ui.elementtypes.DrawableElement;
import electrosphere.renderer.ui.elementtypes.Element;
public class EngineInit {
@ -85,28 +83,6 @@ public class EngineInit {
LoadingThread loadingThread = new LoadingThread(LoadingThreadType.LOAD_VIEWPORT);
Globals.threadManager.start(loadingThread);
//
//wait for client to be fully init'd
int frames = 0;
while(Globals.threadManager.isLoading()){
TestEngineUtils.simulateFrames(1);
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
frames++;
if(frames > MAX_FRAMES_TO_WAIT){
String errorMessage = "Failed to setup connected test scene!\n" +
"Still running threads are:\n"
;
for(LoadingThread thread : Globals.threadManager.getLoadingThreads()){
errorMessage = errorMessage + thread.getType() + "\n";
}
Assertions.fail("Failed to startup");
}
}
TestEngineUtils.flush();
}

View File

@ -2,10 +2,15 @@ package electrosphere.test.testutils;
import static org.junit.jupiter.api.Assertions.*;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Assertions;
import java.util.function.Supplier;
import electrosphere.engine.Globals;
import electrosphere.engine.Main;
import electrosphere.engine.loadingthreads.LoadingThread;
import electrosphere.entity.Entity;
/**
@ -87,6 +92,28 @@ public class TestEngineUtils {
* Flushes any signals that haven't been processed yet
*/
public static void flush(){
//
//wait for client to be fully init'd
int frames = 0;
while(Globals.threadManager.isLoading()){
TestEngineUtils.simulateFrames(1);
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
frames++;
if(frames > EngineInit.MAX_FRAMES_TO_WAIT){
String errorMessage = "Failed to setup connected test scene!\n" +
"Still running threads are:\n"
;
for(LoadingThread thread : Globals.threadManager.getLoadingThreads()){
errorMessage = errorMessage + thread.getType() + "\n";
}
Assertions.fail("Failed to startup");
}
}
while(
Globals.elementService.getSignalQueueCount() > 0
){

View File

@ -0,0 +1,115 @@
package electrosphere.util.ds;
import static org.junit.jupiter.api.Assertions.*;
import electrosphere.test.annotations.FastTest;
import electrosphere.test.annotations.UnitTest;
import electrosphere.util.ds.DirectedGraph.GraphNode;
/**
* Unit tests for the directed graph implementation
*/
public class DirectedGraphUnitTests {
//
//Graph-specific tests
//
@UnitTest
@FastTest
public void testCreateGraph(){
DirectedGraph graph = new DirectedGraph();
assertNotNull(graph);
}
@UnitTest
@FastTest
public void testCreateEntry(){
DirectedGraph graph = new DirectedGraph();
GraphNode node = graph.createNode(null);
assertNotNull(node);
}
@UnitTest
@FastTest
public void testContainsEntryNotNull(){
DirectedGraph graph = new DirectedGraph();
graph.createNode(null);
assertNotNull(graph.getNodes());
}
@UnitTest
@FastTest
public void testContainsEntryHasEntry(){
DirectedGraph graph = new DirectedGraph();
graph.createNode(null);
assertEquals(1,graph.getNodes().size());
}
@UnitTest
@FastTest
public void testDeleteNode(){
DirectedGraph graph = new DirectedGraph();
GraphNode node = graph.createNode(null);
graph.destroyNode(node);
assertEquals(0,graph.getNodes().size());
}
//
//Node-specific tests
//
@UnitTest
@FastTest
public void testCreateNode(){
GraphNode node = new GraphNode();
assertNotNull(node);
}
@UnitTest
@FastTest
public void testNodeGetData(){
GraphNode node = new GraphNode("some data");
assertEquals("some data", node.getData());
}
@UnitTest
@FastTest
public void testAddNeighbor(){
GraphNode node = new GraphNode();
GraphNode neighbor = new GraphNode();
node.addNeighbor(neighbor);
assertEquals(neighbor, node.getNeighbors().get(0));
}
@UnitTest
@FastTest
public void testRemoveNeighbor(){
GraphNode node = new GraphNode();
GraphNode neighbor = new GraphNode();
node.addNeighbor(neighbor);
node.removeNeighbor(neighbor);
assertEquals(0, node.getNeighbors().size());
}
@UnitTest
@FastTest
public void testGetNeighbors(){
GraphNode node = new GraphNode();
GraphNode neighbor = new GraphNode();
node.addNeighbor(neighbor);
assertEquals(1, node.getNeighbors().size());
}
@UnitTest
@FastTest
public void testContainsNeighbor(){
GraphNode node = new GraphNode();
GraphNode neighbor = new GraphNode();
node.addNeighbor(neighbor);
assertEquals(true, node.containsNeighbor(neighbor));
}
}