Renderer/src/main/java/electrosphere/engine/assetmanager/AssetManager.java
2024-03-23 23:19:06 -04:00

436 lines
14 KiB
Java

package electrosphere.engine.assetmanager;
import electrosphere.audio.AudioBuffer;
import electrosphere.collision.CollisionBodyCreation;
import electrosphere.collision.CollisionEngine;
import electrosphere.collision.PhysicsUtils;
import electrosphere.collision.collidable.Collidable;
import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.actor.ActorShaderMask;
import electrosphere.renderer.buffer.HomogenousInstancedArray;
import electrosphere.renderer.buffer.HomogenousUniformBuffer;
import electrosphere.renderer.loading.ModelLoader;
import electrosphere.renderer.model.Mesh;
import electrosphere.renderer.model.Model;
import electrosphere.renderer.shader.ShaderProgram;
import electrosphere.renderer.texture.Texture;
import electrosphere.server.poseactor.PoseModel;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import org.lwjgl.assimp.AIScene;
import org.ode4j.ode.DBody;
import org.ode4j.ode.DWorld;
/**
*
* @author amaterasu
*/
public class AssetManager {
Map<String,Model> modelsLoadedIntoMemory = new ConcurrentHashMap<String,Model>();
List<String> modelsInQueue = new CopyOnWriteArrayList<String>();
List<MeshShaderOverride> shaderOverrides = new CopyOnWriteArrayList<MeshShaderOverride>();
Map<String,Texture> texturesLoadedIntoMemory = new ConcurrentHashMap<String,Texture>();
List<String> texturesInQueue = new CopyOnWriteArrayList<String>();
Map<String,AudioBuffer> audioLoadedIntoMemory = new ConcurrentHashMap<String,AudioBuffer>();
List<String> audioInQueue = new CopyOnWriteArrayList<String>();
Map<String,ShaderProgram> shadersLoadedIntoMemory = new ConcurrentHashMap<String,ShaderProgram>();
List<ActorShaderMask> shadersInQueue = new CopyOnWriteArrayList<ActorShaderMask>();
Map<String,DBody> physicsMeshesLoadedIntoMemory = new ConcurrentHashMap<String,DBody>();
List<PhysicsMeshQueueItem> physicsMeshesToLoad = new CopyOnWriteArrayList<PhysicsMeshQueueItem>();
Map<String,PoseModel> poseModelsLoadedIntoMemory = new ConcurrentHashMap<String,PoseModel>();
List<String> poseModelsInQueue = new CopyOnWriteArrayList<String>();
//A queue of homogenous buffers to allocate this render frame
List<HomogenousUniformBuffer> homogenousBufferAllocationQueue = new CopyOnWriteArrayList<HomogenousUniformBuffer>();
//A queue of homogenous buffers to allocate this render frame
List<HomogenousInstancedArray> instanceArrayBufferAllocationQueue = new CopyOnWriteArrayList<HomogenousInstancedArray>();
//
//General asset manager stuff
//
/**
* For each class/type of asset, load all assets in queue
*/
public void loadAssetsInQueue(){
//models
for(String currentPath : modelsInQueue){
modelsInQueue.remove(currentPath);
AIScene aiScene = ModelLoader.loadAIScene(currentPath);
modelsLoadedIntoMemory.put(currentPath, ModelLoader.createModelFromAiScene(aiScene,currentPath));
for(PhysicsMeshQueueItem physicsMeshQueueItem : physicsMeshesToLoad){
if(physicsMeshQueueItem.modelPath.contains(currentPath)){
//create physics
physicsMeshesToLoad.remove(physicsMeshQueueItem);
physicsMeshesLoadedIntoMemory.put(
getCollisionMeshMapKey(physicsMeshQueueItem.collisionEngine,currentPath),
CollisionBodyCreation.generateRigidBodyFromAIScene(physicsMeshQueueItem.collisionEngine,aiScene,Collidable.TYPE_STATIC_BIT)
);
}
}
}
//textures from disk to gpu
for(String currentPath : texturesInQueue){
texturesInQueue.remove(currentPath);
texturesLoadedIntoMemory.put(currentPath, new Texture(currentPath));
}
//audio from disk
for(String currentPath : audioInQueue){
audioInQueue.remove(currentPath);
audioLoadedIntoMemory.put(currentPath, new AudioBuffer(currentPath));
}
//shaders
for(ActorShaderMask currentShader : shadersInQueue){
shadersInQueue.remove(currentShader);
String key = getShaderKey(currentShader.getVertexShaderPath(),currentShader.getGeometryShaderPath(),currentShader.getFragmentShaderPath());
if(currentShader.getGeometryShaderPath() == null){
shadersLoadedIntoMemory.put(
key,
ShaderProgram.loadSpecificShader(currentShader.getVertexShaderPath(),currentShader.getFragmentShaderPath())
);
} else {
shadersLoadedIntoMemory.put(
key,
ShaderProgram.loadSpecificShader(currentShader.getVertexShaderPath(),currentShader.getGeometryShaderPath(),currentShader.getFragmentShaderPath())
);
}
}
//pose models
for(String currentPath: poseModelsInQueue){
poseModelsInQueue.remove(currentPath);
AIScene scene = ModelLoader.loadAIScene(currentPath);
poseModelsLoadedIntoMemory.put(currentPath, new PoseModel(currentPath, scene));
}
//allocate homogenous buffers
allocateHomogenousBuffers();
//allocate instance array buffers
allocateInstanceArrayBuffers();
//override meshes
performMeshOverrides();
}
//
//Models
//
public void addModelPathToQueue(String path){
if(!modelsInQueue.contains(path) && !modelsLoadedIntoMemory.containsKey(path)){
modelsInQueue.add(path);
}
}
public Model fetchModel(String path){
Model rVal = null;
if(modelsLoadedIntoMemory.containsKey(path)){
rVal = modelsLoadedIntoMemory.get(path);
}
return rVal;
}
/**
Registers a (presumably generated in code) model with the asset manager
@returns a random string that represents the model in the asset manager
*/
public String registerModel(Model m){
String rVal;
UUID newUUID = UUID.randomUUID();
rVal = newUUID.toString();
modelsLoadedIntoMemory.put(rVal,m);
return rVal;
}
/**
* Registers a (presumably generated in code) model to a given path in the asset manager
* Used particularly if you have a specific path you want to relate to a specific model (eg terrain chunk code)
* @param m The model to register
* @param path The path to register the model to
*/
public void registerModelWithPath(Model m, String path){
modelsLoadedIntoMemory.put(path, m);
}
public void registerModelToSpecificString(Model m, String s){
modelsLoadedIntoMemory.put(s,m);
}
public void deregisterModelPath(String path){
modelsLoadedIntoMemory.remove(path);
}
public void queueOverrideMeshShader(String modelName, String meshName, String vertPath, String fragPath){
MeshShaderOverride override = new MeshShaderOverride(modelName,meshName,vertPath,fragPath);
shaderOverrides.add(override);
}
public void performMeshOverrides(){
List<MeshShaderOverride> toRemove = new LinkedList<MeshShaderOverride>();
for(MeshShaderOverride shaderOverride : shaderOverrides){
Model model = null;
if((model = fetchModel(shaderOverride.modelName)) != null){
for(Mesh mesh : model.getMeshes()){
if(mesh.getMeshName().equals(shaderOverride.getMeshName())){
mesh.setShader(ShaderProgram.loadSpecificShader(shaderOverride.vertPath, shaderOverride.fragPath));
}
}
toRemove.add(shaderOverride);
}
}
for(MeshShaderOverride shaderOverride : toRemove){
shaderOverrides.remove(shaderOverride);
}
}
/**
* Nuclear function, reloads all shaders loaded into memory
*/
public void forceReloadAllModels(){
for(String modelKey : modelsLoadedIntoMemory.keySet()){
if(modelKey.contains("Models")){
modelsInQueue.add(modelKey);
modelsLoadedIntoMemory.remove(modelKey);
}
}
// modelsLoadedIntoMemory.clear();
}
//
//Pose Models
//
public void addPoseModelPathToQueue(String path){
if(!poseModelsInQueue.contains(path) && !poseModelsLoadedIntoMemory.containsKey(path)){
poseModelsInQueue.add(path);
}
}
public PoseModel fetchPoseModel(String path){
PoseModel rVal = null;
if(poseModelsLoadedIntoMemory.containsKey(path)){
rVal = poseModelsLoadedIntoMemory.get(path);
}
return rVal;
}
//
// Textures
//
public void addTexturePathtoQueue(String path){
if(!texturesInQueue.contains(path) && !texturesLoadedIntoMemory.containsKey(path)){
texturesInQueue.add(path);
}
}
public Texture fetchTexture(String path){
Texture rVal = null;
if(texturesLoadedIntoMemory.containsKey(path)){
rVal = texturesLoadedIntoMemory.get(path);
}
return rVal;
}
public String registerTexture(Texture t){
String rVal;
UUID newUUID = UUID.randomUUID();
rVal = newUUID.toString();
texturesLoadedIntoMemory.put(rVal,t);
return rVal;
}
public boolean hasLoadedTexture(String path){
return texturesLoadedIntoMemory.containsKey(path);
}
//
//AUDIO
//
public void addAudioPathToQueue(String path){
if(!audioInQueue.contains(path) && !audioLoadedIntoMemory.containsKey(path)){
audioInQueue.add(path);
}
}
public AudioBuffer fetchAudio(String path){
AudioBuffer rVal = null;
if(audioLoadedIntoMemory.containsKey(path)){
rVal = audioLoadedIntoMemory.get(path);
} else {
LoggerInterface.loggerAudio.WARNING("Failed to find audio " + path);
}
return rVal;
}
//
//SHADERS
//
public void addShaderToQueue(String vertexShader, String fragmentShader){
shadersInQueue.add(new ActorShaderMask("","",vertexShader,null,fragmentShader));
}
public void addShaderToQueue(String vertexShader, String geometryShader, String fragmentShader){
shadersInQueue.add(new ActorShaderMask("","",vertexShader,geometryShader,fragmentShader));
}
public ShaderProgram fetchShader(String vertexPath, String geometryShader, String fragmentPath){
String path = getShaderKey(vertexPath,geometryShader,fragmentPath);
ShaderProgram rVal = null;
if(shadersLoadedIntoMemory.containsKey(path)){
rVal = shadersLoadedIntoMemory.get(path);
}
return rVal;
}
static String getShaderKey(String vertexPath, String geometryPath, String fragmentPath){
return vertexPath + "-" + geometryPath + "-" + fragmentPath;
}
/**
* Nuclear function, reloads all shaders loaded into memory
*/
public void forceReloadAllShaders(){
for(String shaderKey : shadersLoadedIntoMemory.keySet()){
String shaderPaths[] = shaderKey.split("-");
if(shaderPaths[1].equals("null")){
shaderPaths[1] = null;
}
shadersInQueue.add(new ActorShaderMask("","",shaderPaths[0],shaderPaths[1],shaderPaths[2]));
}
shadersLoadedIntoMemory.clear();
}
//
//COLLISION MESH
//
public void addCollisionMeshToQueue(PhysicsMeshQueueItem physicsMeshQueueItem){
if(
!physicsMeshesToLoad.contains(physicsMeshQueueItem) &&
!physicsMeshesLoadedIntoMemory.containsKey(getCollisionMeshMapKey(
physicsMeshQueueItem.collisionEngine,
physicsMeshQueueItem.modelPath
))){
physicsMeshesToLoad.add(physicsMeshQueueItem);
}
}
public DBody fetchCollisionObject(CollisionEngine collisionEngine, String path){
return physicsMeshesLoadedIntoMemory.get(getCollisionMeshMapKey(collisionEngine,path));
}
/**
* Gets a key based on collision engine object hash and path of model
* @param collisionEngine collision engine
* @param path The path
* @return The key
*/
private String getCollisionMeshMapKey(CollisionEngine collisionEngine, String path){
return collisionEngine + path;
}
//
//HOMOGENOUS UNIFORM BUFFERS
//
/**
* Allocates all uniform buffers in queue
*/
public void allocateHomogenousBuffers(){
for(HomogenousUniformBuffer buffer : homogenousBufferAllocationQueue){
buffer.allocate();
}
homogenousBufferAllocationQueue.clear();
}
/**
* Adds a uniform buffer to the queue to be allocated
* @param buffer The buffer
*/
public void addHomogenousBufferToQueue(HomogenousUniformBuffer buffer){
homogenousBufferAllocationQueue.add(buffer);
}
//
//INSTANCE ARRAY BUFFERS
//
/**
* Allocates all instance array buffers in queue
*/
public void allocateInstanceArrayBuffers(){
for(HomogenousInstancedArray buffer : instanceArrayBufferAllocationQueue){
buffer.allocate();
}
instanceArrayBufferAllocationQueue.clear();
}
/**
* Adds an instance array buffer to the queue to be allocated
* @param buffer The buffer
*/
public void addInstanceArrayBufferToQueue(HomogenousInstancedArray buffer){
instanceArrayBufferAllocationQueue.add(buffer);
}
}