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 modelsLoadedIntoMemory = new ConcurrentHashMap(); List modelsInQueue = new CopyOnWriteArrayList(); List shaderOverrides = new CopyOnWriteArrayList(); Map texturesLoadedIntoMemory = new ConcurrentHashMap(); List texturesInQueue = new CopyOnWriteArrayList(); Map audioLoadedIntoMemory = new ConcurrentHashMap(); List audioInQueue = new CopyOnWriteArrayList(); Map shadersLoadedIntoMemory = new ConcurrentHashMap(); List shadersInQueue = new CopyOnWriteArrayList(); Map physicsMeshesLoadedIntoMemory = new ConcurrentHashMap(); List physicsMeshesToLoad = new CopyOnWriteArrayList(); Map poseModelsLoadedIntoMemory = new ConcurrentHashMap(); List poseModelsInQueue = new CopyOnWriteArrayList(); //A queue of homogenous buffers to allocate this render frame List homogenousBufferAllocationQueue = new CopyOnWriteArrayList(); //A queue of homogenous buffers to allocate this render frame List instanceArrayBufferAllocationQueue = new CopyOnWriteArrayList(); // //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 toRemove = new LinkedList(); 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); } }