2015-05-15 22:39:43 +00:00
|
|
|
#ifndef HECLDATABASE_HPP
|
|
|
|
#define HECLDATABASE_HPP
|
|
|
|
|
2015-05-17 04:55:29 +00:00
|
|
|
#include <iterator>
|
|
|
|
#include <string>
|
2015-05-18 09:29:23 +00:00
|
|
|
#include <functional>
|
2015-05-19 07:01:18 +00:00
|
|
|
#include <vector>
|
2015-06-09 22:19:59 +00:00
|
|
|
#include <map>
|
|
|
|
#include <memory>
|
|
|
|
#include <atomic>
|
2015-05-21 02:33:05 +00:00
|
|
|
#include <stdexcept>
|
2015-05-18 09:29:23 +00:00
|
|
|
#include <stdint.h>
|
2015-05-17 04:55:29 +00:00
|
|
|
|
2015-05-20 05:22:32 +00:00
|
|
|
#include "HECL.hpp"
|
2015-05-19 07:01:18 +00:00
|
|
|
|
2015-05-17 04:55:29 +00:00
|
|
|
namespace HECLDatabase
|
|
|
|
{
|
|
|
|
|
2015-05-21 02:33:05 +00:00
|
|
|
/**
|
|
|
|
* @brief Base object to subclass for integrating with key project operations
|
|
|
|
*
|
|
|
|
* All project objects are provided with IDataObject pointers to their database
|
|
|
|
* entries. Subclasses register themselves with a type registry so instances
|
|
|
|
* are automatically constructed when performing operations like cooking and packaging.
|
|
|
|
*
|
|
|
|
* DO NOT CONSTRUCT THIS OR SUBCLASSES DIRECTLY!!
|
|
|
|
*/
|
2015-06-09 22:19:59 +00:00
|
|
|
class ProjectObjectBase
|
2015-05-21 02:33:05 +00:00
|
|
|
{
|
|
|
|
friend class CProject;
|
2015-06-09 22:19:59 +00:00
|
|
|
std::string m_path;
|
|
|
|
protected:
|
2015-05-21 02:33:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Byte-order of target system
|
|
|
|
*/
|
|
|
|
enum DataEndianness
|
|
|
|
{
|
|
|
|
DE_NONE,
|
|
|
|
DE_BIG, /**< Big-endian (PowerPC) */
|
|
|
|
DE_LITTLE /**< Little-endian (Intel) */
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Data-formats of target system
|
|
|
|
*/
|
|
|
|
enum DataPlatform
|
|
|
|
{
|
|
|
|
DP_NONE,
|
|
|
|
DP_GENERIC, /**< Scanline textures and 3-way shader bundle (GLSL, HLSL, SPIR-V) */
|
|
|
|
DP_REVOLUTION, /**< Tiled textures and GX register buffers */
|
|
|
|
DP_CAFE /**< Swizzled textures and R700 shader objects */
|
|
|
|
};
|
|
|
|
|
2015-06-09 22:19:59 +00:00
|
|
|
typedef std::function<void(const void* data, size_t len)> FDataAppender;
|
2015-05-21 02:33:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Optional private method implemented by CProjectObject subclasses to cook objects
|
|
|
|
* @param dataAppender subclass calls this function zero or more times to provide cooked-data linearly
|
|
|
|
* @param endianness byte-order to target
|
|
|
|
* @param platform data-formats to target
|
|
|
|
* @return true if cook succeeded
|
|
|
|
*
|
|
|
|
* This method is called during IProject::cookPath().
|
|
|
|
* Part of the cooking process may include embedding database-refs to dependencies.
|
|
|
|
* This method should store the 64-bit value provided by IDataObject::id() when doing this.
|
|
|
|
*/
|
2015-06-09 22:19:59 +00:00
|
|
|
virtual bool _cookObject(FDataAppender dataAppender,
|
2015-05-21 02:33:05 +00:00
|
|
|
DataEndianness endianness, DataPlatform platform)
|
|
|
|
{(void)dataAppender;(void)endianness;(void)platform;return true;}
|
|
|
|
|
2015-06-09 22:19:59 +00:00
|
|
|
typedef std::function<void(ProjectObjectBase*)> FDepAdder;
|
2015-05-21 02:33:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Optional private method implemented by CProjectObject subclasses to resolve dependencies
|
|
|
|
* @param depAdder subclass calls this function zero or more times to register each dependency
|
|
|
|
*
|
|
|
|
* This method is called during IProject::packagePath().
|
|
|
|
* Dependencies registered via this method will eventually have this method called on themselves
|
|
|
|
* as well. This is a non-recursive operation, no need for subclasses to implement recursion-control.
|
|
|
|
*/
|
2015-06-09 22:19:59 +00:00
|
|
|
virtual void _gatherDeps(FDepAdder depAdder)
|
2015-05-21 02:33:05 +00:00
|
|
|
{(void)depAdder;}
|
|
|
|
|
|
|
|
public:
|
2015-06-09 22:19:59 +00:00
|
|
|
ProjectObjectBase(const std::string& path)
|
|
|
|
: m_path(path) {}
|
|
|
|
|
|
|
|
inline const std::string& getPath() const {return m_path;}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Overridable function to verify data at provided path
|
|
|
|
* @return true if ProjectObject subclass handles data at provided path/subpath
|
|
|
|
*/
|
|
|
|
static bool ClaimPath(const std::string& /*path*/, const std::string& /*subpath*/) {return false;}
|
|
|
|
|
2015-05-21 02:33:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-05-19 07:01:18 +00:00
|
|
|
/**
|
|
|
|
* @brief Main project interface
|
|
|
|
*
|
|
|
|
* Projects are intermediate working directories used for staging
|
|
|
|
* resources in their ideal editor-formats. This interface exposes all
|
|
|
|
* primary operations to perform on a given project.
|
|
|
|
*/
|
2015-06-09 22:19:59 +00:00
|
|
|
class Project
|
2015-05-19 07:01:18 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual ~IProject() {}
|
|
|
|
|
2015-05-21 02:33:05 +00:00
|
|
|
/**
|
|
|
|
* @brief Internal packagePath() exception
|
|
|
|
*
|
|
|
|
* Due to the recursive nature of packagePath(), there are potential
|
|
|
|
* pitfalls like infinite-recursion. HECL throws this whenever there
|
|
|
|
* are uncooked dependencies or if the maximum dependency-recursion
|
|
|
|
* limit is exceeded.
|
|
|
|
*/
|
|
|
|
class PackageException : public std::runtime_error {};
|
|
|
|
|
2015-05-19 07:01:18 +00:00
|
|
|
/**
|
|
|
|
* @brief A rough description of how 'expensive' a given cook operation is
|
|
|
|
*
|
|
|
|
* This is used to provide pretty colors during the cook operation
|
|
|
|
*/
|
2015-05-21 02:33:05 +00:00
|
|
|
enum Cost
|
2015-05-19 07:01:18 +00:00
|
|
|
{
|
2015-05-21 02:33:05 +00:00
|
|
|
C_NONE,
|
|
|
|
C_LIGHT,
|
|
|
|
C_MEDIUM,
|
|
|
|
C_HEAVY
|
2015-05-19 07:01:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Register an optional callback to report log-messages using
|
|
|
|
* @param logger logger-callback
|
2015-05-21 02:33:05 +00:00
|
|
|
*
|
|
|
|
* If this method is never called, all project operations will run silently.
|
2015-05-19 07:01:18 +00:00
|
|
|
*/
|
2015-05-20 05:22:32 +00:00
|
|
|
virtual void registerLogger(HECL::TLogger logger)=0;
|
2015-05-19 07:01:18 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get the path of the project's root-directory
|
|
|
|
* @param absolute return as absolute-path
|
|
|
|
* @return project root path
|
2015-05-21 02:33:05 +00:00
|
|
|
*
|
|
|
|
* Self explanatory
|
|
|
|
*/
|
2015-05-27 09:09:05 +00:00
|
|
|
virtual const HECL::ProjectRootPath& getProjectRootPath(bool absolute=false) const=0;
|
2015-05-21 02:33:05 +00:00
|
|
|
|
|
|
|
/**
|
2015-05-27 09:09:05 +00:00
|
|
|
* @brief Add given file(s) to the database
|
2015-05-19 07:01:18 +00:00
|
|
|
* @param path file or pattern within project
|
|
|
|
* @return true on success
|
2015-05-21 02:33:05 +00:00
|
|
|
*
|
|
|
|
* This method blocks while object hashing takes place
|
2015-05-19 07:01:18 +00:00
|
|
|
*/
|
2015-05-27 09:09:05 +00:00
|
|
|
virtual bool addPaths(const std::vector<HECL::ProjectPath>& paths)=0;
|
2015-05-19 07:01:18 +00:00
|
|
|
|
|
|
|
/**
|
2015-05-21 02:33:05 +00:00
|
|
|
* @brief Remove a given file or file-pattern from the database
|
2015-06-09 22:19:59 +00:00
|
|
|
* @param paths file(s) or pattern(s) within project
|
2015-05-21 02:33:05 +00:00
|
|
|
* @param recursive traverse into matched subdirectories
|
|
|
|
* @return true on success
|
|
|
|
*
|
|
|
|
* This method will not delete actual working files from the project
|
|
|
|
* directory. It will delete associated cooked objects though.
|
|
|
|
*/
|
2015-06-09 22:19:59 +00:00
|
|
|
virtual bool removePaths(const std::vector<HECL::ProjectPath>& paths, bool recursive=false)=0;
|
2015-05-21 02:33:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Register a working sub-directory as a Dependency Group
|
|
|
|
* @param path directory to register as Dependency Group
|
|
|
|
* @return true on success
|
|
|
|
*
|
|
|
|
* Dependency Groups are used at runtime to stage burst load-transactions.
|
|
|
|
* They may only be added to directories and will automatically claim
|
|
|
|
* subdirectories as well.
|
|
|
|
*
|
|
|
|
* Cooked objects in dependency groups will be packaged contiguously
|
|
|
|
* and automatically duplicated if shared with other dependency groups.
|
|
|
|
* This contiguous storage makes for optimal loading from slow block-devices
|
|
|
|
* like optical drives.
|
|
|
|
*/
|
2015-06-09 22:19:59 +00:00
|
|
|
virtual bool addGroup(const HECL::ProjectPath& path)=0;
|
2015-05-21 02:33:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Unregister a working sub-directory as a dependency group
|
|
|
|
* @param path directory to unregister as Dependency Group
|
|
|
|
* @return true on success
|
|
|
|
*/
|
2015-06-09 22:19:59 +00:00
|
|
|
virtual bool removeGroup(const HECL::ProjectPath& path)=0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Return map populated with platforms targetable by this project interface
|
|
|
|
* @return Platform map with name-string keys and enable-status values
|
|
|
|
*/
|
|
|
|
virtual const std::map<const std::string, const bool>& listPlatforms()=0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Enable persistent user preference for particular platform string(s)
|
|
|
|
* @param platforms String(s) representing unique platform(s) from listPlatforms
|
|
|
|
* @return true on success
|
|
|
|
*/
|
|
|
|
virtual bool enablePlatforms(const std::vector<std::string>& platforms)=0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Disable persistent user preference for particular platform string(s)
|
|
|
|
* @param platform String(s) representing unique platform(s) from listPlatforms
|
|
|
|
* @return true on success
|
|
|
|
*/
|
|
|
|
virtual bool disablePlatforms(const std::vector<std::string>& platforms)=0;
|
2015-05-21 02:33:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Begin cook process for specified directory
|
|
|
|
* @param path directory of intermediates to cook
|
2015-05-19 07:01:18 +00:00
|
|
|
* @param feedbackCb a callback to run reporting cook-progress
|
|
|
|
* @param recursive traverse subdirectories to cook as well
|
|
|
|
* @return true on success
|
2015-05-21 02:33:05 +00:00
|
|
|
*
|
|
|
|
* Object cooking is generally an expensive process for large projects.
|
|
|
|
* This method blocks execution during the procedure, with periodic
|
|
|
|
* feedback delivered via feedbackCb.
|
2015-05-19 07:01:18 +00:00
|
|
|
*/
|
2015-06-09 22:19:59 +00:00
|
|
|
virtual bool cookPath(const HECL::SystemString& path,
|
2015-05-21 02:33:05 +00:00
|
|
|
std::function<void(std::string&, Cost, unsigned)> feedbackCb,
|
2015-05-19 07:01:18 +00:00
|
|
|
bool recursive=false)=0;
|
|
|
|
|
2015-05-19 21:01:32 +00:00
|
|
|
/**
|
|
|
|
* @brief Interrupts a cook in progress (call from SIGINT handler)
|
2015-05-21 02:33:05 +00:00
|
|
|
*
|
|
|
|
* Database corruption is bad! sqlite is pretty robust at avoiding data corruption,
|
|
|
|
* but HECL spreads its data objects through the filesystem; this ensures that
|
|
|
|
* those objects are cleanly finalized or discarded before stopping.
|
|
|
|
*
|
|
|
|
* Note that this method returns immediately; the resumed cookPath()
|
|
|
|
* call will return as quickly as possible.
|
2015-05-19 21:01:32 +00:00
|
|
|
*/
|
|
|
|
virtual void interruptCook()=0;
|
|
|
|
|
2015-05-19 07:01:18 +00:00
|
|
|
/**
|
2015-05-21 02:33:05 +00:00
|
|
|
* @brief Delete cooked objects for directory
|
|
|
|
* @param path directory of intermediates to clean
|
2015-05-19 07:01:18 +00:00
|
|
|
* @param recursive traverse subdirectories to clean as well
|
|
|
|
* @return true on success
|
2015-05-21 02:33:05 +00:00
|
|
|
*
|
|
|
|
* Developers understand how useful 'clean' is. While ideally not required,
|
|
|
|
* it's useful for verifying that a rebuild from ground-up is doable.
|
2015-05-19 07:01:18 +00:00
|
|
|
*/
|
2015-06-09 22:19:59 +00:00
|
|
|
virtual bool cleanPath(const HECL::SystemString& path, bool recursive=false)=0;
|
2015-05-19 07:01:18 +00:00
|
|
|
|
2015-05-21 02:33:05 +00:00
|
|
|
/**
|
2015-06-09 22:19:59 +00:00
|
|
|
* @brief Nodegraph class for gathering dependency-resolved objects for packaging
|
2015-05-21 02:33:05 +00:00
|
|
|
*/
|
2015-06-09 22:19:59 +00:00
|
|
|
class PackageDepsgraph
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
struct Node
|
|
|
|
{
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
NODE_DATA,
|
|
|
|
NODE_GROUP
|
|
|
|
} type;
|
|
|
|
std::string path;
|
|
|
|
ProjectObjectBase* projectObj;
|
|
|
|
Node* sub;
|
|
|
|
Node* next;
|
|
|
|
};
|
|
|
|
private:
|
|
|
|
friend class Project;
|
|
|
|
std::vector<Node> m_nodes;
|
|
|
|
public:
|
|
|
|
const Node* getRootNode() const {return &m_nodes[0];}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Constructs a full depsgraph of the project-subpath provided
|
|
|
|
* @param path Subpath of project to root depsgraph at
|
|
|
|
* @return Populated depsgraph ready to traverse
|
|
|
|
*/
|
|
|
|
virtual PackageDepsgraph buildPackageDepsgraph(const HECL::ProjectPath& path)=0;
|
2015-05-21 02:33:05 +00:00
|
|
|
|
2015-05-19 07:01:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2015-05-27 09:09:05 +00:00
|
|
|
* @brief Opens an existing or creates a new project using specified root directory
|
|
|
|
* @param rootPath Path to project root-directory
|
2015-05-19 07:01:18 +00:00
|
|
|
* @return New project object
|
2015-05-21 02:33:05 +00:00
|
|
|
*
|
|
|
|
* This is the preferred way to open an existing or create a new HECL project.
|
|
|
|
* All necessary database index files and object directories will be established
|
|
|
|
* within the specified directory path.
|
|
|
|
*/
|
2015-06-09 22:19:59 +00:00
|
|
|
Project* OpenProject(const HECL::ProjectRootPath& rootPath);
|
2015-05-21 02:33:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
2015-06-09 22:19:59 +00:00
|
|
|
* @brief Subclassed by dataspec entries to manage per-game aspects of the data pipeline
|
2015-05-21 02:33:05 +00:00
|
|
|
*
|
2015-06-09 22:19:59 +00:00
|
|
|
* The DataSpec class manages interfaces for unpackaging, cooking, and packaging
|
|
|
|
* of data for interacting with a specific system/game-engine.
|
2015-05-21 02:33:05 +00:00
|
|
|
*/
|
2015-06-09 22:19:59 +00:00
|
|
|
class IDataSpec
|
2015-05-21 02:33:05 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
2015-06-09 22:19:59 +00:00
|
|
|
virtual packageData();
|
2015-05-21 02:33:05 +00:00
|
|
|
};
|
|
|
|
|
2015-05-17 04:55:29 +00:00
|
|
|
}
|
|
|
|
|
2015-05-15 22:39:43 +00:00
|
|
|
#endif // HECLDATABASE_HPP
|