editor mode asset file drag'n'drop

This commit is contained in:
austin 2025-03-26 22:34:24 -04:00
parent ed9dac0b80
commit 62ad638255
15 changed files with 603 additions and 39 deletions

View File

@ -1326,6 +1326,8 @@ Fix entity swap button resetting position
Fix block meshgen not incrementing indices correctly Fix block meshgen not incrementing indices correctly
Fix block meshgen algorithm iteration bug Fix block meshgen algorithm iteration bug
Add debug control to swap first/third person Add debug control to swap first/third person
Setup scaffolding for drag-and-drop asset handling
Editor mode asset file drag and drop

View File

@ -4,6 +4,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import electrosphere.client.ui.menu.debug.entity.ImGuiEntityMacros; import electrosphere.client.ui.menu.debug.entity.ImGuiEntityMacros;
import electrosphere.client.ui.menu.editor.ImGuiEditorWindows;
import electrosphere.controls.ControlHandler.ControlsState; import electrosphere.controls.ControlHandler.ControlsState;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.renderer.ui.imgui.ImGuiLinePlot; import electrosphere.renderer.ui.imgui.ImGuiLinePlot;
@ -35,8 +36,8 @@ public class ImGuiWindowMacros {
* Initializes imgui windows * Initializes imgui windows
*/ */
public static void initImGuiWindows(){ public static void initImGuiWindows(){
createMainDebugMenu(); ImGuiWindowMacros.createMainDebugMenu();
createFramerateGraph(); ImGuiWindowMacros.createFramerateGraph();
ImGuiPlayerEntity.createPlayerEntityDebugWindow(); ImGuiPlayerEntity.createPlayerEntityDebugWindow();
ImGuiFluidMonitor.createFluidDebugWindows(); ImGuiFluidMonitor.createFluidDebugWindows();
ImGuiEntityMacros.createClientEntityWindows(); ImGuiEntityMacros.createClientEntityWindows();
@ -51,6 +52,7 @@ public class ImGuiWindowMacros {
ImGuiNetworkMonitor.createNetworkMonitorWindows(); ImGuiNetworkMonitor.createNetworkMonitorWindows();
ImGuiGriddedManager.createGriddedManagerWindows(); ImGuiGriddedManager.createGriddedManagerWindows();
ImGuiMemory.createMemoryWindows(); ImGuiMemory.createMemoryWindows();
ImGuiEditorWindows.initEditorWindows();
} }
/** /**
@ -60,13 +62,13 @@ public class ImGuiWindowMacros {
globalFrametimeWindow = new ImGuiWindow("Frametime Graph"); globalFrametimeWindow = new ImGuiWindow("Frametime Graph");
globalFrametimePlot = new ImGuiLinePlot("Frametime plot"); globalFrametimePlot = new ImGuiLinePlot("Frametime plot");
globalFrametimeDatasets = new HashMap<String,ImGuiLinePlotDataset>(); globalFrametimeDatasets = new HashMap<String,ImGuiLinePlotDataset>();
initFramerateGraphSeries("totalframerate"); ImGuiWindowMacros.initFramerateGraphSeries("totalframerate");
initFramerateGraphSeries("serversim"); ImGuiWindowMacros.initFramerateGraphSeries("serversim");
initFramerateGraphSeries("clientsim"); ImGuiWindowMacros.initFramerateGraphSeries("clientsim");
initFramerateGraphSeries("render"); ImGuiWindowMacros.initFramerateGraphSeries("render");
initFramerateGraphSeries("assetLoad"); ImGuiWindowMacros.initFramerateGraphSeries("assetLoad");
initFramerateGraphSeries("clientNetwork"); ImGuiWindowMacros.initFramerateGraphSeries("clientNetwork");
initFramerateGraphSeries("controls"); ImGuiWindowMacros.initFramerateGraphSeries("controls");
globalFrametimeWindow.addElement(globalFrametimePlot); globalFrametimeWindow.addElement(globalFrametimePlot);
globalFrametimeWindow.setOpen(false); globalFrametimeWindow.setOpen(false);
Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(globalFrametimeWindow); Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(globalFrametimeWindow);

View File

@ -0,0 +1,58 @@
package electrosphere.client.ui.menu.editor;
import electrosphere.controls.ControlHandler.ControlsState;
import electrosphere.engine.Globals;
import electrosphere.renderer.ui.imgui.ImGuiWindow;
import electrosphere.renderer.ui.imgui.ImGuiWindow.ImGuiWindowCallback;
import imgui.ImGui;
/**
* Details window of the editor
*/
public class ImGuiEditorDetailsWindow {
/**
* The window object
*/
private static ImGuiWindow detailsWindow;
/**
* Gets the details window
* @return the details window
*/
public static ImGuiWindow getDetailsWindow(){
return detailsWindow;
}
/**
* Inits the details menu
*/
protected static void createDetailsMenu(){
detailsWindow = new ImGuiWindow("Details");
detailsWindow.setCallback(new ImGuiWindowCallback() {
@Override
public void exec() {
ImGui.text("Some details or smthn");
//close button
if(ImGui.button("Close")){
detailsWindow.setOpen(false);
}
}
});
detailsWindow.setOpen(false);
Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(detailsWindow);
}
/**
* Toggles the open state of the menu
*/
protected static void toggleDetailsMenus(){
detailsWindow.setOpen(!detailsWindow.isOpen());
if(detailsWindow.isOpen()){
Globals.controlHandler.hintUpdateControlState(ControlsState.IN_GAME_MAIN_MENU);
} else {
Globals.controlHandler.hintUpdateControlState(ControlsState.MAIN_GAME);
}
}
}

View File

@ -0,0 +1,83 @@
package electrosphere.client.ui.menu.editor;
import electrosphere.controls.ControlHandler.ControlsState;
import electrosphere.engine.Globals;
import electrosphere.renderer.ui.imgui.ImGuiWindow;
import electrosphere.renderer.ui.imgui.ImGuiWindow.ImGuiWindowCallback;
import imgui.ImGui;
/**
* Various methods for creating specific imgui windows in engine
*/
public class ImGuiEditorWindows {
//scene hierarchy menu
private static ImGuiWindow mainWindow;
//tracks if the editor menu is open
private static boolean editorIsOpen = false;
/**
* Initializes imgui windows
*/
public static void initEditorWindows(){
ImGuiEditorWindows.createMainEditorMenu();
ImGuiEditorDetailsWindow.createDetailsMenu();
}
/**
* Gets the hierarchy window
* @return the hierarchy window
*/
public static ImGuiWindow getHierarchyWindow(){
return mainWindow;
}
/**
* Inits the hierarchy menus
*/
private static void createMainEditorMenu(){
mainWindow = new ImGuiWindow("Editor");
mainWindow.setCallback(new ImGuiWindowCallback() {
@Override
public void exec() {
ImGui.text("hello :)");
//close button
if(ImGui.button("Close")){
mainWindow.setOpen(false);
}
}
});
mainWindow.setOpen(false);
Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(mainWindow);
}
/**
* Toggles the open state of the menu
*/
public static void toggleEditorMenus(){
mainWindow.setOpen(!mainWindow.isOpen());
ImGuiEditorWindows.editorIsOpen = mainWindow.isOpen();
if(mainWindow.isOpen()){
Globals.controlHandler.hintUpdateControlState(ControlsState.IN_GAME_MAIN_MENU);
} else {
Globals.controlHandler.hintUpdateControlState(ControlsState.MAIN_GAME);
}
//toggle all windows
ImGuiEditorDetailsWindow.toggleDetailsMenus();
}
/**
* Makes sure the main editor menu properly toggles controls if it is closed with the X button
*/
public static void synchronizeMainEditorMenuVisibility(){
if(ImGuiEditorWindows.editorIsOpen && !mainWindow.isOpen()){
ImGuiEditorWindows.editorIsOpen = false;
Globals.controlHandler.hintUpdateControlState(ControlsState.MAIN_GAME);
}
}
}

View File

@ -5,6 +5,7 @@ import java.util.List;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import electrosphere.client.ui.menu.editor.ImGuiEditorWindows;
import electrosphere.controls.Control; import electrosphere.controls.Control;
import electrosphere.controls.Control.ControlMethod; import electrosphere.controls.Control.ControlMethod;
import electrosphere.controls.Control.ControlType; import electrosphere.controls.Control.ControlType;
@ -23,6 +24,7 @@ public class ControlCategoryInGameDebug {
public static final String DEBUG_FRAMESTEP = "framestep"; public static final String DEBUG_FRAMESTEP = "framestep";
public static final String DEBUG_SWAP_EDITOR_MODE = "swapEditorMode"; public static final String DEBUG_SWAP_EDITOR_MODE = "swapEditorMode";
public static final String DEBUG_SWITCH_FIRST_THIRD = "switchFirstThird"; public static final String DEBUG_SWITCH_FIRST_THIRD = "switchFirstThird";
public static final String DEBUG_SWAP_GAME_EDITOR = "swapGameEditor";
/** /**
* Maps the controls * Maps the controls
@ -30,8 +32,9 @@ public class ControlCategoryInGameDebug {
*/ */
public static void mapControls(ControlHandler handler){ public static void mapControls(ControlHandler handler){
handler.addControl(DEBUG_FRAMESTEP, new Control(ControlType.KEY, GLFW.GLFW_KEY_P,false,"Framesetp","Steps the engine forward one frame")); handler.addControl(DEBUG_FRAMESTEP, new Control(ControlType.KEY, GLFW.GLFW_KEY_P,false,"Framesetp","Steps the engine forward one frame"));
handler.addControl(DEBUG_SWAP_EDITOR_MODE, new Control(ControlType.KEY, GLFW.GLFW_KEY_F4,false,"Swap Editor Mode","Swaps to/from the editor entity")); handler.addControl(DEBUG_SWAP_EDITOR_MODE, new Control(ControlType.KEY, GLFW.GLFW_KEY_F4,false,"Swap Editor Entity","Swaps to/from the editor entity"));
handler.addControl(DEBUG_SWITCH_FIRST_THIRD, new Control(ControlType.KEY, GLFW.GLFW_KEY_F5,false,"Switch First/Third Person","Swaps between first and third person")); handler.addControl(DEBUG_SWITCH_FIRST_THIRD, new Control(ControlType.KEY, GLFW.GLFW_KEY_F5,false,"Switch First/Third Person","Swaps between first and third person"));
handler.addControl(DEBUG_SWAP_GAME_EDITOR, new Control(ControlType.KEY, GLFW.GLFW_KEY_F6,false,"Toggle Editor Mode","Toggles between the editor mode and the actual game mode"));
} }
/** /**
@ -73,6 +76,16 @@ public class ControlCategoryInGameDebug {
Globals.controlHandler.setIsThirdPerson(!Globals.controlHandler.cameraIsThirdPerson()); Globals.controlHandler.setIsThirdPerson(!Globals.controlHandler.cameraIsThirdPerson());
}}); }});
controlMap.get(DEBUG_SWITCH_FIRST_THIRD).setRepeatTimeout(0.5f * Main.targetFrameRate); controlMap.get(DEBUG_SWITCH_FIRST_THIRD).setRepeatTimeout(0.5f * Main.targetFrameRate);
//
//Swap between editor and game mode
//
alwaysOnDebugControlList.add(controlMap.get(DEBUG_SWAP_GAME_EDITOR));
controlMap.get(DEBUG_SWAP_GAME_EDITOR).setOnPress(new ControlMethod(){public void execute(MouseState mouseState){
LoggerInterface.loggerEngine.INFO("Toggle Editor Mode");
ImGuiEditorWindows.toggleEditorMenus();
}});
controlMap.get(DEBUG_SWAP_GAME_EDITOR).setRepeatTimeout(0.5f * Main.targetFrameRate);
} }
} }

View File

@ -39,6 +39,7 @@ import electrosphere.controls.ScrollCallback;
import electrosphere.engine.assetmanager.AssetDataStrings; import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.engine.assetmanager.AssetManager; import electrosphere.engine.assetmanager.AssetManager;
import electrosphere.engine.loadingthreads.InitialAssetLoading; import electrosphere.engine.loadingthreads.InitialAssetLoading;
import electrosphere.engine.os.fs.FileWatcherService;
import electrosphere.engine.profiler.Profiler; import electrosphere.engine.profiler.Profiler;
import electrosphere.engine.service.ServiceManager; import electrosphere.engine.service.ServiceManager;
import electrosphere.engine.signal.SignalSystem; import electrosphere.engine.signal.SignalSystem;
@ -387,6 +388,9 @@ public class Globals {
//manager for all widgets currently being drawn to screen //manager for all widgets currently being drawn to screen
public static ElementService elementService; public static ElementService elementService;
public static int openInventoriesCount = 0; public static int openInventoriesCount = 0;
//file service
public static FileWatcherService fileWatcherService;
//collision world data //collision world data
public static CollisionWorldData commonWorldData; public static CollisionWorldData commonWorldData;
@ -546,6 +550,7 @@ public class Globals {
Globals.particleService = (ParticleService)serviceManager.registerService(new ParticleService()); Globals.particleService = (ParticleService)serviceManager.registerService(new ParticleService());
Globals.scriptEngine = (ScriptEngine)serviceManager.registerService(new ScriptEngine()); Globals.scriptEngine = (ScriptEngine)serviceManager.registerService(new ScriptEngine());
Globals.mainThreadSignalService = (MainThreadSignalService)serviceManager.registerService(new MainThreadSignalService()); Globals.mainThreadSignalService = (MainThreadSignalService)serviceManager.registerService(new MainThreadSignalService());
Globals.fileWatcherService = (FileWatcherService)serviceManager.registerService(new FileWatcherService());
serviceManager.instantiate(); serviceManager.instantiate();
// //
//End service manager //End service manager
@ -557,6 +562,7 @@ public class Globals {
Globals.signalSystem.registerService(Globals.particleService); Globals.signalSystem.registerService(Globals.particleService);
Globals.signalSystem.registerService(Globals.scriptEngine); Globals.signalSystem.registerService(Globals.scriptEngine);
Globals.signalSystem.registerService(Globals.mainThreadSignalService); Globals.signalSystem.registerService(Globals.mainThreadSignalService);
Globals.signalSystem.registerService(Globals.fileWatcherService);
} }
@ -744,6 +750,7 @@ public class Globals {
Globals.threadManager = null; Globals.threadManager = null;
Globals.signalSystem = null; Globals.signalSystem = null;
Globals.serviceManager = null; Globals.serviceManager = null;
Globals.fileWatcherService = null;
Globals.clientConnection = null; Globals.clientConnection = null;
Globals.clientSynchronizationManager = null; Globals.clientSynchronizationManager = null;
Globals.server = null; Globals.server = null;

View File

@ -263,7 +263,7 @@ public class Main {
LoggerInterface.loggerEngine.DEBUG_LOOP("Begin load assets"); LoggerInterface.loggerEngine.DEBUG_LOOP("Begin load assets");
Globals.assetManager.loadAssetsInQueue(); Globals.assetManager.loadAssetsInQueue();
LoggerInterface.loggerEngine.DEBUG_LOOP("Begin delete assets"); LoggerInterface.loggerEngine.DEBUG_LOOP("Begin delete assets");
Globals.assetManager.deleteModelsInDeleteQueue(); Globals.assetManager.handleDeleteQueue();
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
} }
@ -302,8 +302,11 @@ public class Main {
SynchronousSignalHandling.runMainThreadSignalHandlers(); SynchronousSignalHandling.runMainThreadSignalHandlers();
/// ///
/// S C R I P T E N G I N E /// E N G I N E S E R V I C E S
/// ///
if(Globals.fileWatcherService != null){
Globals.fileWatcherService.poll();
}
if(Globals.RUN_SCRIPTS && Globals.scriptEngine != null){ if(Globals.RUN_SCRIPTS && Globals.scriptEngine != null){
Globals.scriptEngine.scanScriptDir(); Globals.scriptEngine.scanScriptDir();
} }

View File

@ -66,6 +66,7 @@ public class AssetManager {
Map<String,PoseModel> poseModelsLoadedIntoMemory = new ConcurrentHashMap<String,PoseModel>(); Map<String,PoseModel> poseModelsLoadedIntoMemory = new ConcurrentHashMap<String,PoseModel>();
List<String> poseModelsInQueue = new CopyOnWriteArrayList<String>(); List<String> poseModelsInQueue = new CopyOnWriteArrayList<String>();
List<String> poseModelsInDeleteQueue = new CopyOnWriteArrayList<String>();
//A queue of homogenous buffers to allocate this render frame //A queue of homogenous buffers to allocate this render frame
List<HomogenousUniformBuffer> homogenousBufferAllocationQueue = new CopyOnWriteArrayList<HomogenousUniformBuffer>(); List<HomogenousUniformBuffer> homogenousBufferAllocationQueue = new CopyOnWriteArrayList<HomogenousUniformBuffer>();
@ -173,43 +174,59 @@ public class AssetManager {
//allocate homogenous buffers //allocate homogenous buffers
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Allocate homogenous buffers"); LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Allocate homogenous buffers");
allocateHomogenousBuffers(); this.allocateHomogenousBuffers();
//allocate instance array buffers //allocate instance array buffers
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Allocate instance array buffers"); LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Allocate instance array buffers");
allocateInstanceArrayBuffers(); this.allocateInstanceArrayBuffers();
//override meshes //override meshes
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Override meshes"); LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Override meshes");
performMeshOverrides(); this.performMeshOverrides();
} }
//
/** //Updating assets
* Deletes all models in the delete queue //
*/ public void updateAsset(String path){
public void deleteModelsInDeleteQueue(){ LoggerInterface.loggerEngine.DEBUG("AssetManager - updateAsset");
for(String modelPath : modelsInDeleteQueue){ //models
Model model = this.fetchModel(modelPath); if(modelsLoadedIntoMemory.containsKey(path)){
if(model != null){ this.queueModelForDeletion(path);
model.delete(); this.deleteModelsInDeleteQueue();
} this.addModelPathToQueue(path);
this.modelsLoadedIntoMemory.remove(modelPath); }
//textures
if(texturesLoadedIntoMemory.containsKey(path)){
this.queueTextureForDeletion(path);
this.deleteTexturesInDeleteQueue();
this.addTexturePathtoQueue(path);
}
//pose models
if(poseModelsLoadedIntoMemory.containsKey(path)){
this.queuePoseModelForDeletion(path);
this.deletePoseModelsInDeleteQueue();
this.addPoseModelPathToQueue(path);
}
if(audioLoadedIntoMemory.containsKey(path)){
throw new Error("Unhandled asset type! (Audio)");
}
if(shadersLoadedIntoMemory.containsKey(path)){
throw new Error("Unhandled asset type! (Shader - Visual)");
}
if(computeShadersLoadedIntoMemory.containsKey(path)){
throw new Error("Unhandled asset type! (Shader - Compute)");
} }
} }
/** /**
* Deletes all textures in the delete queue * Handles the delete queues
*/ */
public void deleteTexturesInDeleteQueue(){ public void handleDeleteQueue(){
for(String texturePath : texturesInDeleteQueue){ this.deleteModelsInDeleteQueue();
Texture texture = this.fetchTexture(texturePath); this.deletePoseModelsInDeleteQueue();
if(texture != null){ this.deleteTexturesInDeleteQueue();
texture.free();
}
this.texturesLoadedIntoMemory.remove(texturePath);
}
} }
@ -217,6 +234,8 @@ public class AssetManager {
// //
//Models //Models
// //
@ -305,6 +324,19 @@ public class AssetManager {
// modelsLoadedIntoMemory.clear(); // modelsLoadedIntoMemory.clear();
} }
/**
* Deletes all models in the delete queue
*/
public void deleteModelsInDeleteQueue(){
for(String modelPath : modelsInDeleteQueue){
Model model = this.fetchModel(modelPath);
if(model != null){
model.delete();
}
this.modelsLoadedIntoMemory.remove(modelPath);
}
}
@ -347,6 +379,27 @@ public class AssetManager {
public void registerPoseModelWithPath(PoseModel m, String path){ public void registerPoseModelWithPath(PoseModel m, String path){
poseModelsLoadedIntoMemory.put(path, m); poseModelsLoadedIntoMemory.put(path, m);
} }
/**
* Queues a pose model for deletion
* @param modelPath The path to the pose model
*/
public void queuePoseModelForDeletion(String modelPath){
poseModelsInDeleteQueue.add(modelPath);
}
/**
* Deletes all pose models in the delete queue
*/
public void deletePoseModelsInDeleteQueue(){
for(String modelPath : poseModelsInDeleteQueue){
PoseModel poseModel = this.fetchPoseModel(modelPath);
if(poseModel != null){
poseModel.delete();
}
this.poseModelsLoadedIntoMemory.remove(modelPath);
}
}
@ -423,6 +476,19 @@ public class AssetManager {
} }
return null; return null;
} }
/**
* Deletes all textures in the delete queue
*/
public void deleteTexturesInDeleteQueue(){
for(String texturePath : texturesInDeleteQueue){
Texture texture = this.fetchTexture(texturePath);
if(texture != null){
texture.free();
}
this.texturesLoadedIntoMemory.remove(texturePath);
}
}

View File

@ -0,0 +1,63 @@
package electrosphere.engine.os;
import java.io.File;
import java.nio.file.Path;
import java.util.List;
import electrosphere.client.ui.menu.editor.ImGuiEditorWindows;
import electrosphere.engine.Globals;
import electrosphere.engine.os.fs.FileWatcher;
import electrosphere.logger.LoggerInterface;
/**
* Handles drag-and-drop signals from the OS
*/
public class OSDragAndDrop {
/**
* Fires when a file path is dropped on the application
* @param paths The paths of the files
*/
public static void handleDragAndDrop(List<String> paths){
if(ImGuiEditorWindows.getHierarchyWindow().isOpen()){
OSDragAndDrop.handleDropAsset(paths);
}
}
/**
* Handles the case where asset path(s) have been dropped on the application
* @param paths The paths of the assets
*/
private static void handleDropAsset(List<String> paths){
//try watching the file and register it to be an asset
LoggerInterface.loggerFileIO.WARNING("File(s) added to application");
for(String rawPath : paths){
String normalized = rawPath.toLowerCase();
Path absolutePath = new File(rawPath).toPath();
Path relativePath = new File("./assets").getAbsoluteFile().toPath().relativize(absolutePath);
//register based on file type
if(normalized.contains(".glsl") || normalized.contains(".dae")){
Globals.assetManager.addModelPathToQueue(relativePath.toString());
} else if(normalized.contains(".wav") || normalized.contains(".ogg")){
Globals.assetManager.addAudioPathToQueue(relativePath.toString());
} else if(normalized.contains(".jpg") || normalized.contains(".jpeg") || normalized.contains(".png")){
Globals.assetManager.addTexturePathtoQueue(relativePath.toString());
} else {
throw new Error("Unhandled file type! " + rawPath);
}
//watch the asset for file updates
LoggerInterface.loggerEngine.WARNING("Tracking " + rawPath);
Globals.fileWatcherService.trackFile(new FileWatcher(rawPath).setOnWrite(updatedPath -> {
LoggerInterface.loggerFileIO.WARNING("File updated: " + updatedPath.toString());
Globals.assetManager.updateAsset(updatedPath.toString());
}).setOnDelete(updatedPath -> {
LoggerInterface.loggerFileIO.WARNING("File deleted: " + updatedPath.toString());
}).setOnCreate(updatedPath -> {
LoggerInterface.loggerFileIO.WARNING("File created: " + updatedPath.toString());
}));
}
}
}

View File

@ -0,0 +1,123 @@
package electrosphere.engine.os.fs;
import java.io.File;
import java.nio.file.Path;
import java.util.function.Consumer;
/**
* Sets a callback to fire every time a type of event happens to a fire
*/
public class FileWatcher {
/**
* The path of the file that is being watched
*/
Path path;
/**
* The callback that fires when the file is created
*/
Consumer<Path> onCreate;
/**
* The callback that fires when the file is edited
*/
Consumer<Path> onWrite;
/**
* The callback that fires when the file is deleted
*/
Consumer<Path> onDelete;
/**
* Constructor
* @param path The path the watcher should follow
*/
public FileWatcher(String path){
this.path = new File(path).toPath();
}
/**
* Gets the path of the file that this watcher is tracking
* @return The path of the file that this watcher is tracking
*/
public Path getPath(){
return this.path;
}
/**
* Sets the on-create callback for the watcher
* @param onCreate The callback that fires when the file is created
* @return The file watcher instance that the callback is being attached to
*/
public FileWatcher setOnCreate(Consumer<Path> onCreate){
this.onCreate = onCreate;
return this;
}
/**
* Gets the on-create callback
* @return The on-create callback
*/
public Consumer<Path> getOnCreate(){
return this.onCreate;
}
/**
* Fires when the file is created
*/
protected void onCreate(){
this.onCreate.accept(path);
}
/**
* Sets the on-write callback for the watcher
* @param onWrite The callback that fires when the file is edited
* @return The file watcher instance that the callback is being attached to
*/
public FileWatcher setOnWrite(Consumer<Path> onWrite){
this.onWrite = onWrite;
return this;
}
/**
* Gets the on-write callback
* @return The on-write callback
*/
public Consumer<Path> getOnWrite(){
return this.onWrite;
}
/**
* Fires when the file is written to
*/
protected void onWrite(){
this.onWrite.accept(path);
}
/**
* Sets the on-delete callback for the watcher
* @param onDelete The callback that fires when the file is deleted
* @return The file watcher instance that the callback is being attached to
*/
public FileWatcher setOnDelete(Consumer<Path> onDelete){
this.onDelete = onDelete;
return this;
}
/**
* Gets the on-delete callback
* @return The on-delete callback
*/
public Consumer<Path> getOnDelete(){
return this.onDelete;
}
/**
* Fires when the file is deleted
*/
protected void onDelete(){
this.onDelete.accept(path);
}
}

View File

@ -0,0 +1,118 @@
package electrosphere.engine.os.fs;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import electrosphere.engine.signal.Signal.SignalType;
import electrosphere.engine.signal.SignalServiceImpl;
import electrosphere.logger.LoggerInterface;
/**
* Service that manages file watchers
*/
public class FileWatcherService extends SignalServiceImpl {
/**
* The file system object
*/
FileSystem fs;
/**
* The watch service
*/
WatchService watchService;
/**
* Map of path to watcher
*/
Map<String,FileWatcher> pathWatcherMap;
/**
* Constructor
*/
public FileWatcherService() {
super(
"FileWatcher",
new SignalType[]{
}
);
this.fs = FileSystems.getDefault();
try {
this.watchService = fs.newWatchService();
} catch (IOException e) {
LoggerInterface.loggerFileIO.ERROR(e);
}
this.pathWatcherMap = new HashMap<String,FileWatcher>();
}
/**
* Tracks a file
* @param watcher Tracks a file
*/
public void trackFile(FileWatcher watcher){
try {
watcher.getPath().getParent().register(
watchService,
new WatchEvent.Kind[]{StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE}
);
pathWatcherMap.put(watcher.path.toAbsolutePath().normalize().toString(),watcher);
} catch (IOException e) {
LoggerInterface.loggerEngine.ERROR(e);
}
}
/**
* Scans all tracked files
*/
public void poll(){
WatchKey key = null;
while((key = watchService.poll()) != null){
List<WatchEvent<?>> events = key.pollEvents();
Path keyParentDir = (Path)key.watchable();
for(WatchEvent<?> event : events){
if(event.kind() == StandardWatchEventKinds.ENTRY_MODIFY){
if(event.context() instanceof Path){
Path filePath = (Path)event.context();
Path resolved = keyParentDir.resolve(filePath);
String normalized = resolved.toAbsolutePath().normalize().toString();
FileWatcher watcher = this.pathWatcherMap.get(normalized);
if(watcher != null){
watcher.onWrite();
}
}
} else if(event.kind() == StandardWatchEventKinds.ENTRY_CREATE){
if(event.context() instanceof Path){
Path filePath = (Path)event.context();
Path resolved = keyParentDir.resolve(filePath);
String normalized = resolved.toAbsolutePath().normalize().toString();
FileWatcher watcher = this.pathWatcherMap.get(normalized);
if(watcher != null){
watcher.onCreate();
}
}
} else if(event.kind() == StandardWatchEventKinds.ENTRY_DELETE){
if(event.context() instanceof Path){
Path filePath = (Path)event.context();
Path resolved = keyParentDir.resolve(filePath);
String normalized = resolved.toAbsolutePath().normalize().toString();
FileWatcher watcher = this.pathWatcherMap.get(normalized);
if(watcher != null){
watcher.onDelete();
}
}
}
}
key.reset();
}
}
}

View File

@ -9,10 +9,13 @@ import static org.lwjgl.opengl.GL30.glBindRenderbuffer;
import static org.lwjgl.system.MemoryUtil.NULL; import static org.lwjgl.system.MemoryUtil.NULL;
import java.nio.IntBuffer; import java.nio.IntBuffer;
import java.util.LinkedList;
import java.util.List;
import org.joml.Matrix4d; import org.joml.Matrix4d;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.lwjgl.BufferUtils; import org.lwjgl.BufferUtils;
import org.lwjgl.PointerBuffer;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback; import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GL;
@ -21,8 +24,10 @@ import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GL45; import org.lwjgl.opengl.GL45;
import org.lwjgl.opengl.GLDebugMessageCallback; import org.lwjgl.opengl.GLDebugMessageCallback;
import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.engine.os.OSDragAndDrop;
import electrosphere.engine.signal.Signal.SignalType; import electrosphere.engine.signal.Signal.SignalType;
import electrosphere.logger.LoggerInterface; import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.debug.DebugRendering; import electrosphere.renderer.debug.DebugRendering;
@ -444,6 +449,19 @@ public class RenderingEngine {
// fogColor.flip(); // fogColor.flip();
// GL11.glFogfv(GL_FOG_COLOR, fogColor); // GL11.glFogfv(GL_FOG_COLOR, fogColor);
//
//Set file drag-and-drop for app
//
GLFW.glfwSetDropCallback(Globals.window, (long window, int count, long names) -> {
PointerBuffer charPointers = MemoryUtil.memPointerBuffer(names, count);
List<String> paths = new LinkedList<String>();
for(int i = 0; i < count; i++){
String name = MemoryUtil.memUTF8(charPointers.get(i));
paths.add(name);
}
OSDragAndDrop.handleDragAndDrop(paths);
});
// //
//Init pipelines //Init pipelines
// //

View File

@ -4,6 +4,7 @@ import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import electrosphere.client.ui.menu.debug.ImGuiWindowMacros; import electrosphere.client.ui.menu.debug.ImGuiWindowMacros;
import electrosphere.client.ui.menu.editor.ImGuiEditorWindows;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.renderer.OpenGLState; import electrosphere.renderer.OpenGLState;
import electrosphere.renderer.RenderPipelineState; import electrosphere.renderer.RenderPipelineState;
@ -63,6 +64,7 @@ public class ImGuiPipeline implements RenderPipeline {
ImGui.render(); ImGui.render();
imGuiGl13.renderDrawData(ImGui.getDrawData()); imGuiGl13.renderDrawData(ImGui.getDrawData());
ImGuiWindowMacros.synchronizeMainDebugMenuVisibility(); ImGuiWindowMacros.synchronizeMainDebugMenuVisibility();
ImGuiEditorWindows.synchronizeMainEditorMenuVisibility();
} }
} }

View File

@ -161,8 +161,7 @@ public class ScriptEngine extends SignalServiceImpl {
} }
}); });
} catch (IOException e) { } catch (IOException e) {
// TODO Auto-generated catch block LoggerInterface.loggerEngine.ERROR(e);
e.printStackTrace();
} }
} }

View File

@ -267,4 +267,11 @@ public class PoseModel {
return this.bones; return this.bones;
} }
/**
* Delete - currently does nothing
*/
public void delete(){
}
} }