first working file watching with efsw, oome namespace overhaul
This commit is contained in:
parent
ac206809e8
commit
e5c7906d35
@ -7,11 +7,11 @@
|
|||||||
namespace oom {
|
namespace oom {
|
||||||
namespace bella {
|
namespace bella {
|
||||||
// Function declaration
|
// Function declaration
|
||||||
dl::bella_sdk::Node essentialsToScene(dl::bella_sdk::Scene& belScene);
|
dl::bella_sdk::Node defaultScene2025(dl::bella_sdk::Scene& belScene);
|
||||||
|
|
||||||
// @param belScene - the scene to create the essentials in
|
// @param belScene - the scene to create the essentials in
|
||||||
// @return - the world node
|
// @return - the world node
|
||||||
dl::bella_sdk::Node essentialsToScene(dl::bella_sdk::Scene& belScene) {
|
dl::bella_sdk::Node defaultScene2025(dl::bella_sdk::Scene& belScene) {
|
||||||
// Create the basic scene elements in Bella
|
// Create the basic scene elements in Bella
|
||||||
// Each line creates a different type of node in the scene auto belBeautyPass = belScene.createNode("beautyPass","oomerBeautyPass","oomerBeautyPass");
|
// Each line creates a different type of node in the scene auto belBeautyPass = belScene.createNode("beautyPass","oomerBeautyPass","oomerBeautyPass");
|
||||||
auto belWorld = belScene.world(); // Get scene world root
|
auto belWorld = belScene.world(); // Get scene world root
|
||||||
|
|||||||
@ -1,12 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Bella SDK includes - external libraries for 3D rendering
|
|
||||||
#include "../bella_scene_sdk/src/bella_sdk/bella_scene.h" // For creating and manipulating 3D scenes in Bella
|
#include "../bella_scene_sdk/src/bella_sdk/bella_scene.h" // For creating and manipulating 3D scenes in Bella
|
||||||
//#include "../bella_scene_sdk/src/dl_core/dl_main.inl" // Core functionality from the Diffuse Logic engine
|
|
||||||
|
|
||||||
// Now define the oomer namespace with using declarations for all functions/classes
|
|
||||||
namespace oom {
|
namespace oom {
|
||||||
namespace bella {
|
namespace bella {
|
||||||
|
// Unit mesh cube created in Blender, with rounded edges
|
||||||
|
// Used for emitter voxels because procedural Bella box does not currently support emission
|
||||||
void addMeshCube(dl::bella_sdk::Node& belMeshVoxel) {
|
void addMeshCube(dl::bella_sdk::Node& belMeshVoxel) {
|
||||||
belMeshVoxel["name"] = "oomerMeshVoxel";
|
belMeshVoxel["name"] = "oomerMeshVoxel";
|
||||||
belMeshVoxel["channels"][0] = "st";
|
belMeshVoxel["channels"][0] = "st";
|
||||||
|
|||||||
@ -1,18 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Bella SDK includes - external libraries for 3D rendering
|
|
||||||
#include "../bella_scene_sdk/src/bella_sdk/bella_scene.h" // For creating and manipulating 3D scenes in Bella
|
#include "../bella_scene_sdk/src/bella_sdk/bella_scene.h" // For creating and manipulating 3D scenes in Bella
|
||||||
//#include "../bella_scene_sdk/src/dl_core/dl_main.inl" // Core functionality from the Diffuse Logic engine
|
|
||||||
|
|
||||||
// Define the oom namespace
|
|
||||||
namespace oom {
|
namespace oom {
|
||||||
namespace bella {
|
namespace bella {
|
||||||
// Function declaration
|
// Function declaration
|
||||||
dl::bella_sdk::Node essentialsToScene(dl::bella_sdk::Scene& belScene);
|
dl::bella_sdk::Node defaultScene2025(dl::bella_sdk::Scene& belScene);
|
||||||
|
|
||||||
// @param belScene - the scene to create the essentials in
|
// @param belScene - the scene to create the essentials in
|
||||||
// @return - the world node
|
// @return - the world node
|
||||||
dl::bella_sdk::Node essentialsToScene(dl::bella_sdk::Scene& belScene) {
|
dl::bella_sdk::Node defaultScene2025(dl::bella_sdk::Scene& belScene) {
|
||||||
// Create the basic scene elements in Bella
|
// Create the basic scene elements in Bella
|
||||||
// Each line creates a different type of node in the scene auto belBeautyPass = belScene.createNode("beautyPass","oomerBeautyPass","oomerBeautyPass");
|
// Each line creates a different type of node in the scene auto belBeautyPass = belScene.createNode("beautyPass","oomerBeautyPass","oomerBeautyPass");
|
||||||
auto belWorld = belScene.world(); // Get scene world root
|
auto belWorld = belScene.world(); // Get scene world root
|
||||||
@ -30,15 +26,15 @@ namespace oom {
|
|||||||
auto belGroundMat = belScene.createNode("quickMaterial","oomerGroundMat","oomerGroundMat");
|
auto belGroundMat = belScene.createNode("quickMaterial","oomerGroundMat","oomerGroundMat");
|
||||||
auto belSun = belScene.createNode("sun","oomerSun","oomerSun");
|
auto belSun = belScene.createNode("sun","oomerSun","oomerSun");
|
||||||
auto belColorDome = belScene.createNode("colorDome","oomerColorDome","oomerColorDome");
|
auto belColorDome = belScene.createNode("colorDome","oomerColorDome","oomerColorDome");
|
||||||
|
|
||||||
auto belSettings = belScene.settings(); // Get scene settings
|
auto belSettings = belScene.settings(); // Get scene settings
|
||||||
|
|
||||||
// Configure camera
|
// Configure camera
|
||||||
belCam["resolution"] = dl::Vec2 {1920, 1080}; // Set resolution to 1080p
|
belCam["resolution"] = dl::Vec2 {1920, 1080}; // Set resolution to 1080p
|
||||||
belCam["lens"] = belLens; // Connect camera to lens
|
belCam["lens"] = belLens; // Connect camera to lens
|
||||||
belCam["sensor"] = belSensor; // Connect camera to sensor
|
belCam["sensor"] = belSensor; // Connect camera to sensor
|
||||||
belCamForm.parentTo(belWorld); // Parent camera transform to world
|
belCamForm.parentTo(belWorld); // Parent camera transform to world
|
||||||
belCam.parentTo(belCamForm); // Parent camera to camera transform
|
belCam.parentTo(belCamForm); // Parent camera to camera transform
|
||||||
|
|
||||||
// Position the camera with a transformation matrix
|
|
||||||
belCamForm["steps"][0]["xform"] = dl::Mat4 {0.525768608156, -0.850627633385, 0, 0, -0.234464751651, -0.144921468924, -0.961261695938, 0, 0.817675761479, 0.505401223947, -0.275637355817, 0, -88.12259018466, -54.468125200218, 50.706001690932, 1};
|
belCamForm["steps"][0]["xform"] = dl::Mat4 {0.525768608156, -0.850627633385, 0, 0, -0.234464751651, -0.144921468924, -0.961261695938, 0, 0.817675761479, 0.505401223947, -0.275637355817, 0, -88.12259018466, -54.468125200218, 50.706001690932, 1};
|
||||||
|
|
||||||
// Configure environment (image-based lighting)
|
// Configure environment (image-based lighting)
|
||||||
@ -50,14 +46,9 @@ namespace oom {
|
|||||||
belColorDome["zenith"] = dl::Rgba{1.0f, 1.0f, 1.0f, 1.0f};
|
belColorDome["zenith"] = dl::Rgba{1.0f, 1.0f, 1.0f, 1.0f};
|
||||||
belColorDome["horizon"] = dl::Rgba{.85f, 0.76f, 0.294f, 1.0f};
|
belColorDome["horizon"] = dl::Rgba{.85f, 0.76f, 0.294f, 1.0f};
|
||||||
belColorDome["altitude"] = 14.0f;
|
belColorDome["altitude"] = 14.0f;
|
||||||
// Configure ground plane
|
|
||||||
//belGroundPlane["elevation"] = -.5f;
|
|
||||||
belGroundPlane["material"] = belGroundMat;
|
|
||||||
|
|
||||||
/* Commented out: Sun configuration
|
// Configure ground plane
|
||||||
belSun["size"] = 20.0f;
|
belGroundPlane["material"] = belGroundMat;
|
||||||
belSun["month"] = "july";
|
|
||||||
belSun["rotation"] = 50.0f;*/
|
|
||||||
|
|
||||||
// Configure materials
|
// Configure materials
|
||||||
belGroundMat["type"] = "metal";
|
belGroundMat["type"] = "metal";
|
||||||
@ -72,7 +63,6 @@ namespace oom {
|
|||||||
belSettings["threads"] = dl::bella_sdk::Input(0); // Auto-detect thread count
|
belSettings["threads"] = dl::bella_sdk::Input(0); // Auto-detect thread count
|
||||||
belSettings["groundPlane"] = belGroundPlane;
|
belSettings["groundPlane"] = belGroundPlane;
|
||||||
belSettings["iprNavigation"]= "maya"; // Use Maya-like navigation in viewer
|
belSettings["iprNavigation"]= "maya"; // Use Maya-like navigation in viewer
|
||||||
//settings["sun"] = sun;
|
|
||||||
|
|
||||||
auto belVoxel = belScene.createNode("box","oomerVoxel","oomerVoxel");
|
auto belVoxel = belScene.createNode("box","oomerVoxel","oomerVoxel");
|
||||||
auto belLiqVoxel = belScene.createNode("box","oomerLiqVoxel","oomerLiqVoxel");
|
auto belLiqVoxel = belScene.createNode("box","oomerLiqVoxel","oomerLiqVoxel");
|
||||||
@ -84,7 +74,7 @@ namespace oom {
|
|||||||
belBevel["radius"] = 90.0f;
|
belBevel["radius"] = 90.0f;
|
||||||
belBevel["samples"] =dl::UInt(6);
|
belBevel["samples"] =dl::UInt(6);
|
||||||
|
|
||||||
oom::bella::addMeshCube(belMeshVoxel);
|
oom::bella::addMeshCube(belMeshVoxel); // bring in a blender mesh cube for emitters
|
||||||
// Configure voxel box dimensions
|
// Configure voxel box dimensions
|
||||||
belVoxel["radius"] = 0.33f;
|
belVoxel["radius"] = 0.33f;
|
||||||
belVoxel["sizeX"] = 0.99f;
|
belVoxel["sizeX"] = 0.99f;
|
||||||
|
|||||||
551
oom_file.h
Normal file
551
oom_file.h
Normal file
@ -0,0 +1,551 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
#include <chrono>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex> // Add this line for std::mutex and std::lock_guard
|
||||||
|
#include <map> // Add this line for std::map
|
||||||
|
|
||||||
|
#include "../efsw/src/efsw/FileSystem.hpp" // For file watching
|
||||||
|
#include "../efsw/src/efsw/System.hpp" // For file watching
|
||||||
|
#include "../efsw/include/efsw/efsw.hpp" // For file watching
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// OOM NAMESPACE - Contains core file watching functionality
|
||||||
|
//==============================================================================
|
||||||
|
namespace oom {
|
||||||
|
namespace file {
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// RenderQueue Class
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* A thread-safe FIFO queue that tracks render files
|
||||||
|
*
|
||||||
|
* This class implements a specialized queue that maintains both:
|
||||||
|
* 1. FIFO (First-In-First-Out) ordering via a vector
|
||||||
|
* 2. Fast lookup capability via a map
|
||||||
|
*
|
||||||
|
* It's designed to be safely used across multiple threads
|
||||||
|
*/
|
||||||
|
class Queue {
|
||||||
|
public:
|
||||||
|
// Default constructor - Creates an empty queue
|
||||||
|
Queue() = default;
|
||||||
|
|
||||||
|
// Move constructor - Transfers ownership of resources from another queue
|
||||||
|
Queue(Queue&& other) noexcept {
|
||||||
|
// Lock the other queue to prevent concurrent modification during the move
|
||||||
|
std::lock_guard<std::mutex> lock(other.mutex);
|
||||||
|
|
||||||
|
// Transfer ownership of the data structures using std::move
|
||||||
|
pathVector = std::move(other.pathVector);
|
||||||
|
pathMap = std::move(other.pathMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move assignment operator - Similar to move constructor but for assignment operations
|
||||||
|
Queue& operator=(Queue&& other) noexcept {
|
||||||
|
// Avoid self-assignment (moving to itself)
|
||||||
|
if (this != &other) {
|
||||||
|
// Lock both queues to prevent concurrent modification
|
||||||
|
std::lock_guard<std::mutex> lock1(mutex);
|
||||||
|
std::lock_guard<std::mutex> lock2(other.mutex);
|
||||||
|
|
||||||
|
// Transfer ownership of the data structures
|
||||||
|
pathVector = std::move(other.pathVector);
|
||||||
|
pathMap = std::move(other.pathMap);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete copy operations since mutexes can't be copied
|
||||||
|
Queue(const Queue&) = delete;
|
||||||
|
Queue& operator=(const Queue&) = delete;
|
||||||
|
|
||||||
|
// Add a file to the queue if it's not already there
|
||||||
|
bool push(const std::filesystem::path& path) {
|
||||||
|
// Lock the queue during modification to ensure thread safety
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
|
||||||
|
// Check if the path already exists in our map (fast lookup)
|
||||||
|
if (pathMap.find(path) == pathMap.end()) {
|
||||||
|
// If not found, add to the vector (maintains order)
|
||||||
|
pathVector.push_back(path);
|
||||||
|
// Mark as present in the map for fast future lookups
|
||||||
|
pathMap[path] = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the next file to render (FIFO order) and remove it from the queue
|
||||||
|
bool pop(std::filesystem::path& outPath) {
|
||||||
|
// Lock the queue during access to ensure thread safety
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
|
||||||
|
if (!pathVector.empty()) {
|
||||||
|
// Get the first item (oldest) from the vector
|
||||||
|
outPath = pathVector.front();
|
||||||
|
// Remove it from the vector
|
||||||
|
pathVector.erase(pathVector.begin());
|
||||||
|
// Remove it from the map as well
|
||||||
|
pathMap.erase(outPath);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove a specific file by name
|
||||||
|
bool remove(const std::filesystem::path& path) {
|
||||||
|
// Lock the queue during modification to ensure thread safety
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
|
||||||
|
if (pathMap.find(path) != pathMap.end()) {
|
||||||
|
// Remove from vector using erase-remove idiom
|
||||||
|
pathVector.erase(
|
||||||
|
std::remove(pathVector.begin(), pathVector.end(), path),
|
||||||
|
pathVector.end()
|
||||||
|
);
|
||||||
|
// Remove from map
|
||||||
|
pathMap.erase(path);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a file exists in the queue
|
||||||
|
bool contains(const std::filesystem::path& path) const {
|
||||||
|
// Lock the queue during access to ensure thread safety
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
// Use the map for fast lookup
|
||||||
|
return pathMap.find(path) != pathMap.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the number of files in the queue
|
||||||
|
size_t size() const {
|
||||||
|
// Lock the queue during access to ensure thread safety
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
return pathVector.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the queue is empty
|
||||||
|
bool empty() const {
|
||||||
|
// Lock the queue during access to ensure thread safety
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
return pathVector.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear all files from the queue
|
||||||
|
void clear() {
|
||||||
|
// Lock the queue during modification to ensure thread safety
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
// Clear both data structures
|
||||||
|
pathVector.clear();
|
||||||
|
pathMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::filesystem::path> pathVector; // Stores paths in order (FIFO queue)
|
||||||
|
std::map<std::filesystem::path, bool> pathMap; // Maps paths to bool for fast existence checks
|
||||||
|
mutable std::mutex mutex; // Makes operations thread-safe; mutable allows locking in const methods
|
||||||
|
};
|
||||||
|
|
||||||
|
// Forward declaration needed for UpdateListener
|
||||||
|
class Watcher;
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// UpdateListener Class
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Processes file system events from efsw and filters them
|
||||||
|
*
|
||||||
|
* This class receives notifications from the file system watcher (efsw)
|
||||||
|
* when files are created, modified or deleted, and then filters these
|
||||||
|
* events based on file extensions and directories.
|
||||||
|
*/
|
||||||
|
class UpdateListener : public efsw::FileWatchListener {
|
||||||
|
public:
|
||||||
|
// Constructor takes a pointer to its parent Watcher
|
||||||
|
UpdateListener(Watcher* parent);
|
||||||
|
|
||||||
|
// Signals the listener to stop processing events
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
// Converts efsw action codes to human-readable strings
|
||||||
|
std::string getActionName(efsw::Action action);
|
||||||
|
|
||||||
|
// Check if a file extension is in our watch list
|
||||||
|
bool isWatchedExtension(const std::string& extension);
|
||||||
|
|
||||||
|
// Check if a directory should be ignored
|
||||||
|
bool isIgnoredDirectory(const std::string& directory);
|
||||||
|
|
||||||
|
// Main callback that efsw calls when file system events occur
|
||||||
|
void handleFileAction(efsw::WatchID watchid,
|
||||||
|
const std::string& dir,
|
||||||
|
const std::string& filename,
|
||||||
|
efsw::Action action,
|
||||||
|
std::string oldFilename = "") override;
|
||||||
|
private:
|
||||||
|
std::atomic<bool> should_stop_{false}; // Flag to signal stopping
|
||||||
|
Watcher* parentWatcher; // Reference to parent Watcher
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// Watcher Class
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Manages file watching and file queues
|
||||||
|
*
|
||||||
|
* This class coordinates the file system watching functionality
|
||||||
|
* and maintains queues of files to be rendered or deleted.
|
||||||
|
*/
|
||||||
|
class Watcher {
|
||||||
|
public:
|
||||||
|
// Constructor with configurable extensions and ignored directories
|
||||||
|
Watcher(const std::vector<std::string>& extensions = {".bsz", ".zip"},
|
||||||
|
const std::vector<std::string>& ignoreDirs = {"download"});
|
||||||
|
|
||||||
|
// Destructor to clean up resources
|
||||||
|
~Watcher();
|
||||||
|
|
||||||
|
// Prevent copying or moving to simplify handling
|
||||||
|
Watcher(const Watcher&) = delete;
|
||||||
|
Watcher& operator=(const Watcher&) = delete;
|
||||||
|
Watcher(Watcher&&) = delete;
|
||||||
|
Watcher& operator=(Watcher&&) = delete;
|
||||||
|
|
||||||
|
// Start watching a directory
|
||||||
|
bool startWatching(const std::string& directory);
|
||||||
|
|
||||||
|
// Stop watching
|
||||||
|
void stopWatching();
|
||||||
|
|
||||||
|
// Get the next file to render
|
||||||
|
bool getNextFileToRender(std::filesystem::path& outPath);
|
||||||
|
|
||||||
|
// Get the next file to delete
|
||||||
|
bool getNextFileToDelete(std::filesystem::path& outPath);
|
||||||
|
|
||||||
|
// Check if there are files to render
|
||||||
|
bool hasFilesToRender() const;
|
||||||
|
|
||||||
|
// Check if there are files to delete
|
||||||
|
bool hasFilesToDelete() const;
|
||||||
|
|
||||||
|
// Add or remove extensions dynamically
|
||||||
|
void addExtension(const std::string& extension);
|
||||||
|
void removeExtension(const std::string& extension);
|
||||||
|
|
||||||
|
// Add or remove ignored directories
|
||||||
|
void addIgnoreDirectory(const std::string& directory);
|
||||||
|
void removeIgnoreDirectory(const std::string& directory);
|
||||||
|
|
||||||
|
// Get extensions and ignored directories (for UpdateListener)
|
||||||
|
const std::vector<std::string>& getWatchExtensions() const { return watchExtensions; }
|
||||||
|
const std::vector<std::string>& getIgnoreDirectories() const { return ignoreDirectories; }
|
||||||
|
|
||||||
|
// Access to queues (for UpdateListener)
|
||||||
|
void addToRenderQueue(const std::filesystem::path& path);
|
||||||
|
void addToDeleteQueue(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// File extensions to monitor (without leading dot)
|
||||||
|
std::vector<std::string> watchExtensions;
|
||||||
|
|
||||||
|
// Directory names to ignore
|
||||||
|
std::vector<std::string> ignoreDirectories;
|
||||||
|
|
||||||
|
// Queues for the different file actions
|
||||||
|
Queue incomingRenderQueue;
|
||||||
|
Queue incomingDeleteQueue;
|
||||||
|
|
||||||
|
// Mutexes for thread safety
|
||||||
|
mutable std::mutex renderQueueMutex;
|
||||||
|
mutable std::mutex deleteQueueMutex;
|
||||||
|
mutable std::mutex extensionsMutex;
|
||||||
|
mutable std::mutex directoriesMutex;
|
||||||
|
|
||||||
|
// File watcher components
|
||||||
|
std::unique_ptr<efsw::FileWatcher> fileWatcher;
|
||||||
|
std::unique_ptr<UpdateListener> updateListener;
|
||||||
|
|
||||||
|
// Watch state
|
||||||
|
bool isWatching;
|
||||||
|
std::atomic<bool> stopRequested;
|
||||||
|
std::thread watcherThread;
|
||||||
|
|
||||||
|
// Path being watched
|
||||||
|
std::string watchPath;
|
||||||
|
|
||||||
|
// Internal function to run the watcher in a separate thread
|
||||||
|
void watcherThreadFunc();
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// Global variable within oom namespace
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
std::atomic<bool> active_render(false);
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
// IMPLEMENTATION SECTION - Method implementations for the above classes
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// UpdateListener implementation
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
UpdateListener::UpdateListener(Watcher* parent)
|
||||||
|
: should_stop_(false), parentWatcher(parent) {}
|
||||||
|
|
||||||
|
void UpdateListener::stop() {
|
||||||
|
should_stop_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string UpdateListener::getActionName(efsw::Action action) {
|
||||||
|
switch (action) {
|
||||||
|
case efsw::Actions::Add:
|
||||||
|
return "Add";
|
||||||
|
case efsw::Actions::Modified:
|
||||||
|
return "Modified";
|
||||||
|
case efsw::Actions::Delete:
|
||||||
|
return "Delete";
|
||||||
|
case efsw::Actions::Moved:
|
||||||
|
return "Moved";
|
||||||
|
default:
|
||||||
|
return "Bad Action";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UpdateListener::isWatchedExtension(const std::string& extension) {
|
||||||
|
// Get the extensions list from parent
|
||||||
|
const auto& extensions = parentWatcher->getWatchExtensions();
|
||||||
|
|
||||||
|
// Check if the extension is in our watch list
|
||||||
|
return std::find(extensions.begin(), extensions.end(), extension) != extensions.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UpdateListener::isIgnoredDirectory(const std::string& directory) {
|
||||||
|
// Get the ignored directories list from parent
|
||||||
|
const auto& ignoreDirs = parentWatcher->getIgnoreDirectories();
|
||||||
|
|
||||||
|
// Check if the directory is in our ignore list
|
||||||
|
return std::find(ignoreDirs.begin(), ignoreDirs.end(), directory) != ignoreDirs.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateListener::handleFileAction(efsw::WatchID watchid,
|
||||||
|
const std::string& dir,
|
||||||
|
const std::string& filename,
|
||||||
|
efsw::Action action,
|
||||||
|
std::string oldFilename) {
|
||||||
|
if (should_stop_) return; // Early exit if we're stopping
|
||||||
|
|
||||||
|
std::string actionName = getActionName(action);
|
||||||
|
std::filesystem::path filePath = dir + filename;
|
||||||
|
std::filesystem::path parentPath = dir;
|
||||||
|
|
||||||
|
// Get the filename extension without the dot
|
||||||
|
std::string extension = filePath.extension().string();
|
||||||
|
if (!extension.empty() && extension[0] == '.') {
|
||||||
|
extension = extension.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the parent directory name
|
||||||
|
std::string parentDir = parentPath.filename().string();
|
||||||
|
|
||||||
|
// Check if we should ignore this directory
|
||||||
|
if (isIgnoredDirectory(parentDir)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process based on the action type
|
||||||
|
if (actionName == "Delete") {
|
||||||
|
if (isWatchedExtension(extension)) {
|
||||||
|
parentWatcher->addToDeleteQueue(filePath);
|
||||||
|
std::cout << "\n==" << "STOP RENDER: " << filePath.string() << "\n==" << std::endl;
|
||||||
|
}
|
||||||
|
} else if (actionName == "Add" || actionName == "Modified") {
|
||||||
|
if (should_stop_) return; // Check again before starting render
|
||||||
|
|
||||||
|
if (isWatchedExtension(extension)) {
|
||||||
|
parentWatcher->addToRenderQueue(filePath);
|
||||||
|
std::cout << "\n==" << "RENDER QUEUED: " << filePath.string() << "\n==" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// Watcher implementation
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Watcher::Watcher(const std::vector<std::string>& extensions,
|
||||||
|
const std::vector<std::string>& ignoreDirs)
|
||||||
|
: isWatching(false), stopRequested(false) {
|
||||||
|
// Process extensions to ensure they don't have leading dots
|
||||||
|
for (const auto& ext : extensions) {
|
||||||
|
std::string processedExt = ext;
|
||||||
|
if (!ext.empty() && ext[0] == '.') {
|
||||||
|
processedExt = ext.substr(1);
|
||||||
|
}
|
||||||
|
watchExtensions.push_back(processedExt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store ignored directories
|
||||||
|
ignoreDirectories = ignoreDirs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Watcher::~Watcher() {
|
||||||
|
stopWatching();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Watcher::startWatching(const std::string& directory) {
|
||||||
|
if (isWatching) {
|
||||||
|
stopWatching();
|
||||||
|
}
|
||||||
|
|
||||||
|
watchPath = directory;
|
||||||
|
stopRequested = false;
|
||||||
|
|
||||||
|
// Start the watcher thread
|
||||||
|
watcherThread = std::thread(&Watcher::watcherThreadFunc, this);
|
||||||
|
isWatching = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Watcher::stopWatching() {
|
||||||
|
if (!isWatching) return;
|
||||||
|
|
||||||
|
stopRequested = true;
|
||||||
|
|
||||||
|
if (updateListener) {
|
||||||
|
updateListener->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (watcherThread.joinable()) {
|
||||||
|
watcherThread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
isWatching = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Watcher::getNextFileToRender(std::filesystem::path& outPath) {
|
||||||
|
std::lock_guard<std::mutex> lock(renderQueueMutex);
|
||||||
|
return incomingRenderQueue.pop(outPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Watcher::getNextFileToDelete(std::filesystem::path& outPath) {
|
||||||
|
std::lock_guard<std::mutex> lock(deleteQueueMutex);
|
||||||
|
return incomingDeleteQueue.pop(outPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Watcher::hasFilesToRender() const {
|
||||||
|
std::lock_guard<std::mutex> lock(renderQueueMutex);
|
||||||
|
return !incomingRenderQueue.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Watcher::hasFilesToDelete() const {
|
||||||
|
std::lock_guard<std::mutex> lock(deleteQueueMutex);
|
||||||
|
return !incomingDeleteQueue.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Watcher::addExtension(const std::string& extension) {
|
||||||
|
std::lock_guard<std::mutex> lock(extensionsMutex);
|
||||||
|
std::string processedExt = extension;
|
||||||
|
if (!extension.empty() && extension[0] == '.') {
|
||||||
|
processedExt = extension.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it already exists
|
||||||
|
if (std::find(watchExtensions.begin(), watchExtensions.end(), processedExt) == watchExtensions.end()) {
|
||||||
|
watchExtensions.push_back(processedExt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Watcher::removeExtension(const std::string& extension) {
|
||||||
|
std::lock_guard<std::mutex> lock(extensionsMutex);
|
||||||
|
std::string processedExt = extension;
|
||||||
|
if (!extension.empty() && extension[0] == '.') {
|
||||||
|
processedExt = extension.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = std::find(watchExtensions.begin(), watchExtensions.end(), processedExt);
|
||||||
|
if (it != watchExtensions.end()) {
|
||||||
|
watchExtensions.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Watcher::addIgnoreDirectory(const std::string& directory) {
|
||||||
|
std::lock_guard<std::mutex> lock(directoriesMutex);
|
||||||
|
|
||||||
|
// Check if it already exists
|
||||||
|
if (std::find(ignoreDirectories.begin(), ignoreDirectories.end(), directory) == ignoreDirectories.end()) {
|
||||||
|
ignoreDirectories.push_back(directory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Watcher::removeIgnoreDirectory(const std::string& directory) {
|
||||||
|
std::lock_guard<std::mutex> lock(directoriesMutex);
|
||||||
|
|
||||||
|
auto it = std::find(ignoreDirectories.begin(), ignoreDirectories.end(), directory);
|
||||||
|
if (it != ignoreDirectories.end()) {
|
||||||
|
ignoreDirectories.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Watcher::addToRenderQueue(const std::filesystem::path& path) {
|
||||||
|
std::lock_guard<std::mutex> lock(renderQueueMutex);
|
||||||
|
if (!incomingRenderQueue.contains(path)) {
|
||||||
|
incomingRenderQueue.push(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Watcher::addToDeleteQueue(const std::filesystem::path& path) {
|
||||||
|
std::lock_guard<std::mutex> lock(deleteQueueMutex);
|
||||||
|
if (!incomingDeleteQueue.contains(path)) {
|
||||||
|
incomingDeleteQueue.push(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Watcher::watcherThreadFunc() {
|
||||||
|
// Create a new FileWatcher
|
||||||
|
fileWatcher = std::make_unique<efsw::FileWatcher>(false);
|
||||||
|
|
||||||
|
// Create a new UpdateListener
|
||||||
|
updateListener = std::make_unique<UpdateListener>(this);
|
||||||
|
|
||||||
|
// Configure the watcher
|
||||||
|
fileWatcher->followSymlinks(false);
|
||||||
|
fileWatcher->allowOutOfScopeLinks(false);
|
||||||
|
|
||||||
|
// Check if the directory exists
|
||||||
|
if (!watchPath.empty() && std::filesystem::exists(watchPath)) {
|
||||||
|
// Add the directory to watch
|
||||||
|
efsw::WatchID watchID = fileWatcher->addWatch(watchPath, updateListener.get(), true);
|
||||||
|
|
||||||
|
if (watchID > 0) {
|
||||||
|
// Start watching
|
||||||
|
fileWatcher->watch();
|
||||||
|
std::cout << "Watching directory: " << watchPath << std::endl;
|
||||||
|
|
||||||
|
// Run until stopped
|
||||||
|
while (!stopRequested) {
|
||||||
|
efsw::System::sleep(500);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cout << "Error trying to watch directory: " << watchPath << std::endl;
|
||||||
|
std::cout << efsw::Errors::Log::getLastErrorLog().c_str() << std::endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cout << "Error: Directory does not exist: " << watchPath << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace file
|
||||||
|
} // namespace oom
|
||||||
101
oom_license.h
101
oom_license.h
@ -86,5 +86,106 @@ https://github.com/libimobiledevice/libplist
|
|||||||
|
|
||||||
This software uses libraries from the libplist project under the LGPL version 2.1.)";
|
This software uses libraries from the libplist project under the LGPL version 2.1.)";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::string printDayEnvironmentHDRI019_1K_TONEMAPPED() { return R"(
|
||||||
|
DayEnvironmentHDRI019_1K-TONEMAPPED.jpg from ambientCG.com,
|
||||||
|
licensed under the Creative Commons CC0 1.0 Universal License.)";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string printJson() { return R"(
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT)";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string printSTBImage() { return R"(
|
||||||
|
STB Image
|
||||||
|
https://github.com/nothings/stb
|
||||||
|
|
||||||
|
License: Public Domain)";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string printLibSodium() { return R"(
|
||||||
|
libsodium
|
||||||
|
|
||||||
|
|
||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright (c) 2013-2025
|
||||||
|
Frank Denis <j at pureftpd dot org>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.)";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string printCppZMQ() { return R"(
|
||||||
|
cppZMQ
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to
|
||||||
|
deal in the Software without restriction, including without limitation the
|
||||||
|
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
IN THE SOFTWARE.)";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string printLibZMQ() { return R"(
|
||||||
|
libzmq
|
||||||
|
https://github.com/zeromq/libzmq
|
||||||
|
|
||||||
|
libzmq is free software; you can redistribute it and/or modify it under the terms of the Mozilla Public License Version 2.0.)";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string printEFSW() { return R"(
|
||||||
|
efsw
|
||||||
|
|
||||||
|
Copyright (c) 2020 Martín Lucas Golini
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com)
|
||||||
|
http://code.google.com/p/simplefilewatcher/ also MIT licensed.)";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
16
oom_misc.h
16
oom_misc.h
@ -3,17 +3,8 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream> // For std::ofstream
|
#include <fstream> // For std::ofstream
|
||||||
#include <filesystem> // For std::filesystem
|
#include <filesystem> // For std::filesystem
|
||||||
//#include "DayEnvironmentHDRI019_1K-TONEMAPPED.h" // embedded image dome light
|
|
||||||
#include <cmath> // For std::pow
|
#include <cmath> // For std::pow
|
||||||
|
|
||||||
/*extern const unsigned int DayEnvironmentHDRI019_1K_TONEMAPPED_jpg_len;
|
|
||||||
extern const unsigned char DayEnvironmentHDRI019_1K_TONEMAPPED_jpg[];
|
|
||||||
inline float srgbToLinear(float value);
|
|
||||||
inline std::vector<uint8_t> LZFSEToArray(const std::string& lzfseFullName);
|
|
||||||
inline std::vector<uint8_t> decompressLZFSE(const std::string& dirName, const std::string& compressedName);
|
|
||||||
inline void saveHDRI();
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace oom {
|
namespace oom {
|
||||||
namespace misc {
|
namespace misc {
|
||||||
//Forward declarations
|
//Forward declarations
|
||||||
@ -93,13 +84,6 @@ namespace oom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline std::string printDayEnvironmentHDRI019_1K_TONEMAPPEDLicence() {
|
|
||||||
return R"(
|
|
||||||
DayEnvironmentHDRI019_1K-TONEMAPPED.jpg from ambientCG.com,
|
|
||||||
licensed under the Creative Commons CC0 1.0 Universal License.)";
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned char DayEnvironmentHDRI019_1K_TONEMAPPED_jpg[] = {
|
const unsigned char DayEnvironmentHDRI019_1K_TONEMAPPED_jpg[] = {
|
||||||
0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01,
|
0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01,
|
||||||
0x01, 0x00, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xe1, 0x00, 0x4c,
|
0x01, 0x00, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xe1, 0x00, 0x4c,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user