fixes + ssbo impl + instanced actor rearch
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
This commit is contained in:
parent
dd763b31a9
commit
f7d1bbed70
@ -730,6 +730,14 @@ DBody key refactor
|
|||||||
Audio for grass/leaves
|
Audio for grass/leaves
|
||||||
Re-enable UI test
|
Re-enable UI test
|
||||||
Fix foliage chunk-level radius being too low (causing grass cutoff)
|
Fix foliage chunk-level radius being too low (causing grass cutoff)
|
||||||
|
Turn on anti-aliasing for font generation
|
||||||
|
|
||||||
|
(09/12/2024)
|
||||||
|
Alias fonts
|
||||||
|
Fix audio handling bug
|
||||||
|
SSBO implementation
|
||||||
|
Rearch instanced actor
|
||||||
|
ParticleService implementation
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
|
|||||||
@ -13,8 +13,13 @@ import org.lwjgl.openal.AL10;
|
|||||||
*/
|
*/
|
||||||
public class AudioSource {
|
public class AudioSource {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An undefined source's id
|
||||||
|
*/
|
||||||
|
static final int UNDEFINED_ID = -1;
|
||||||
|
|
||||||
//The id for the source
|
//The id for the source
|
||||||
int sourceId;
|
int sourceId = UNDEFINED_ID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an audio source object
|
* Creates an audio source object
|
||||||
@ -37,46 +42,56 @@ public class AudioSource {
|
|||||||
*/
|
*/
|
||||||
public void setBuffer(int bufferId) {
|
public void setBuffer(int bufferId) {
|
||||||
stop();
|
stop();
|
||||||
|
if(isAllocated()){
|
||||||
AL10.alSourcei(sourceId, AL10.AL_BUFFER, bufferId);
|
AL10.alSourcei(sourceId, AL10.AL_BUFFER, bufferId);
|
||||||
Globals.audioEngine.checkError();
|
Globals.audioEngine.checkError();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the position of the audio source
|
* Sets the position of the audio source
|
||||||
* @param position the position
|
* @param position the position
|
||||||
*/
|
*/
|
||||||
public void setPosition(Vector3f position) {
|
public void setPosition(Vector3f position) {
|
||||||
|
if(isAllocated()){
|
||||||
AL10.alSource3f(sourceId, AL10.AL_POSITION, position.x, position.y, position.z);
|
AL10.alSource3f(sourceId, AL10.AL_POSITION, position.x, position.y, position.z);
|
||||||
Globals.audioEngine.checkError();
|
Globals.audioEngine.checkError();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the speed of the audio source
|
* Sets the speed of the audio source
|
||||||
* @param speed the speed
|
* @param speed the speed
|
||||||
*/
|
*/
|
||||||
public void setSpeed(Vector3f speed) {
|
public void setSpeed(Vector3f speed) {
|
||||||
|
if(isAllocated()){
|
||||||
AL10.alSource3f(sourceId, AL10.AL_VELOCITY, speed.x, speed.y, speed.z);
|
AL10.alSource3f(sourceId, AL10.AL_VELOCITY, speed.x, speed.y, speed.z);
|
||||||
Globals.audioEngine.checkError();
|
Globals.audioEngine.checkError();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the temporal offset of the source (ie how far into the clip to start playingf)
|
* Sets the temporal offset of the source (ie how far into the clip to start playingf)
|
||||||
* @param time The time in seconds
|
* @param time The time in seconds
|
||||||
*/
|
*/
|
||||||
public void setOffset(float time){
|
public void setOffset(float time){
|
||||||
|
if(isAllocated()){
|
||||||
AL10.alSourcef(sourceId, AL11.AL_SEC_OFFSET, time);
|
AL10.alSourcef(sourceId, AL11.AL_SEC_OFFSET, time);
|
||||||
Globals.audioEngine.checkError();
|
Globals.audioEngine.checkError();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the gain of the audio source
|
* Sets the gain of the audio source
|
||||||
* @param gain the gain
|
* @param gain the gain
|
||||||
*/
|
*/
|
||||||
public void setGain(float gain) {
|
public void setGain(float gain) {
|
||||||
|
if(isAllocated()){
|
||||||
LoggerInterface.loggerAudio.DEBUG("Set Gain: " + gain);
|
LoggerInterface.loggerAudio.DEBUG("Set Gain: " + gain);
|
||||||
AL10.alSourcef(sourceId, AL10.AL_GAIN, gain);
|
AL10.alSourcef(sourceId, AL10.AL_GAIN, gain);
|
||||||
Globals.audioEngine.checkError();
|
Globals.audioEngine.checkError();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an arbitrary property on the audio source
|
* Sets an arbitrary property on the audio source
|
||||||
@ -84,25 +99,32 @@ public class AudioSource {
|
|||||||
* @param value The value to set the param to
|
* @param value The value to set the param to
|
||||||
*/
|
*/
|
||||||
public void setProperty(int param, float value) {
|
public void setProperty(int param, float value) {
|
||||||
|
if(isAllocated()){
|
||||||
AL10.alSourcef(sourceId, param, value);
|
AL10.alSourcef(sourceId, param, value);
|
||||||
Globals.audioEngine.checkError();
|
Globals.audioEngine.checkError();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plays the audio source
|
* Plays the audio source
|
||||||
*/
|
*/
|
||||||
public void play() {
|
public void play() {
|
||||||
|
if(isAllocated()){
|
||||||
AL10.alSourcePlay(sourceId);
|
AL10.alSourcePlay(sourceId);
|
||||||
Globals.audioEngine.checkError();
|
Globals.audioEngine.checkError();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets whether the audio source is currently playing or not
|
* Gets whether the audio source is currently playing or not
|
||||||
* @return True if it is playing, false otherwise
|
* @return True if it is playing, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean isPlaying() {
|
public boolean isPlaying() {
|
||||||
boolean isPlaying = AL10.alGetSourcei(sourceId, AL10.AL_SOURCE_STATE) == AL10.AL_PLAYING;
|
boolean isPlaying = false;
|
||||||
|
if(isAllocated()){
|
||||||
|
isPlaying = AL10.alGetSourcei(sourceId, AL10.AL_SOURCE_STATE) == AL10.AL_PLAYING;
|
||||||
Globals.audioEngine.checkError();
|
Globals.audioEngine.checkError();
|
||||||
|
}
|
||||||
return isPlaying;
|
return isPlaying;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,24 +132,37 @@ public class AudioSource {
|
|||||||
* Pauses the audio source
|
* Pauses the audio source
|
||||||
*/
|
*/
|
||||||
public void pause() {
|
public void pause() {
|
||||||
|
if(isAllocated()){
|
||||||
AL10.alSourcePause(sourceId);
|
AL10.alSourcePause(sourceId);
|
||||||
Globals.audioEngine.checkError();
|
Globals.audioEngine.checkError();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops the audio source
|
* Stops the audio source
|
||||||
*/
|
*/
|
||||||
public void stop() {
|
public void stop() {
|
||||||
|
if(isAllocated()){
|
||||||
AL10.alSourceStop(sourceId);
|
AL10.alSourceStop(sourceId);
|
||||||
Globals.audioEngine.checkError();
|
Globals.audioEngine.checkError();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleans up the source
|
* Cleans up the source
|
||||||
*/
|
*/
|
||||||
public void cleanup() {
|
public void cleanup() {
|
||||||
stop();
|
stop();
|
||||||
|
sourceId = UNDEFINED_ID;
|
||||||
AL10.alDeleteSources(sourceId);
|
AL10.alDeleteSources(sourceId);
|
||||||
Globals.audioEngine.checkError();
|
Globals.audioEngine.checkError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the audio source is allocated or not
|
||||||
|
* @return true if allocated, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean isAllocated(){
|
||||||
|
return sourceId != UNDEFINED_ID;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,77 @@
|
|||||||
|
package electrosphere.client.entity.particle;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import electrosphere.engine.signal.Signal;
|
||||||
|
import electrosphere.engine.signal.SignalServiceImpl;
|
||||||
|
import electrosphere.renderer.actor.instance.StridedInstanceData;
|
||||||
|
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The particle service
|
||||||
|
*/
|
||||||
|
public class ParticleService extends SignalServiceImpl {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of particles
|
||||||
|
*/
|
||||||
|
static final int MAX_PARTICLES = 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path to the vertex shader
|
||||||
|
*/
|
||||||
|
static final String VERTEX_SHADER_PATH = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path to the fragment shader
|
||||||
|
*/
|
||||||
|
static final String FRAGMENT_SHADER_PATH = "";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The instance data for the particles
|
||||||
|
*/
|
||||||
|
StridedInstanceData particleInstanceData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public ParticleService() {
|
||||||
|
super("ParticleService");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
super.destroy();
|
||||||
|
if(particleInstanceData != null){
|
||||||
|
particleInstanceData.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(Signal signal){
|
||||||
|
boolean rVal = false;
|
||||||
|
switch(signal.getType()){
|
||||||
|
case RENDERING_ENGINE_READY: {
|
||||||
|
List<HomogenousBufferTypes> types = Arrays.asList(new HomogenousBufferTypes[]{
|
||||||
|
//position
|
||||||
|
HomogenousBufferTypes.VEC3D,
|
||||||
|
//rotation
|
||||||
|
HomogenousBufferTypes.VEC4D,
|
||||||
|
//scale
|
||||||
|
HomogenousBufferTypes.VEC3D,
|
||||||
|
//texture index
|
||||||
|
HomogenousBufferTypes.INT,
|
||||||
|
});
|
||||||
|
this.particleInstanceData = new StridedInstanceData(MAX_PARTICLES,types,VERTEX_SHADER_PATH,FRAGMENT_SHADER_PATH);
|
||||||
|
rVal = true;
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -12,6 +12,7 @@ import electrosphere.audio.VirtualAudioSourceManager;
|
|||||||
import electrosphere.audio.collision.HitboxAudioService;
|
import electrosphere.audio.collision.HitboxAudioService;
|
||||||
import electrosphere.audio.movement.MovementAudioService;
|
import electrosphere.audio.movement.MovementAudioService;
|
||||||
import electrosphere.auth.AuthenticationManager;
|
import electrosphere.auth.AuthenticationManager;
|
||||||
|
import electrosphere.client.entity.particle.ParticleService;
|
||||||
import electrosphere.client.fluid.cells.FluidCellManager;
|
import electrosphere.client.fluid.cells.FluidCellManager;
|
||||||
import electrosphere.client.fluid.manager.ClientFluidManager;
|
import electrosphere.client.fluid.manager.ClientFluidManager;
|
||||||
import electrosphere.client.foliagemanager.ClientFoliageManager;
|
import electrosphere.client.foliagemanager.ClientFoliageManager;
|
||||||
@ -292,6 +293,7 @@ public class Globals {
|
|||||||
//
|
//
|
||||||
public static String particleBillboardModel;
|
public static String particleBillboardModel;
|
||||||
public static ParticleDefinition particleDefinition;
|
public static ParticleDefinition particleDefinition;
|
||||||
|
public static ParticleService particleService;
|
||||||
|
|
||||||
public static ShaderOptionMap shaderOptionMap;
|
public static ShaderOptionMap shaderOptionMap;
|
||||||
|
|
||||||
@ -505,6 +507,7 @@ public class Globals {
|
|||||||
//add services here
|
//add services here
|
||||||
Globals.signalSystem = (SignalSystem)serviceManager.registerService(new SignalSystem());
|
Globals.signalSystem = (SignalSystem)serviceManager.registerService(new SignalSystem());
|
||||||
Globals.elementService = (ElementService)serviceManager.registerService(new ElementService());
|
Globals.elementService = (ElementService)serviceManager.registerService(new ElementService());
|
||||||
|
Globals.particleService = (ParticleService)serviceManager.registerService(new ParticleService());
|
||||||
serviceManager.instantiate();
|
serviceManager.instantiate();
|
||||||
//
|
//
|
||||||
//End service manager
|
//End service manager
|
||||||
@ -515,6 +518,7 @@ public class Globals {
|
|||||||
Globals.signalSystem.registerService(SignalType.YOGA_APPLY, Globals.elementService);
|
Globals.signalSystem.registerService(SignalType.YOGA_APPLY, Globals.elementService);
|
||||||
Globals.signalSystem.registerService(SignalType.YOGA_DESTROY, Globals.elementService);
|
Globals.signalSystem.registerService(SignalType.YOGA_DESTROY, Globals.elementService);
|
||||||
Globals.signalSystem.registerService(SignalType.UI_MODIFICATION, Globals.elementService);
|
Globals.signalSystem.registerService(SignalType.UI_MODIFICATION, Globals.elementService);
|
||||||
|
Globals.signalSystem.registerService(SignalType.RENDERING_ENGINE_READY, Globals.particleService);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -668,6 +672,7 @@ public class Globals {
|
|||||||
Globals.clientSynchronizationManager = null;
|
Globals.clientSynchronizationManager = null;
|
||||||
Globals.server = null;
|
Globals.server = null;
|
||||||
Globals.serverSynchronizationManager = null;
|
Globals.serverSynchronizationManager = null;
|
||||||
|
Globals.playerManager = null;
|
||||||
Globals.javaPID = null;
|
Globals.javaPID = null;
|
||||||
Globals.RENDER_FLAG_RENDER_SHADOW_MAP = true;
|
Globals.RENDER_FLAG_RENDER_SHADOW_MAP = true;
|
||||||
Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT = false;
|
Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT = false;
|
||||||
|
|||||||
@ -17,6 +17,11 @@ public class Signal {
|
|||||||
//
|
//
|
||||||
ENGINE_SHUTDOWN,
|
ENGINE_SHUTDOWN,
|
||||||
|
|
||||||
|
//
|
||||||
|
//RENDERING
|
||||||
|
//
|
||||||
|
RENDERING_ENGINE_READY,
|
||||||
|
|
||||||
//
|
//
|
||||||
//UI
|
//UI
|
||||||
//
|
//
|
||||||
|
|||||||
@ -5,9 +5,11 @@ import java.util.Map;
|
|||||||
|
|
||||||
import org.joml.Vector2i;
|
import org.joml.Vector2i;
|
||||||
import org.lwjgl.opengl.GL40;
|
import org.lwjgl.opengl.GL40;
|
||||||
|
import org.lwjgl.opengl.GL45;
|
||||||
|
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.logger.LoggerInterface;
|
import electrosphere.logger.LoggerInterface;
|
||||||
|
import electrosphere.renderer.buffer.UniformBlockBinding;
|
||||||
import electrosphere.renderer.shader.ShaderProgram;
|
import electrosphere.renderer.shader.ShaderProgram;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,6 +56,11 @@ public class OpenGLState {
|
|||||||
//map of texture units and their corresponding texture pointers
|
//map of texture units and their corresponding texture pointers
|
||||||
Map<Integer,Integer> unitToPointerMap;
|
Map<Integer,Integer> unitToPointerMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map of index -> uniform buffer bound to that index
|
||||||
|
*/
|
||||||
|
Map<Integer,UniformBlockBinding> indexBlockMap;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the opengl state
|
* Initializes the opengl state
|
||||||
@ -69,7 +76,8 @@ public class OpenGLState {
|
|||||||
framebufferType = 0;
|
framebufferType = 0;
|
||||||
framebufferPointer = 0;
|
framebufferPointer = 0;
|
||||||
activeShader = null;
|
activeShader = null;
|
||||||
unitToPointerMap = new HashMap<Integer,Integer>();
|
this.unitToPointerMap = new HashMap<Integer,Integer>();
|
||||||
|
this.indexBlockMap = new HashMap<Integer,UniformBlockBinding>();
|
||||||
this.storeCurrentEnvironmentContraints();
|
this.storeCurrentEnvironmentContraints();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,4 +317,38 @@ public class OpenGLState {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds a buffer to a given uniform buffer block index
|
||||||
|
* @param index the index
|
||||||
|
* @param buffer the buffer
|
||||||
|
*/
|
||||||
|
public void glBindBufferBase(int index, UniformBlockBinding buffer){
|
||||||
|
if(this.indexBlockMap.containsKey(index)){
|
||||||
|
UniformBlockBinding currentBuffer = this.indexBlockMap.get(index);
|
||||||
|
if(currentBuffer == null || currentBuffer != buffer){
|
||||||
|
//does not already contain index, should bind
|
||||||
|
this.indexBlockMap.put(index,buffer);
|
||||||
|
GL45.glBindBufferBase(index, index, buffer.getId());
|
||||||
|
Globals.renderingEngine.checkError();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//does not already contain index, should bind
|
||||||
|
this.indexBlockMap.put(index,buffer);
|
||||||
|
GL45.glBindBufferBase(index, index, buffer.getId());
|
||||||
|
Globals.renderingEngine.checkError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unbinds a buffer from a given uniform buffer block index
|
||||||
|
* @param index the index
|
||||||
|
*/
|
||||||
|
public void glUnbindBufferBase(int index){
|
||||||
|
if(this.indexBlockMap.containsKey(index)){
|
||||||
|
this.indexBlockMap.remove(index);
|
||||||
|
GL45.glBindBufferBase(index, index, UniformBlockBinding.UNBIND_ADDRESS);
|
||||||
|
Globals.renderingEngine.checkError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,6 +43,7 @@ import org.lwjgl.opengl.GLDebugMessageCallback;
|
|||||||
import org.lwjgl.system.MemoryStack;
|
import org.lwjgl.system.MemoryStack;
|
||||||
|
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.engine.signal.Signal.SignalType;
|
||||||
import electrosphere.logger.LoggerInterface;
|
import electrosphere.logger.LoggerInterface;
|
||||||
import electrosphere.renderer.debug.DebugRendering;
|
import electrosphere.renderer.debug.DebugRendering;
|
||||||
import electrosphere.renderer.framebuffer.Framebuffer;
|
import electrosphere.renderer.framebuffer.Framebuffer;
|
||||||
@ -462,6 +463,13 @@ public class RenderingEngine {
|
|||||||
float nearClip = 0.001f;
|
float nearClip = 0.001f;
|
||||||
Globals.projectionMatrix.setPerspective(verticalFOV, Globals.aspectRatio, nearClip, Globals.userSettings.getGraphicsViewDistance());
|
Globals.projectionMatrix.setPerspective(verticalFOV, Globals.aspectRatio, nearClip, Globals.userSettings.getGraphicsViewDistance());
|
||||||
Globals.viewMatrix.translation(new Vector3f(0.0f,0.0f,-3.0f));
|
Globals.viewMatrix.translation(new Vector3f(0.0f,0.0f,-3.0f));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alert everyone that the rendering engine is ready
|
||||||
|
*/
|
||||||
|
if(Globals.signalSystem != null){
|
||||||
|
Globals.signalSystem.post(SignalType.RENDERING_ENGINE_READY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,399 @@
|
|||||||
|
package electrosphere.renderer.actor.instance;
|
||||||
|
|
||||||
|
import java.nio.DoubleBuffer;
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.joml.Matrix4d;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.joml.Vector4d;
|
||||||
|
import org.joml.Vector4f;
|
||||||
|
import org.lwjgl.BufferUtils;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.renderer.OpenGLState;
|
||||||
|
import electrosphere.renderer.RenderPipelineState;
|
||||||
|
import electrosphere.renderer.buffer.HomogenousInstancedArray;
|
||||||
|
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
|
||||||
|
import electrosphere.renderer.buffer.ShaderAttribute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An instance data that uses multiple homogenous buffers
|
||||||
|
*/
|
||||||
|
public class HomogenousInstanceData implements InstanceData {
|
||||||
|
|
||||||
|
//the capacity (number of instanced) of this data block. Defaults to 100
|
||||||
|
int capacity = 1000;
|
||||||
|
|
||||||
|
//shader paths
|
||||||
|
String vertexShaderPath;
|
||||||
|
String fragmentShaderPath;
|
||||||
|
|
||||||
|
//the number of draw calls since the last clear operation
|
||||||
|
int drawCalls = 0;
|
||||||
|
|
||||||
|
//The set of instanced actors to draw
|
||||||
|
List<InstancedActor> actorQueue = null;
|
||||||
|
//Map of actor to index in the buffers that are emitted
|
||||||
|
Map<InstancedActor,Integer> actorIndexMap = new HashMap<InstancedActor,Integer>();
|
||||||
|
//Map of index -> actor used for buffer evictions
|
||||||
|
Map<Integer,InstancedActor> indexActorMap = new HashMap<Integer,InstancedActor>();
|
||||||
|
|
||||||
|
//list of all attribute indices in use by this instance data
|
||||||
|
List<ShaderAttribute> attributeIndices = new LinkedList<ShaderAttribute>();
|
||||||
|
//map of attribute -> buffer of attribute data
|
||||||
|
Map<ShaderAttribute,Object> attributeCpuBufferMap = new HashMap<ShaderAttribute,Object>();
|
||||||
|
//map of attribute -> gl HomogenousBuffer
|
||||||
|
Map<ShaderAttribute,HomogenousInstancedArray> attributeGlBufferMap = new HashMap<ShaderAttribute,HomogenousInstancedArray>();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param capacity Capacity of the buffer (number of elements) backing this data
|
||||||
|
*/
|
||||||
|
protected HomogenousInstanceData(int capacity, String vertexPath, String fragmentPath){
|
||||||
|
this.capacity = capacity;
|
||||||
|
this.vertexShaderPath = vertexPath;
|
||||||
|
this.fragmentShaderPath = fragmentPath;
|
||||||
|
actorQueue = new LinkedList<InstancedActor>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new type of attribute to this instance data block
|
||||||
|
* @param shaderAttribute The shader attribute
|
||||||
|
* @param type The type of the attribute
|
||||||
|
*/
|
||||||
|
protected void addDataType(ShaderAttribute shaderAttribute, HomogenousBufferTypes type){
|
||||||
|
attributeIndices.add(shaderAttribute);
|
||||||
|
switch(type){
|
||||||
|
case VEC3F: {
|
||||||
|
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createFloatBuffer(capacity * 3));
|
||||||
|
} break;
|
||||||
|
case VEC3D: {
|
||||||
|
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createDoubleBuffer(capacity * 3));
|
||||||
|
} break;
|
||||||
|
case VEC4F: {
|
||||||
|
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createFloatBuffer(capacity * 4));
|
||||||
|
} break;
|
||||||
|
case VEC4D: {
|
||||||
|
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createDoubleBuffer(capacity * 4));
|
||||||
|
} break;
|
||||||
|
case DOUBLE: {
|
||||||
|
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createDoubleBuffer(capacity));
|
||||||
|
} break;
|
||||||
|
case FLOAT: {
|
||||||
|
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createFloatBuffer(capacity));
|
||||||
|
} break;
|
||||||
|
case INT: {
|
||||||
|
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createIntBuffer(capacity));
|
||||||
|
} break;
|
||||||
|
case MAT4F: {
|
||||||
|
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createFloatBuffer(capacity * 4 * 4));
|
||||||
|
} break;
|
||||||
|
case MAT4D: {
|
||||||
|
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createFloatBuffer(capacity * 4 * 4));
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
if(shaderAttribute.isSingleIndex()){
|
||||||
|
attributeGlBufferMap.put(shaderAttribute,HomogenousInstancedArray.createHomogenousInstancedArray(shaderAttribute.getIndex(), type, capacity));
|
||||||
|
} else {
|
||||||
|
attributeGlBufferMap.put(shaderAttribute,HomogenousInstancedArray.createHomogenousInstancedArray(shaderAttribute.getIndices(), type, capacity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an actor to be sorted in the queue
|
||||||
|
* @param actor The actor to be sorted
|
||||||
|
*/
|
||||||
|
public void addInstance(InstancedActor actor){
|
||||||
|
actorQueue.add(actor);
|
||||||
|
drawCalls++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of entries that are to be drawn
|
||||||
|
* @return The number of entries to be drawn
|
||||||
|
*/
|
||||||
|
public int getDrawCount(){
|
||||||
|
return drawCalls;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the queue
|
||||||
|
*/
|
||||||
|
public void clearDrawQueue(){
|
||||||
|
actorQueue.clear();
|
||||||
|
drawCalls = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills the buffers for the upcoming render call. The intention is to make this emberassingly parallel.
|
||||||
|
*/
|
||||||
|
public void fillBuffers(){
|
||||||
|
int i = 0;
|
||||||
|
//for some reason the limit is not being set correctly. This explicitly forces it for each buffer
|
||||||
|
for(ShaderAttribute attribute : attributeIndices){
|
||||||
|
switch(attributeGlBufferMap.get(attribute).getType()){
|
||||||
|
case VEC3F: {
|
||||||
|
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
buffer.limit(buffer.capacity());
|
||||||
|
} break;
|
||||||
|
case VEC3D: {
|
||||||
|
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
buffer.limit(buffer.capacity());
|
||||||
|
} break;
|
||||||
|
case VEC4F: {
|
||||||
|
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
buffer.limit(buffer.capacity());
|
||||||
|
} break;
|
||||||
|
case VEC4D: {
|
||||||
|
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
buffer.limit(buffer.capacity());
|
||||||
|
} break;
|
||||||
|
case MAT4F: {
|
||||||
|
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
buffer.limit(buffer.capacity());
|
||||||
|
// System.out.println(buffer.position() + " " + buffer.limit());
|
||||||
|
} break;
|
||||||
|
case MAT4D: {
|
||||||
|
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
buffer.limit(buffer.capacity());
|
||||||
|
} break;
|
||||||
|
case DOUBLE: {
|
||||||
|
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
buffer.limit(buffer.capacity());
|
||||||
|
} break;
|
||||||
|
case FLOAT: {
|
||||||
|
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
buffer.limit(buffer.capacity());
|
||||||
|
} break;
|
||||||
|
case INT: {
|
||||||
|
IntBuffer buffer = ((IntBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
buffer.limit(buffer.capacity());
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// actorQueue.sort(Comparator.naturalOrder());
|
||||||
|
//buffer data
|
||||||
|
for(InstancedActor actor : actorQueue){
|
||||||
|
//push values to attribute buffers
|
||||||
|
for(ShaderAttribute attribute : attributeIndices){
|
||||||
|
switch(attributeGlBufferMap.get(attribute).getType()){
|
||||||
|
case VEC3F: {
|
||||||
|
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
Vector3f vec = (Vector3f)actor.getAttributeValue(attribute);
|
||||||
|
buffer.put(vec.x);
|
||||||
|
buffer.put(vec.y);
|
||||||
|
buffer.put(vec.z);
|
||||||
|
} break;
|
||||||
|
case VEC3D: {
|
||||||
|
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
Vector3d vec = (Vector3d)actor.getAttributeValue(attribute);
|
||||||
|
buffer.put(vec.x);
|
||||||
|
buffer.put(vec.y);
|
||||||
|
buffer.put(vec.z);
|
||||||
|
} break;
|
||||||
|
case VEC4F: {
|
||||||
|
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
Vector4f vec = (Vector4f)actor.getAttributeValue(attribute);
|
||||||
|
buffer.put(vec.w);
|
||||||
|
buffer.put(vec.x);
|
||||||
|
buffer.put(vec.y);
|
||||||
|
buffer.put(vec.z);
|
||||||
|
} break;
|
||||||
|
case VEC4D: {
|
||||||
|
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
Vector4d vec = (Vector4d)actor.getAttributeValue(attribute);
|
||||||
|
buffer.put(vec.w);
|
||||||
|
buffer.put(vec.x);
|
||||||
|
buffer.put(vec.y);
|
||||||
|
buffer.put(vec.z);
|
||||||
|
} break;
|
||||||
|
case MAT4F: {
|
||||||
|
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
Matrix4f mat = (Matrix4f)actor.getAttributeValue(attribute);
|
||||||
|
buffer.put(mat.m00());
|
||||||
|
buffer.put(mat.m01());
|
||||||
|
buffer.put(mat.m02());
|
||||||
|
buffer.put(mat.m03());
|
||||||
|
|
||||||
|
buffer.put(mat.m10());
|
||||||
|
buffer.put(mat.m11());
|
||||||
|
buffer.put(mat.m12());
|
||||||
|
buffer.put(mat.m13());
|
||||||
|
|
||||||
|
buffer.put(mat.m20());
|
||||||
|
buffer.put(mat.m21());
|
||||||
|
buffer.put(mat.m22());
|
||||||
|
buffer.put(mat.m23());
|
||||||
|
|
||||||
|
buffer.put(mat.m30());
|
||||||
|
buffer.put(mat.m31());
|
||||||
|
buffer.put(mat.m32());
|
||||||
|
buffer.put(mat.m33());
|
||||||
|
} break;
|
||||||
|
case MAT4D: {
|
||||||
|
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
Matrix4d mat = (Matrix4d)actor.getAttributeValue(attribute);
|
||||||
|
buffer.put((float)mat.m00());
|
||||||
|
buffer.put((float)mat.m01());
|
||||||
|
buffer.put((float)mat.m02());
|
||||||
|
buffer.put((float)mat.m03());
|
||||||
|
|
||||||
|
buffer.put((float)mat.m10());
|
||||||
|
buffer.put((float)mat.m11());
|
||||||
|
buffer.put((float)mat.m12());
|
||||||
|
buffer.put((float)mat.m13());
|
||||||
|
|
||||||
|
buffer.put((float)mat.m20());
|
||||||
|
buffer.put((float)mat.m21());
|
||||||
|
buffer.put((float)mat.m22());
|
||||||
|
buffer.put((float)mat.m23());
|
||||||
|
|
||||||
|
buffer.put((float)mat.m30());
|
||||||
|
buffer.put((float)mat.m31());
|
||||||
|
buffer.put((float)mat.m32());
|
||||||
|
buffer.put((float)mat.m33());
|
||||||
|
} break;
|
||||||
|
case DOUBLE: {
|
||||||
|
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
buffer.put((Double)actor.getAttributeValue(attribute));
|
||||||
|
} break;
|
||||||
|
case FLOAT: {
|
||||||
|
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
buffer.put((Float)actor.getAttributeValue(attribute));
|
||||||
|
} break;
|
||||||
|
case INT: {
|
||||||
|
IntBuffer buffer = ((IntBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
buffer.put((Integer)actor.getAttributeValue(attribute));
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//increment
|
||||||
|
i++;
|
||||||
|
if(i >= capacity){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//reset all buffers
|
||||||
|
flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flips the data buffer(s)
|
||||||
|
*/
|
||||||
|
public void flip(){
|
||||||
|
//reset all buffers
|
||||||
|
for(ShaderAttribute attribute : attributeIndices){
|
||||||
|
switch(attributeGlBufferMap.get(attribute).getType()){
|
||||||
|
case VEC3F: {
|
||||||
|
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
if(buffer.position() > 0){
|
||||||
|
buffer.flip();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case VEC3D: {
|
||||||
|
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
if(buffer.position() > 0){
|
||||||
|
buffer.flip();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case VEC4F: {
|
||||||
|
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
if(buffer.position() > 0){
|
||||||
|
buffer.flip();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case VEC4D: {
|
||||||
|
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
if(buffer.position() > 0){
|
||||||
|
buffer.flip();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case MAT4F: {
|
||||||
|
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
if(buffer.position() > 0){
|
||||||
|
buffer.flip();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case MAT4D: {
|
||||||
|
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
if(buffer.position() > 0){
|
||||||
|
buffer.flip();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case DOUBLE: {
|
||||||
|
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
if(buffer.position() > 0){
|
||||||
|
buffer.flip();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case FLOAT: {
|
||||||
|
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
if(buffer.position() > 0){
|
||||||
|
buffer.flip();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case INT: {
|
||||||
|
IntBuffer buffer = ((IntBuffer)attributeCpuBufferMap.get(attribute));
|
||||||
|
if(buffer.position() > 0){
|
||||||
|
buffer.flip();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a map of all attributes to the buffers of data for that attribute
|
||||||
|
* @return The data buffers
|
||||||
|
*/
|
||||||
|
public Map<ShaderAttribute,Object> getCpuBufferMap(){
|
||||||
|
return attributeCpuBufferMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a map of attribute name to gl homogenous buffer object
|
||||||
|
* @return The map
|
||||||
|
*/
|
||||||
|
public Map<ShaderAttribute,HomogenousInstancedArray> getGlBufferMap(){
|
||||||
|
return attributeGlBufferMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getVertexShader(){
|
||||||
|
return vertexShaderPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFragmentShader(){
|
||||||
|
return fragmentShaderPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void upload(OpenGLState openGLState, RenderPipelineState renderPipelineState){
|
||||||
|
Map<ShaderAttribute,Object> buffers = this.getCpuBufferMap();
|
||||||
|
Map<ShaderAttribute,HomogenousInstancedArray> glBufferMap = this.getGlBufferMap();
|
||||||
|
for(ShaderAttribute attribute : buffers.keySet()){
|
||||||
|
HomogenousInstancedArray buffer = glBufferMap.get(attribute);
|
||||||
|
buffer.updateBuffer(buffers.get(attribute), 0);
|
||||||
|
buffer.bind(renderPipelineState);
|
||||||
|
}
|
||||||
|
renderPipelineState.setInstanceCount(this.getDrawCount());
|
||||||
|
Globals.renderingEngine.checkError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'destroy'");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,366 +1,61 @@
|
|||||||
package electrosphere.renderer.actor.instance;
|
package electrosphere.renderer.actor.instance;
|
||||||
|
|
||||||
import java.nio.DoubleBuffer;
|
import electrosphere.renderer.OpenGLState;
|
||||||
import java.nio.FloatBuffer;
|
import electrosphere.renderer.RenderPipelineState;
|
||||||
import java.nio.IntBuffer;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.joml.Matrix4d;
|
|
||||||
import org.joml.Matrix4f;
|
|
||||||
import org.joml.Vector3d;
|
|
||||||
import org.joml.Vector3f;
|
|
||||||
import org.joml.Vector4d;
|
|
||||||
import org.joml.Vector4f;
|
|
||||||
import org.lwjgl.BufferUtils;
|
|
||||||
|
|
||||||
import electrosphere.renderer.buffer.HomogenousInstancedArray;
|
|
||||||
import electrosphere.renderer.buffer.ShaderAttribute;
|
|
||||||
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Effectively controls the block of data that is passed to the gpu each time this instance is drawn.
|
* Effectively controls the block of data that is passed to the gpu each time this instance is drawn.
|
||||||
* Does priority management to draw the instanced of higher priority if there happens to be greater than the capacity number of items to draw.
|
* Does priority management to draw the instanced of higher priority if there happens to be greater than the capacity number of items to draw.
|
||||||
*/
|
*/
|
||||||
public class InstanceData {
|
public interface InstanceData {
|
||||||
|
|
||||||
//the capacity (number of instanced) of this data block. Defaults to 100
|
|
||||||
int capacity = 1000;
|
|
||||||
|
|
||||||
//shader paths
|
|
||||||
String vertexShaderPath;
|
|
||||||
String fragmentShaderPath;
|
|
||||||
|
|
||||||
//the number of draw calls since the last clear operation
|
|
||||||
int drawCalls = 0;
|
|
||||||
|
|
||||||
//The set of instanced actors to draw
|
|
||||||
List<InstancedActor> actorQueue = null;
|
|
||||||
//Map of actor to index in the buffers that are emitted
|
|
||||||
Map<InstancedActor,Integer> actorIndexMap = new HashMap<InstancedActor,Integer>();
|
|
||||||
//Map of index -> actor used for buffer evictions
|
|
||||||
Map<Integer,InstancedActor> indexActorMap = new HashMap<Integer,InstancedActor>();
|
|
||||||
|
|
||||||
//list of all attribute indices in use by this instance data
|
|
||||||
List<ShaderAttribute> attributeIndices = new LinkedList<ShaderAttribute>();
|
|
||||||
//map of attribute -> buffer of attribute data
|
|
||||||
Map<ShaderAttribute,Object> attributeCpuBufferMap = new HashMap<ShaderAttribute,Object>();
|
|
||||||
//map of attribute -> gl HomogenousBuffer
|
|
||||||
Map<ShaderAttribute,HomogenousInstancedArray> attributeGlBufferMap = new HashMap<ShaderAttribute,HomogenousInstancedArray>();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
* @param capacity Capacity of the buffer (number of elements) backing this data
|
|
||||||
*/
|
|
||||||
protected InstanceData(int capacity, String vertexPath, String fragmentPath){
|
|
||||||
this.capacity = capacity;
|
|
||||||
this.vertexShaderPath = vertexPath;
|
|
||||||
this.fragmentShaderPath = fragmentPath;
|
|
||||||
actorQueue = new LinkedList<InstancedActor>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new type of attribute to this instance data block
|
|
||||||
* @param shaderAttribute The shader attribute
|
|
||||||
* @param type The type of the attribute
|
|
||||||
*/
|
|
||||||
protected void addDataType(ShaderAttribute shaderAttribute, HomogenousBufferTypes type){
|
|
||||||
attributeIndices.add(shaderAttribute);
|
|
||||||
switch(type){
|
|
||||||
case VEC3F: {
|
|
||||||
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createFloatBuffer(capacity * 3));
|
|
||||||
} break;
|
|
||||||
case VEC3D: {
|
|
||||||
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createDoubleBuffer(capacity * 3));
|
|
||||||
} break;
|
|
||||||
case VEC4F: {
|
|
||||||
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createFloatBuffer(capacity * 4));
|
|
||||||
} break;
|
|
||||||
case VEC4D: {
|
|
||||||
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createDoubleBuffer(capacity * 4));
|
|
||||||
} break;
|
|
||||||
case DOUBLE: {
|
|
||||||
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createDoubleBuffer(capacity));
|
|
||||||
} break;
|
|
||||||
case FLOAT: {
|
|
||||||
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createFloatBuffer(capacity));
|
|
||||||
} break;
|
|
||||||
case INT: {
|
|
||||||
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createIntBuffer(capacity));
|
|
||||||
} break;
|
|
||||||
case MAT4F: {
|
|
||||||
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createFloatBuffer(capacity * 4 * 4));
|
|
||||||
} break;
|
|
||||||
case MAT4D: {
|
|
||||||
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createFloatBuffer(capacity * 4 * 4));
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
if(shaderAttribute.isSingleIndex()){
|
|
||||||
attributeGlBufferMap.put(shaderAttribute,HomogenousInstancedArray.createHomogenousInstancedArray(shaderAttribute.getIndex(), type, capacity));
|
|
||||||
} else {
|
|
||||||
attributeGlBufferMap.put(shaderAttribute,HomogenousInstancedArray.createHomogenousInstancedArray(shaderAttribute.getIndices(), type, capacity));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an actor to be sorted in the queue
|
* Adds an actor to be sorted in the queue
|
||||||
* @param actor The actor to be sorted
|
* @param actor The actor to be sorted
|
||||||
*/
|
*/
|
||||||
protected void addInstance(InstancedActor actor){
|
public void addInstance(InstancedActor actor);
|
||||||
actorQueue.add(actor);
|
|
||||||
drawCalls++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the number of entries that are to be drawn
|
* Gets the number of entries that are to be drawn
|
||||||
* @return The number of entries to be drawn
|
* @return The number of entries to be drawn
|
||||||
*/
|
*/
|
||||||
public int getDrawCount(){
|
public int getDrawCount();
|
||||||
return drawCalls;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the queue
|
* Clears the queue
|
||||||
*/
|
*/
|
||||||
protected void clearDrawQueue(){
|
public void clearDrawQueue();
|
||||||
actorQueue.clear();
|
|
||||||
drawCalls = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fills the buffers for the upcoming render call. The intention is to make this emberassingly parallel.
|
* Fills the buffers for the upcoming render call. The intention is to make this emberassingly parallel.
|
||||||
*/
|
*/
|
||||||
protected void fillBuffers(){
|
public void fillBuffers();
|
||||||
int i = 0;
|
|
||||||
//for some reason the limit is not being set correctly. This explicitly forces it for each buffer
|
|
||||||
for(ShaderAttribute attribute : attributeIndices){
|
|
||||||
switch(attributeGlBufferMap.get(attribute).getType()){
|
|
||||||
case VEC3F: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.limit(buffer.capacity());
|
|
||||||
} break;
|
|
||||||
case VEC3D: {
|
|
||||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.limit(buffer.capacity());
|
|
||||||
} break;
|
|
||||||
case VEC4F: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.limit(buffer.capacity());
|
|
||||||
} break;
|
|
||||||
case VEC4D: {
|
|
||||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.limit(buffer.capacity());
|
|
||||||
} break;
|
|
||||||
case MAT4F: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.limit(buffer.capacity());
|
|
||||||
// System.out.println(buffer.position() + " " + buffer.limit());
|
|
||||||
} break;
|
|
||||||
case MAT4D: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.limit(buffer.capacity());
|
|
||||||
} break;
|
|
||||||
case DOUBLE: {
|
|
||||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.limit(buffer.capacity());
|
|
||||||
} break;
|
|
||||||
case FLOAT: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.limit(buffer.capacity());
|
|
||||||
} break;
|
|
||||||
case INT: {
|
|
||||||
IntBuffer buffer = ((IntBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.limit(buffer.capacity());
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
actorQueue.sort(Comparator.naturalOrder());
|
|
||||||
//buffer data
|
|
||||||
for(InstancedActor actor : actorQueue){
|
|
||||||
//push values to attribute buffers
|
|
||||||
for(ShaderAttribute attribute : attributeIndices){
|
|
||||||
switch(attributeGlBufferMap.get(attribute).getType()){
|
|
||||||
case VEC3F: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
Vector3f vec = (Vector3f)actor.getAttributeValue(attribute);
|
|
||||||
buffer.put(vec.x);
|
|
||||||
buffer.put(vec.y);
|
|
||||||
buffer.put(vec.z);
|
|
||||||
} break;
|
|
||||||
case VEC3D: {
|
|
||||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
Vector3d vec = (Vector3d)actor.getAttributeValue(attribute);
|
|
||||||
buffer.put(vec.x);
|
|
||||||
buffer.put(vec.y);
|
|
||||||
buffer.put(vec.z);
|
|
||||||
} break;
|
|
||||||
case VEC4F: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
Vector4f vec = (Vector4f)actor.getAttributeValue(attribute);
|
|
||||||
buffer.put(vec.w);
|
|
||||||
buffer.put(vec.x);
|
|
||||||
buffer.put(vec.y);
|
|
||||||
buffer.put(vec.z);
|
|
||||||
} break;
|
|
||||||
case VEC4D: {
|
|
||||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
Vector4d vec = (Vector4d)actor.getAttributeValue(attribute);
|
|
||||||
buffer.put(vec.w);
|
|
||||||
buffer.put(vec.x);
|
|
||||||
buffer.put(vec.y);
|
|
||||||
buffer.put(vec.z);
|
|
||||||
} break;
|
|
||||||
case MAT4F: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
Matrix4f mat = (Matrix4f)actor.getAttributeValue(attribute);
|
|
||||||
buffer.put(mat.m00());
|
|
||||||
buffer.put(mat.m01());
|
|
||||||
buffer.put(mat.m02());
|
|
||||||
buffer.put(mat.m03());
|
|
||||||
|
|
||||||
buffer.put(mat.m10());
|
|
||||||
buffer.put(mat.m11());
|
|
||||||
buffer.put(mat.m12());
|
|
||||||
buffer.put(mat.m13());
|
|
||||||
|
|
||||||
buffer.put(mat.m20());
|
|
||||||
buffer.put(mat.m21());
|
|
||||||
buffer.put(mat.m22());
|
|
||||||
buffer.put(mat.m23());
|
|
||||||
|
|
||||||
buffer.put(mat.m30());
|
|
||||||
buffer.put(mat.m31());
|
|
||||||
buffer.put(mat.m32());
|
|
||||||
buffer.put(mat.m33());
|
|
||||||
} break;
|
|
||||||
case MAT4D: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
Matrix4d mat = (Matrix4d)actor.getAttributeValue(attribute);
|
|
||||||
buffer.put((float)mat.m00());
|
|
||||||
buffer.put((float)mat.m01());
|
|
||||||
buffer.put((float)mat.m02());
|
|
||||||
buffer.put((float)mat.m03());
|
|
||||||
|
|
||||||
buffer.put((float)mat.m10());
|
|
||||||
buffer.put((float)mat.m11());
|
|
||||||
buffer.put((float)mat.m12());
|
|
||||||
buffer.put((float)mat.m13());
|
|
||||||
|
|
||||||
buffer.put((float)mat.m20());
|
|
||||||
buffer.put((float)mat.m21());
|
|
||||||
buffer.put((float)mat.m22());
|
|
||||||
buffer.put((float)mat.m23());
|
|
||||||
|
|
||||||
buffer.put((float)mat.m30());
|
|
||||||
buffer.put((float)mat.m31());
|
|
||||||
buffer.put((float)mat.m32());
|
|
||||||
buffer.put((float)mat.m33());
|
|
||||||
} break;
|
|
||||||
case DOUBLE: {
|
|
||||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.put((Double)actor.getAttributeValue(attribute));
|
|
||||||
} break;
|
|
||||||
case FLOAT: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.put((Float)actor.getAttributeValue(attribute));
|
|
||||||
} break;
|
|
||||||
case INT: {
|
|
||||||
IntBuffer buffer = ((IntBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
buffer.put((Integer)actor.getAttributeValue(attribute));
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//increment
|
|
||||||
i++;
|
|
||||||
if(i >= capacity){
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//reset all buffers
|
|
||||||
flip();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void flip(){
|
|
||||||
//reset all buffers
|
|
||||||
for(ShaderAttribute attribute : attributeIndices){
|
|
||||||
switch(attributeGlBufferMap.get(attribute).getType()){
|
|
||||||
case VEC3F: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
if(buffer.position() > 0){
|
|
||||||
buffer.flip();
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case VEC3D: {
|
|
||||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
if(buffer.position() > 0){
|
|
||||||
buffer.flip();
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case VEC4F: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
if(buffer.position() > 0){
|
|
||||||
buffer.flip();
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case VEC4D: {
|
|
||||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
if(buffer.position() > 0){
|
|
||||||
buffer.flip();
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case MAT4F: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
if(buffer.position() > 0){
|
|
||||||
buffer.flip();
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case MAT4D: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
if(buffer.position() > 0){
|
|
||||||
buffer.flip();
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case DOUBLE: {
|
|
||||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
if(buffer.position() > 0){
|
|
||||||
buffer.flip();
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case FLOAT: {
|
|
||||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
if(buffer.position() > 0){
|
|
||||||
buffer.flip();
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case INT: {
|
|
||||||
IntBuffer buffer = ((IntBuffer)attributeCpuBufferMap.get(attribute));
|
|
||||||
if(buffer.position() > 0){
|
|
||||||
buffer.flip();
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a map of all attributes to the buffers of data for that attribute
|
* Flips the buffer(s)
|
||||||
* @return The data buffers
|
|
||||||
*/
|
*/
|
||||||
public Map<ShaderAttribute,Object> getCpuBufferMap(){
|
public void flip();
|
||||||
return attributeCpuBufferMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a map of attribute name to gl homogenous buffer object
|
* Gets the vertex shader associated with this data
|
||||||
* @return The map
|
* @return The vertex shader
|
||||||
*/
|
*/
|
||||||
public Map<ShaderAttribute,HomogenousInstancedArray> getGlBufferMap(){
|
public String getVertexShader();
|
||||||
return attributeGlBufferMap;
|
|
||||||
}
|
/**
|
||||||
|
* Gets the fragment shader associated with this data
|
||||||
|
* @return The fragment shader
|
||||||
|
*/
|
||||||
|
public String getFragmentShader();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uploads the instance data
|
||||||
|
*/
|
||||||
|
public void upload(OpenGLState openGLState, RenderPipelineState renderPipelineState);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys the data
|
||||||
|
*/
|
||||||
|
public void destroy();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,7 +49,7 @@ public class InstanceManager {
|
|||||||
InstancedActor rVal = new InstancedActor(modelPath);
|
InstancedActor rVal = new InstancedActor(modelPath);
|
||||||
if(!pathToInstanceData.containsKey(modelPath)){
|
if(!pathToInstanceData.containsKey(modelPath)){
|
||||||
//create instance data
|
//create instance data
|
||||||
InstanceData instanceData = new InstanceData(capacity,vertexShaderPath,fragmentShaderPath);
|
HomogenousInstanceData instanceData = new HomogenousInstanceData(capacity,vertexShaderPath,fragmentShaderPath);
|
||||||
//queue shader
|
//queue shader
|
||||||
Globals.assetManager.addShaderToQueue(vertexShaderPath, fragmentShaderPath);
|
Globals.assetManager.addShaderToQueue(vertexShaderPath, fragmentShaderPath);
|
||||||
//if asset manager doesn't have model, queue model
|
//if asset manager doesn't have model, queue model
|
||||||
@ -84,7 +84,7 @@ public class InstanceManager {
|
|||||||
data.fillBuffers();
|
data.fillBuffers();
|
||||||
|
|
||||||
//fetch model/shader and draw if both available
|
//fetch model/shader and draw if both available
|
||||||
ShaderProgram shader = Globals.assetManager.fetchShader(data.vertexShaderPath, null, data.fragmentShaderPath);
|
ShaderProgram shader = Globals.assetManager.fetchShader(data.getVertexShader(), null, data.getFragmentShader());
|
||||||
Model model = Globals.assetManager.fetchModel(modelPath);
|
Model model = Globals.assetManager.fetchModel(modelPath);
|
||||||
if(model != null && shader != null){
|
if(model != null && shader != null){
|
||||||
openGLState.setActiveShader(renderPipelineState, shader);
|
openGLState.setActiveShader(renderPipelineState, shader);
|
||||||
|
|||||||
@ -0,0 +1,237 @@
|
|||||||
|
package electrosphere.renderer.actor.instance;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.joml.Matrix4d;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.joml.Vector4d;
|
||||||
|
import org.joml.Vector4f;
|
||||||
|
|
||||||
|
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
|
||||||
|
import electrosphere.renderer.buffer.HomogenousUniformBuffer;
|
||||||
|
import electrosphere.renderer.buffer.ShaderAttribute;
|
||||||
|
import electrosphere.renderer.buffer.ShaderStorageBuffer;
|
||||||
|
import electrosphere.renderer.OpenGLState;
|
||||||
|
import electrosphere.renderer.RenderPipelineState;
|
||||||
|
import electrosphere.renderer.buffer.BufferEnums.BufferAccess;
|
||||||
|
import electrosphere.renderer.buffer.BufferEnums.BufferUsage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instance data that uses a single buffer with strided input
|
||||||
|
*/
|
||||||
|
public class StridedInstanceData implements InstanceData {
|
||||||
|
|
||||||
|
//the capacity (number of instanced) of this data block. Defaults to 100
|
||||||
|
int capacity = 1000;
|
||||||
|
|
||||||
|
//shader paths
|
||||||
|
String vertexShaderPath;
|
||||||
|
String fragmentShaderPath;
|
||||||
|
|
||||||
|
//the number of draw calls since the last clear operation
|
||||||
|
int drawCalls = 0;
|
||||||
|
|
||||||
|
//The set of instanced actors to draw
|
||||||
|
List<InstancedActor> actorQueue = null;
|
||||||
|
//Map of actor to index in the buffers that are emitted
|
||||||
|
Map<InstancedActor,Integer> actorIndexMap = new HashMap<InstancedActor,Integer>();
|
||||||
|
//Map of index -> actor used for buffer evictions
|
||||||
|
Map<Integer,InstancedActor> indexActorMap = new HashMap<Integer,InstancedActor>();
|
||||||
|
|
||||||
|
//list of all attribute indices in use by this instance data
|
||||||
|
List<ShaderAttribute> attributeIndices = new LinkedList<ShaderAttribute>();
|
||||||
|
|
||||||
|
//the SSBO
|
||||||
|
ShaderStorageBuffer buffer;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param capacity Capacity of the buffer (number of elements) backing this data
|
||||||
|
*/
|
||||||
|
public StridedInstanceData(int capacity, List<HomogenousBufferTypes> types, String vertexPath, String fragmentPath){
|
||||||
|
int entrySize = 0;
|
||||||
|
for(HomogenousBufferTypes type : types){
|
||||||
|
entrySize = entrySize + HomogenousUniformBuffer.calculateTypeSize(type);
|
||||||
|
}
|
||||||
|
this.capacity = capacity;
|
||||||
|
this.vertexShaderPath = vertexPath;
|
||||||
|
this.fragmentShaderPath = fragmentPath;
|
||||||
|
actorQueue = new LinkedList<InstancedActor>();
|
||||||
|
this.buffer = new ShaderStorageBuffer(capacity * entrySize, BufferUsage.STREAM, BufferAccess.DRAW);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new type of attribute to this instance data block
|
||||||
|
* @param shaderAttribute The shader attribute
|
||||||
|
* @param type The type of the attribute
|
||||||
|
*/
|
||||||
|
protected void addDataType(ShaderAttribute shaderAttribute, HomogenousBufferTypes type){
|
||||||
|
attributeIndices.add(shaderAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an actor to be sorted in the queue
|
||||||
|
* @param actor The actor to be sorted
|
||||||
|
*/
|
||||||
|
public void addInstance(InstancedActor actor){
|
||||||
|
actorQueue.add(actor);
|
||||||
|
drawCalls++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of entries that are to be drawn
|
||||||
|
* @return The number of entries to be drawn
|
||||||
|
*/
|
||||||
|
public int getDrawCount(){
|
||||||
|
return drawCalls;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the queue
|
||||||
|
*/
|
||||||
|
public void clearDrawQueue(){
|
||||||
|
actorQueue.clear();
|
||||||
|
drawCalls = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills the buffers for the upcoming render call. The intention is to make this emberassingly parallel.
|
||||||
|
*/
|
||||||
|
public void fillBuffers(){
|
||||||
|
int i = 0;
|
||||||
|
ByteBuffer byteBuff = this.buffer.getBuffer();
|
||||||
|
//buffer data
|
||||||
|
for(InstancedActor actor : actorQueue){
|
||||||
|
//push values to attribute buffers
|
||||||
|
for(ShaderAttribute attribute : attributeIndices){
|
||||||
|
switch(attribute.getType()){
|
||||||
|
case VEC3F: {
|
||||||
|
Vector3f vec = (Vector3f)actor.getAttributeValue(attribute);
|
||||||
|
byteBuff.putFloat(vec.x);
|
||||||
|
byteBuff.putFloat(vec.y);
|
||||||
|
byteBuff.putFloat(vec.z);
|
||||||
|
} break;
|
||||||
|
case VEC3D: {
|
||||||
|
Vector3d vec = (Vector3d)actor.getAttributeValue(attribute);
|
||||||
|
byteBuff.putDouble(vec.x);
|
||||||
|
byteBuff.putDouble(vec.y);
|
||||||
|
byteBuff.putDouble(vec.z);
|
||||||
|
} break;
|
||||||
|
case VEC4F: {
|
||||||
|
Vector4f vec = (Vector4f)actor.getAttributeValue(attribute);
|
||||||
|
byteBuff.putFloat(vec.w);
|
||||||
|
byteBuff.putFloat(vec.x);
|
||||||
|
byteBuff.putFloat(vec.y);
|
||||||
|
byteBuff.putFloat(vec.z);
|
||||||
|
} break;
|
||||||
|
case VEC4D: {
|
||||||
|
Vector4d vec = (Vector4d)actor.getAttributeValue(attribute);
|
||||||
|
byteBuff.putDouble(vec.w);
|
||||||
|
byteBuff.putDouble(vec.x);
|
||||||
|
byteBuff.putDouble(vec.y);
|
||||||
|
byteBuff.putDouble(vec.z);
|
||||||
|
} break;
|
||||||
|
case MAT4F: {
|
||||||
|
Matrix4f mat = (Matrix4f)actor.getAttributeValue(attribute);
|
||||||
|
byteBuff.putFloat(mat.m00());
|
||||||
|
byteBuff.putFloat(mat.m01());
|
||||||
|
byteBuff.putFloat(mat.m02());
|
||||||
|
byteBuff.putFloat(mat.m03());
|
||||||
|
|
||||||
|
byteBuff.putFloat(mat.m10());
|
||||||
|
byteBuff.putFloat(mat.m11());
|
||||||
|
byteBuff.putFloat(mat.m12());
|
||||||
|
byteBuff.putFloat(mat.m13());
|
||||||
|
|
||||||
|
byteBuff.putFloat(mat.m20());
|
||||||
|
byteBuff.putFloat(mat.m21());
|
||||||
|
byteBuff.putFloat(mat.m22());
|
||||||
|
byteBuff.putFloat(mat.m23());
|
||||||
|
|
||||||
|
byteBuff.putFloat(mat.m30());
|
||||||
|
byteBuff.putFloat(mat.m31());
|
||||||
|
byteBuff.putFloat(mat.m32());
|
||||||
|
byteBuff.putFloat(mat.m33());
|
||||||
|
} break;
|
||||||
|
case MAT4D: {
|
||||||
|
Matrix4d mat = (Matrix4d)actor.getAttributeValue(attribute);
|
||||||
|
byteBuff.putDouble((float)mat.m00());
|
||||||
|
byteBuff.putDouble((float)mat.m01());
|
||||||
|
byteBuff.putDouble((float)mat.m02());
|
||||||
|
byteBuff.putDouble((float)mat.m03());
|
||||||
|
|
||||||
|
byteBuff.putDouble((float)mat.m10());
|
||||||
|
byteBuff.putDouble((float)mat.m11());
|
||||||
|
byteBuff.putDouble((float)mat.m12());
|
||||||
|
byteBuff.putDouble((float)mat.m13());
|
||||||
|
|
||||||
|
byteBuff.putDouble((float)mat.m20());
|
||||||
|
byteBuff.putDouble((float)mat.m21());
|
||||||
|
byteBuff.putDouble((float)mat.m22());
|
||||||
|
byteBuff.putDouble((float)mat.m23());
|
||||||
|
|
||||||
|
byteBuff.putDouble((float)mat.m30());
|
||||||
|
byteBuff.putDouble((float)mat.m31());
|
||||||
|
byteBuff.putDouble((float)mat.m32());
|
||||||
|
byteBuff.putDouble((float)mat.m33());
|
||||||
|
} break;
|
||||||
|
case DOUBLE: {
|
||||||
|
byteBuff.putDouble((Double)actor.getAttributeValue(attribute));
|
||||||
|
} break;
|
||||||
|
case FLOAT: {
|
||||||
|
byteBuff.putFloat((Float)actor.getAttributeValue(attribute));
|
||||||
|
} break;
|
||||||
|
case INT: {
|
||||||
|
byteBuff.putInt((Integer)actor.getAttributeValue(attribute));
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//increment
|
||||||
|
i++;
|
||||||
|
if(i >= capacity){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//reset all buffers
|
||||||
|
flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flips the data buffer(s)
|
||||||
|
*/
|
||||||
|
public void flip(){
|
||||||
|
this.buffer.getBuffer().flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getVertexShader(){
|
||||||
|
return vertexShaderPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFragmentShader(){
|
||||||
|
return fragmentShaderPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void upload(OpenGLState openGLState, RenderPipelineState renderPipelineState){
|
||||||
|
this.buffer.upload();
|
||||||
|
openGLState.glBindBufferBase(0, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
if(this.buffer != null){
|
||||||
|
this.buffer.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
97
src/main/java/electrosphere/renderer/buffer/BufferEnums.java
Normal file
97
src/main/java/electrosphere/renderer/buffer/BufferEnums.java
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
package electrosphere.renderer.buffer;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL45;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enums for various buffer data
|
||||||
|
*/
|
||||||
|
public class BufferEnums {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Buffer usage enum
|
||||||
|
*/
|
||||||
|
public static enum BufferUsage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data store contents will be modified once and used many times.
|
||||||
|
*/
|
||||||
|
STATIC,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data store contents will be modified once and used at most a few times.
|
||||||
|
*/
|
||||||
|
STREAM,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data store contents will be modified repeatedly and used many times.
|
||||||
|
*/
|
||||||
|
DYNAMIC,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Buffer access enum
|
||||||
|
*/
|
||||||
|
public static enum BufferAccess {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data store contents are modified by the application, and used as the source for GL drawing and image specification commands.
|
||||||
|
*/
|
||||||
|
DRAW,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data store contents are modified by reading data from the GL, and used to return that data when queried by the application.
|
||||||
|
*/
|
||||||
|
READ,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data store contents are modified by reading data from the GL, and used as the source for GL drawing and image specification commands.
|
||||||
|
*/
|
||||||
|
COPY,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the constant for the given usage and access combination
|
||||||
|
* @param usage The usage value
|
||||||
|
* @param access The access value
|
||||||
|
* @return The constant
|
||||||
|
*/
|
||||||
|
public static int getBufferUsage(BufferUsage usage, BufferAccess access){
|
||||||
|
if(usage == null || access == null){
|
||||||
|
throw new IllegalArgumentException("Passed null value into getBufferUsage! " + usage + " " + access);
|
||||||
|
}
|
||||||
|
switch(usage){
|
||||||
|
case STATIC: {
|
||||||
|
switch(access){
|
||||||
|
case DRAW:
|
||||||
|
return GL45.GL_STATIC_DRAW;
|
||||||
|
case READ:
|
||||||
|
return GL45.GL_STATIC_READ;
|
||||||
|
case COPY:
|
||||||
|
return GL45.GL_STATIC_COPY;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case STREAM: {
|
||||||
|
switch(access){
|
||||||
|
case DRAW:
|
||||||
|
return GL45.GL_STREAM_DRAW;
|
||||||
|
case READ:
|
||||||
|
return GL45.GL_STREAM_READ;
|
||||||
|
case COPY:
|
||||||
|
return GL45.GL_STREAM_COPY;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case DYNAMIC: {
|
||||||
|
switch(access){
|
||||||
|
case DRAW:
|
||||||
|
return GL45.GL_DYNAMIC_DRAW;
|
||||||
|
case READ:
|
||||||
|
return GL45.GL_DYNAMIC_READ;
|
||||||
|
case COPY:
|
||||||
|
return GL45.GL_DYNAMIC_COPY;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Somehow hit unreachable code! " + access + " " + usage);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -119,6 +119,43 @@ public class HomogenousUniformBuffer {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the number of bytes required by this type
|
||||||
|
* @return The number of bytes
|
||||||
|
*/
|
||||||
|
public static int calculateTypeSize(HomogenousBufferTypes type){
|
||||||
|
switch(type){
|
||||||
|
case VEC3F: {
|
||||||
|
return 3 * 4;
|
||||||
|
}
|
||||||
|
case VEC3D: {
|
||||||
|
return 3 * 8;
|
||||||
|
}
|
||||||
|
case VEC4F: {
|
||||||
|
return 4 * 4;
|
||||||
|
}
|
||||||
|
case VEC4D: {
|
||||||
|
return 4 * 8;
|
||||||
|
}
|
||||||
|
case DOUBLE: {
|
||||||
|
return 1 * 8;
|
||||||
|
}
|
||||||
|
case FLOAT: {
|
||||||
|
return 1 * 4;
|
||||||
|
}
|
||||||
|
case INT: {
|
||||||
|
return 1 * 4;
|
||||||
|
}
|
||||||
|
case MAT4F: {
|
||||||
|
return 4 * 4 * 4;
|
||||||
|
}
|
||||||
|
case MAT4D: {
|
||||||
|
return 4 * 4 * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether this buffer is ready to stream data to or bind
|
* Returns whether this buffer is ready to stream data to or bind
|
||||||
* @return True if ready, false otherwise
|
* @return True if ready, false otherwise
|
||||||
|
|||||||
@ -0,0 +1,54 @@
|
|||||||
|
package electrosphere.renderer.buffer;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL45;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An opengl buffer
|
||||||
|
*/
|
||||||
|
public interface OpenGLBuffer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the buffer
|
||||||
|
*/
|
||||||
|
public static enum BufferType {
|
||||||
|
/**
|
||||||
|
* An array buffer
|
||||||
|
*/
|
||||||
|
GL_ARRAY_BUFFER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A storage buffer
|
||||||
|
*/
|
||||||
|
GL_SHADER_STORAGE_BUFFER,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the id of the buffer on opengl side
|
||||||
|
* @return The id
|
||||||
|
*/
|
||||||
|
public int getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type of the buffer
|
||||||
|
* @return The type
|
||||||
|
*/
|
||||||
|
public BufferType getType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the int representing the buffer type
|
||||||
|
* @param buffer The buffer
|
||||||
|
*/
|
||||||
|
public static int getTypeInt(OpenGLBuffer buffer){
|
||||||
|
if(buffer == null){
|
||||||
|
throw new IllegalArgumentException("Passed null buffer into getTypeInt! " + buffer);
|
||||||
|
}
|
||||||
|
switch(buffer.getType()){
|
||||||
|
case GL_ARRAY_BUFFER:
|
||||||
|
return GL45.GL_ARRAY_BUFFER;
|
||||||
|
case GL_SHADER_STORAGE_BUFFER:
|
||||||
|
return GL45.GL_SHADER_STORAGE_BUFFER;
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Somehow reached unreachable code! " + buffer + " " + buffer.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
package electrosphere.renderer.buffer;
|
package electrosphere.renderer.buffer;
|
||||||
|
|
||||||
|
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an attribute of a shader.
|
* Represents an attribute of a shader.
|
||||||
* When working with shader attributes, almost all data types are 1-1 where one vec4 can be stored in 1 attribute.
|
* When working with shader attributes, almost all data types are 1-1 where one vec4 can be stored in 1 attribute.
|
||||||
@ -13,6 +15,11 @@ public class ShaderAttribute {
|
|||||||
//for multi-attribute index types (mat4f, mat4d, etc)
|
//for multi-attribute index types (mat4f, mat4d, etc)
|
||||||
int[] attributeIndices;
|
int[] attributeIndices;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the attribute
|
||||||
|
*/
|
||||||
|
HomogenousBufferTypes type;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for 1-1 attribute
|
* Constructor for 1-1 attribute
|
||||||
@ -30,6 +37,15 @@ public class ShaderAttribute {
|
|||||||
this.attributeIndices = attributeIndices;
|
this.attributeIndices = attributeIndices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for 1-1 attribute
|
||||||
|
* @param attributeIndex The attribute index
|
||||||
|
*/
|
||||||
|
public ShaderAttribute(int attributeIndex, HomogenousBufferTypes type){
|
||||||
|
this.attributeIndex = attributeIndex;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the attribute is a 1-1 relation
|
* Checks if the attribute is a 1-1 relation
|
||||||
* @return True if 1-1, false otherwise
|
* @return True if 1-1, false otherwise
|
||||||
@ -54,4 +70,12 @@ public class ShaderAttribute {
|
|||||||
return attributeIndices;
|
return attributeIndices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type of the attribute
|
||||||
|
* @return The type
|
||||||
|
*/
|
||||||
|
public HomogenousBufferTypes getType(){
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,105 @@
|
|||||||
|
package electrosphere.renderer.buffer;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import org.lwjgl.BufferUtils;
|
||||||
|
import org.lwjgl.opengl.GL45;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.renderer.buffer.BufferEnums.BufferAccess;
|
||||||
|
import electrosphere.renderer.buffer.BufferEnums.BufferUsage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A shader storage buffer
|
||||||
|
*/
|
||||||
|
public class ShaderStorageBuffer implements UniformBlockBinding {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id for the buffer
|
||||||
|
*/
|
||||||
|
int id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The java buffer associated with the SSBO
|
||||||
|
*/
|
||||||
|
ByteBuffer buffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param capacity The capacity of the SSBO
|
||||||
|
* @param usage The usage of the buffer
|
||||||
|
* @param access The access of the buffer
|
||||||
|
*/
|
||||||
|
public ShaderStorageBuffer(int capacity, BufferUsage usage, BufferAccess access){
|
||||||
|
//create the buffer java-side
|
||||||
|
buffer = BufferUtils.createByteBuffer(capacity);
|
||||||
|
|
||||||
|
//create the buffer opengl-side
|
||||||
|
id = GL45.glGenBuffers();
|
||||||
|
Globals.renderingEngine.checkError();
|
||||||
|
GL45.glBindBuffer(GL45.GL_SHADER_STORAGE_BUFFER, id);
|
||||||
|
Globals.renderingEngine.checkError();
|
||||||
|
GL45.glBufferData(GL45.GL_SHADER_STORAGE_BUFFER, MemoryUtil.NULL, BufferEnums.getBufferUsage(usage, access));
|
||||||
|
Globals.renderingEngine.checkError();
|
||||||
|
GL45.glBindBuffer(GL45.GL_SHADER_STORAGE_BUFFER,id);
|
||||||
|
Globals.renderingEngine.checkError();
|
||||||
|
GL45.glBindBuffer(GL45.GL_SHADER_STORAGE_BUFFER,UNBIND_ADDRESS);
|
||||||
|
Globals.renderingEngine.checkError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uploads the java side buffer to opengl
|
||||||
|
*/
|
||||||
|
public void upload(){
|
||||||
|
long offset = 0;
|
||||||
|
//bind
|
||||||
|
GL45.glBindBuffer(GL45.GL_SHADER_STORAGE_BUFFER,id);
|
||||||
|
Globals.renderingEngine.checkError();
|
||||||
|
|
||||||
|
//upload
|
||||||
|
GL45.glBufferSubData(GL45.GL_SHADER_STORAGE_BUFFER, offset, buffer);
|
||||||
|
Globals.renderingEngine.checkError();
|
||||||
|
|
||||||
|
//unbind
|
||||||
|
GL45.glBindBuffer(GL45.GL_SHADER_STORAGE_BUFFER,UNBIND_ADDRESS);
|
||||||
|
Globals.renderingEngine.checkError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys the buffer
|
||||||
|
*/
|
||||||
|
public void destroy(){
|
||||||
|
if(buffer != null){
|
||||||
|
//destroy opengl-side buffer
|
||||||
|
GL45.glDeleteBuffers(id);
|
||||||
|
|
||||||
|
//destroy java-side buffer
|
||||||
|
MemoryUtil.memFree(buffer);
|
||||||
|
|
||||||
|
//set the java-side buffer to be null
|
||||||
|
buffer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the java-side buffer
|
||||||
|
* @return The java-side buffer
|
||||||
|
*/
|
||||||
|
public ByteBuffer getBuffer(){
|
||||||
|
return this.buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BufferType getType() {
|
||||||
|
return BufferType.GL_SHADER_STORAGE_BUFFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package electrosphere.renderer.buffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A buffer that can be bound to a uniform block
|
||||||
|
*/
|
||||||
|
public interface UniformBlockBinding extends OpenGLBuffer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The address to use to unbind a buffer
|
||||||
|
*/
|
||||||
|
static final int UNBIND_ADDRESS = 0;
|
||||||
|
|
||||||
|
}
|
||||||
@ -7,8 +7,6 @@ import electrosphere.renderer.RenderPipelineState;
|
|||||||
import electrosphere.renderer.RenderingEngine;
|
import electrosphere.renderer.RenderingEngine;
|
||||||
import electrosphere.renderer.actor.ActorTextureMask;
|
import electrosphere.renderer.actor.ActorTextureMask;
|
||||||
import electrosphere.renderer.actor.instance.InstanceData;
|
import electrosphere.renderer.actor.instance.InstanceData;
|
||||||
import electrosphere.renderer.buffer.HomogenousInstancedArray;
|
|
||||||
import electrosphere.renderer.buffer.ShaderAttribute;
|
|
||||||
import electrosphere.renderer.light.LightManager;
|
import electrosphere.renderer.light.LightManager;
|
||||||
import electrosphere.renderer.shader.ShaderProgram;
|
import electrosphere.renderer.shader.ShaderProgram;
|
||||||
import electrosphere.renderer.texture.Texture;
|
import electrosphere.renderer.texture.Texture;
|
||||||
@ -18,7 +16,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.joml.Matrix4d;
|
import org.joml.Matrix4d;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
@ -323,23 +320,6 @@ public class Mesh {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a buffer to the gpu
|
|
||||||
* @param uniformTypeMap The type of the buffer
|
|
||||||
* @param buffers The buffer
|
|
||||||
*/
|
|
||||||
void bufferInstanceData(
|
|
||||||
RenderPipelineState renderPipelineState,
|
|
||||||
Map<ShaderAttribute,Object> buffers,
|
|
||||||
Map<ShaderAttribute,HomogenousInstancedArray> uniformGlBufferMap
|
|
||||||
){
|
|
||||||
for(ShaderAttribute attribute : buffers.keySet()){
|
|
||||||
HomogenousInstancedArray buffer = uniformGlBufferMap.get(attribute);
|
|
||||||
buffer.updateBuffer(buffers.get(attribute), 0);
|
|
||||||
buffer.bind(renderPipelineState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws the mesh
|
* Draws the mesh
|
||||||
@ -491,11 +471,7 @@ public class Mesh {
|
|||||||
if(renderPipelineState.getInstanced()){
|
if(renderPipelineState.getInstanced()){
|
||||||
if(renderPipelineState.getInstanceData()!=null){
|
if(renderPipelineState.getInstanceData()!=null){
|
||||||
InstanceData instanceData = renderPipelineState.getInstanceData();
|
InstanceData instanceData = renderPipelineState.getInstanceData();
|
||||||
Map<ShaderAttribute,Object> buffers = instanceData.getCpuBufferMap();
|
instanceData.upload(openGLState, renderPipelineState);
|
||||||
Map<ShaderAttribute,HomogenousInstancedArray> glBufferMap = instanceData.getGlBufferMap();
|
|
||||||
bufferInstanceData(renderPipelineState, buffers, glBufferMap);
|
|
||||||
renderPipelineState.setInstanceCount(instanceData.getDrawCount());
|
|
||||||
Globals.renderingEngine.checkError();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -47,7 +47,7 @@ public class FontManager {
|
|||||||
font = new java.awt.Font(java.awt.Font.MONOSPACED, java.awt.Font.PLAIN, 16);
|
font = new java.awt.Font(java.awt.Font.MONOSPACED, java.awt.Font.PLAIN, 16);
|
||||||
}
|
}
|
||||||
if(font!=null){
|
if(font!=null){
|
||||||
defaultFont = FontUtils.loadFont(Globals.renderingEngine.getOpenGLState(), font, false);
|
defaultFont = FontUtils.loadFont(Globals.renderingEngine.getOpenGLState(), font, true);
|
||||||
fontMap.put("default",defaultFont);
|
fontMap.put("default",defaultFont);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,64 @@
|
|||||||
|
package electrosphere.renderer.buffer;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.renderer.OpenGLState;
|
||||||
|
import electrosphere.renderer.buffer.BufferEnums.BufferAccess;
|
||||||
|
import electrosphere.renderer.buffer.BufferEnums.BufferUsage;
|
||||||
|
import electrosphere.test.annotations.UnitTest;
|
||||||
|
import electrosphere.test.template.RenderingTestTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for the shader storage buffer
|
||||||
|
*/
|
||||||
|
public class ShaderStorageBufferTests extends RenderingTestTemplate {
|
||||||
|
|
||||||
|
@UnitTest
|
||||||
|
public void test_Constructor_NoThrow(){
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
new ShaderStorageBuffer(10, BufferUsage.STATIC, BufferAccess.READ);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@UnitTest
|
||||||
|
public void test_Constructor_JavaSideCapacity_10(){
|
||||||
|
ShaderStorageBuffer buffer = new ShaderStorageBuffer(10, BufferUsage.STATIC, BufferAccess.READ);
|
||||||
|
assertEquals(10, buffer.getBuffer().limit());
|
||||||
|
}
|
||||||
|
|
||||||
|
@UnitTest
|
||||||
|
public void test_destroy_NoThrow(){
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
ShaderStorageBuffer buffer = new ShaderStorageBuffer(10, BufferUsage.STATIC, BufferAccess.READ);
|
||||||
|
buffer.destroy();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@UnitTest
|
||||||
|
public void test_destroyTwice_NoThrow(){
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
ShaderStorageBuffer buffer = new ShaderStorageBuffer(10, BufferUsage.STATIC, BufferAccess.READ);
|
||||||
|
buffer.destroy();
|
||||||
|
buffer.destroy();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@UnitTest
|
||||||
|
public void test_upload_NoThrow(){
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
ShaderStorageBuffer buffer = new ShaderStorageBuffer(10, BufferUsage.STATIC, BufferAccess.READ);
|
||||||
|
buffer.upload();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@UnitTest
|
||||||
|
public void test_bind_NoThrow(){
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
ShaderStorageBuffer buffer = new ShaderStorageBuffer(10, BufferUsage.STATIC, BufferAccess.READ);
|
||||||
|
OpenGLState openGLState = Globals.renderingEngine.getOpenGLState();
|
||||||
|
openGLState.glBindBufferBase(0, buffer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -2,25 +2,19 @@ package electrosphere.renderer.framebuffer;
|
|||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
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.engine.Globals;
|
||||||
import electrosphere.renderer.RenderingEngine;
|
import electrosphere.renderer.RenderingEngine;
|
||||||
import electrosphere.renderer.texture.Texture;
|
import electrosphere.renderer.texture.Texture;
|
||||||
import electrosphere.test.template.extensions.StateCleanupCheckerExtension;
|
import electrosphere.test.annotations.UnitTest;
|
||||||
|
import electrosphere.test.template.RenderingTestTemplate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for framebuffer creation utilities
|
* Tests for framebuffer creation utilities
|
||||||
*/
|
*/
|
||||||
@ExtendWith(StateCleanupCheckerExtension.class)
|
public class FramebufferUtilsTests extends RenderingTestTemplate {
|
||||||
public class FramebufferUtilsTests {
|
|
||||||
|
|
||||||
@Test
|
@UnitTest
|
||||||
public void testCreateScreenFramebuffer(){
|
public void testCreateScreenFramebuffer(){
|
||||||
Globals.initGlobals();
|
|
||||||
Globals.renderingEngine = new RenderingEngine();
|
|
||||||
Globals.renderingEngine.createOpenglContext();
|
|
||||||
assertDoesNotThrow(() -> {
|
assertDoesNotThrow(() -> {
|
||||||
Texture screenTextureColor = FramebufferUtils.generateScreenTextureColorAlpha(Globals.renderingEngine.getOpenGLState(), Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
|
Texture screenTextureColor = FramebufferUtils.generateScreenTextureColorAlpha(Globals.renderingEngine.getOpenGLState(), Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
|
||||||
RenderingEngine.screenTextureColor = screenTextureColor;
|
RenderingEngine.screenTextureColor = screenTextureColor;
|
||||||
@ -29,11 +23,9 @@ public class FramebufferUtilsTests {
|
|||||||
Framebuffer screenFramebuffer = FramebufferUtils.generateScreenTextureFramebuffer(Globals.renderingEngine.getOpenGLState(), Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, screenTextureColor, screenTextureDepth);
|
Framebuffer screenFramebuffer = FramebufferUtils.generateScreenTextureFramebuffer(Globals.renderingEngine.getOpenGLState(), Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, screenTextureColor, screenTextureDepth);
|
||||||
RenderingEngine.screenFramebuffer = screenFramebuffer;
|
RenderingEngine.screenFramebuffer = screenFramebuffer;
|
||||||
});
|
});
|
||||||
Globals.renderingEngine.destroy();
|
|
||||||
Globals.resetGlobals();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@UnitTest
|
||||||
public void testCreateScreenFramebufferRepeat(){
|
public void testCreateScreenFramebufferRepeat(){
|
||||||
assertDoesNotThrow(() -> {
|
assertDoesNotThrow(() -> {
|
||||||
Globals.initGlobals();
|
Globals.initGlobals();
|
||||||
@ -51,8 +43,6 @@ public class FramebufferUtilsTests {
|
|||||||
screenTextureColor = FramebufferUtils.generateScreenTextureColorAlpha(Globals.renderingEngine.getOpenGLState(), Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
|
screenTextureColor = FramebufferUtils.generateScreenTextureColorAlpha(Globals.renderingEngine.getOpenGLState(), Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
|
||||||
screenTextureDepth = FramebufferUtils.generateScreenTextureDepth(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);
|
FramebufferUtils.generateScreenTextureFramebuffer(Globals.renderingEngine.getOpenGLState(), Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, screenTextureColor, screenTextureDepth);
|
||||||
Globals.renderingEngine.destroy();
|
|
||||||
Globals.resetGlobals();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,13 +3,13 @@ package electrosphere.renderer.ui.elements;
|
|||||||
import electrosphere.test.annotations.IntegrationTest;
|
import electrosphere.test.annotations.IntegrationTest;
|
||||||
import electrosphere.menu.WindowUtils;
|
import electrosphere.menu.WindowUtils;
|
||||||
import electrosphere.menu.mainmenu.MenuGeneratorsUITesting;
|
import electrosphere.menu.mainmenu.MenuGeneratorsUITesting;
|
||||||
import electrosphere.test.template.RenderingTestTemplate;
|
import electrosphere.test.template.UITestTemplate;
|
||||||
import electrosphere.test.testutils.TestEngineUtils;
|
import electrosphere.test.testutils.TestEngineUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for the window class
|
* Tests for the window class
|
||||||
*/
|
*/
|
||||||
public class WindowTest extends RenderingTestTemplate {
|
public class WindowTest extends UITestTemplate {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests creating a window
|
* Tests creating a window
|
||||||
|
|||||||
@ -0,0 +1,43 @@
|
|||||||
|
package electrosphere.test.template;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Tag;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
||||||
|
import electrosphere.test.template.extensions.StateCleanupCheckerExtension;
|
||||||
|
import electrosphere.test.template.extensions.UIExtension;
|
||||||
|
|
||||||
|
import static electrosphere.test.testutils.Assertions.*;
|
||||||
|
import electrosphere.test.testutils.TestRenderingUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A test class that involves testing renders
|
||||||
|
*/
|
||||||
|
@Tag("integration")
|
||||||
|
@Tag("graphical")
|
||||||
|
@ExtendWith(StateCleanupCheckerExtension.class)
|
||||||
|
@ExtendWith(UIExtension.class)
|
||||||
|
public class UITestTemplate {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the most recent render versus an existing image
|
||||||
|
* @param renderName The name associated with the render
|
||||||
|
* @param existingRenderPath The path to the existing image
|
||||||
|
*/
|
||||||
|
public void checkRender(String renderName, String existingRenderPath){
|
||||||
|
//of the format "electrosphere.renderer.ui.elements.WindowTest"
|
||||||
|
String canonicalName = this.getClass().getCanonicalName();
|
||||||
|
|
||||||
|
//check the render
|
||||||
|
assertEqualsRender(existingRenderPath, () -> {
|
||||||
|
|
||||||
|
//on failure, save the failed render
|
||||||
|
String failureSavePath = "./.testcache/" + canonicalName + "-" + renderName + ".png";
|
||||||
|
File saveFile = new File(failureSavePath);
|
||||||
|
System.err.println("[[ATTACHMENT|" + saveFile.getAbsolutePath() + "]]");
|
||||||
|
TestRenderingUtils.saveTestRender(failureSavePath);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -5,8 +5,7 @@ import org.junit.jupiter.api.extension.BeforeEachCallback;
|
|||||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||||
|
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.engine.Main;
|
import electrosphere.renderer.RenderingEngine;
|
||||||
import electrosphere.test.testutils.EngineInit;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spins up an tears down generic rendering environment
|
* Spins up an tears down generic rendering environment
|
||||||
@ -15,17 +14,15 @@ public class RenderingExtension implements BeforeEachCallback, AfterEachCallback
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void beforeEach(ExtensionContext context) throws Exception {
|
public void beforeEach(ExtensionContext context) throws Exception {
|
||||||
Globals.WINDOW_DECORATED = false;
|
Globals.initGlobals();
|
||||||
Globals.WINDOW_FULLSCREEN = true;
|
Globals.renderingEngine = new RenderingEngine();
|
||||||
Globals.RUN_AUDIO = false;
|
Globals.renderingEngine.createOpenglContext();
|
||||||
Globals.WINDOW_WIDTH = 1920;
|
|
||||||
Globals.WINDOW_HEIGHT = 1080;
|
|
||||||
EngineInit.initGraphicalEngine();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterEach(ExtensionContext context) throws Exception {
|
public void afterEach(ExtensionContext context) throws Exception {
|
||||||
Main.shutdown();
|
Globals.renderingEngine.destroy();
|
||||||
|
Globals.resetGlobals();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -26,6 +26,7 @@ public class StateCleanupCheckerExtension implements AfterEachCallback {
|
|||||||
Globals.clientSynchronizationManager,
|
Globals.clientSynchronizationManager,
|
||||||
Globals.server,
|
Globals.server,
|
||||||
Globals.serverSynchronizationManager,
|
Globals.serverSynchronizationManager,
|
||||||
|
Globals.playerManager,
|
||||||
LoggerInterface.loggerEngine,
|
LoggerInterface.loggerEngine,
|
||||||
RenderingEngine.screenFramebuffer,
|
RenderingEngine.screenFramebuffer,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
package electrosphere.test.template.extensions;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.extension.AfterEachCallback;
|
||||||
|
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
||||||
|
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.engine.Main;
|
||||||
|
import electrosphere.test.testutils.EngineInit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spins up an tears down generic ui environment
|
||||||
|
*/
|
||||||
|
public class UIExtension implements BeforeEachCallback, AfterEachCallback {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeEach(ExtensionContext context) throws Exception {
|
||||||
|
Globals.WINDOW_DECORATED = false;
|
||||||
|
Globals.WINDOW_FULLSCREEN = true;
|
||||||
|
Globals.RUN_AUDIO = false;
|
||||||
|
Globals.WINDOW_WIDTH = 1920;
|
||||||
|
Globals.WINDOW_HEIGHT = 1080;
|
||||||
|
EngineInit.initGraphicalEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterEach(ExtensionContext context) throws Exception {
|
||||||
|
Main.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 33 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB |
Loading…
Reference in New Issue
Block a user