From fdad683c9d08f14766a207374f91ca98db11d318 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 13 Jul 2009 16:05:53 +0100 Subject: [PATCH] Start on resource implementation --- buildings/white_house/white_house.xml | 5 ++ include/IBuilding.hpp | 7 +- include/IXMLParser.hpp | 14 +-- include/ResourceCache.hpp | 55 ++++++++++++ include/Resources.hpp | 47 ++++++++++ schemas/building.xsd | 12 +++ src/Building.cpp | 54 ++++++++++++ src/Editor.cpp | 8 +- src/Main.cpp | 3 + src/Resources.cpp | 120 ++++++++++++++++++++++++++ 10 files changed, 312 insertions(+), 13 deletions(-) create mode 100644 buildings/white_house/white_house.xml create mode 100644 include/ResourceCache.hpp create mode 100644 include/Resources.hpp create mode 100644 schemas/building.xsd create mode 100644 src/Resources.cpp diff --git a/buildings/white_house/white_house.xml b/buildings/white_house/white_house.xml new file mode 100644 index 0000000..5ad8237 --- /dev/null +++ b/buildings/white_house/white_house.xml @@ -0,0 +1,5 @@ + + + White House + house.obj + diff --git a/include/IBuilding.hpp b/include/IBuilding.hpp index 97fa687..074004a 100644 --- a/include/IBuilding.hpp +++ b/include/IBuilding.hpp @@ -19,14 +19,19 @@ #define INC_IBUILDING_HPP #include "Platform.hpp" +#include "IModel.hpp" -#include +#include // Interface to buildings and other bits of scenery struct IBuilding { virtual ~IBuilding() {} + + virtual IModelPtr model() const = 0; }; typedef shared_ptr IBuildingPtr; +IBuildingPtr loadBuilding(const string& aResId); + #endif diff --git a/include/IXMLParser.hpp b/include/IXMLParser.hpp index 4fedd43..aececb1 100644 --- a/include/IXMLParser.hpp +++ b/include/IXMLParser.hpp @@ -64,11 +64,11 @@ private: struct IXMLCallback { virtual ~IXMLCallback() {} - virtual void startElement(const std::string& localName, - const AttributeSet& attrs) = 0; - virtual void endElement(const std::string& localName) = 0; - virtual void text(const std::string& localName, - const std::string& aString) = 0; + virtual void startElement(const string& localName, + const AttributeSet& attrs) {} + virtual void endElement(const string& localName) {} + virtual void text(const string& localName, + const string& aString) {} }; // Interface to a validating XML parser @@ -79,8 +79,8 @@ struct IXMLParser { }; typedef std::tr1::shared_ptr IXMLParserPtr; - + IXMLParserPtr makeXMLParser(const std::string& aSchemaFile); - + #endif diff --git a/include/ResourceCache.hpp b/include/ResourceCache.hpp new file mode 100644 index 0000000..fd11aa9 --- /dev/null +++ b/include/ResourceCache.hpp @@ -0,0 +1,55 @@ +// +// Copyright (C) 2009 Nick Gasson +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef INC_RESOURCE_CACHE_HPP +#define INC_RESOURCE_CACHE_HPP + +#include +#include + +#include "Resources.hpp" + +// A generic cache for resources +template +class ResourceCache { +public: + typedef function LoaderType; + + ResourceCache(LoaderType aLoader, const string& aClass) + : myLoader(aLoader), myClass(aClass) {} + + T load(const string& aResId) + { + typename CacheType::iterator it = myCache.find(aResId); + if (it != myCache.end()) + return (*it).second; + else { + T loaded = myLoader(findResource(aResId, myClass)); + myCache[aResId] = loaded; + return loaded; + } + } + +private: + LoaderType myLoader; + const string myClass; + + typedef map CacheType; + CacheType myCache; +}; + +#endif diff --git a/include/Resources.hpp b/include/Resources.hpp new file mode 100644 index 0000000..48d7c1d --- /dev/null +++ b/include/Resources.hpp @@ -0,0 +1,47 @@ +// +// Copyright (C) 2009 Nick Gasson +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef INC_RESOURCES_HPP +#define INC_RESOURCES_HPP + +#include "Platform.hpp" + +#include +#include + +// Interface to game resource +// A game resource is a directory containing related media files +// E.g. a building resource might contain the model, textures, +// and the XML file describing it +struct IResource { + virtual ~IResource() {} + + virtual string name() const = 0; + virtual string xmlFileName() const = 0; +}; + +typedef shared_ptr IResourcePtr; + +typedef list ResourceList; +typedef ResourceList::iterator ResourceListIt; + +// Generic interface to game resources +void initResources(); +void enumResources(const string& aClass, ResourceList& aList); +IResourcePtr findResource(const string& aResId, const string& aClass); + +#endif diff --git a/schemas/building.xsd b/schemas/building.xsd new file mode 100644 index 0000000..5f0176b --- /dev/null +++ b/schemas/building.xsd @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/Building.cpp b/src/Building.cpp index a9b2864..0e7468e 100644 --- a/src/Building.cpp +++ b/src/Building.cpp @@ -16,3 +16,57 @@ // #include "IBuilding.hpp" +#include "Resources.hpp" +#include "ResourceCache.hpp" +#include "ILogger.hpp" +#include "IXMLParser.hpp" + +// Concrete implementation of buildings +class Building : public IBuilding, public IXMLCallback { +public: + Building(IResourcePtr aRes); + + // IBuildingInterface + IModelPtr model() const { return myModel; } + + // IXMLCallback interface + void text(const string& localName, const string& aString); +private: + IModelPtr myModel; + string myName; + IResourcePtr myResource; +}; + +Building::Building(IResourcePtr aRes) + : myName("???"), myResource(aRes) +{ + static IXMLParserPtr parser = makeXMLParser("schemas/building.xsd"); + + parser->parse(aRes->xmlFileName(), *this); +} + +void Building::text(const string& localName, const string& aString) +{ + debug() << "text " << localName << " = " << aString; + + if (localName == "name") + myName = aString; + else if (localName == "model") + myModel = loadModel(aString); +} + +namespace { + + IBuildingPtr loadBuildingXml(IResourcePtr aRes) + { + log() << "Loading building from " << aRes->xmlFileName(); + + return IBuildingPtr(new Building(aRes)); + } +} + +IBuildingPtr loadBuilding(const string& aResId) +{ + static ResourceCache cache(loadBuildingXml, "buildings"); + return cache.load(aResId); +} diff --git a/src/Editor.cpp b/src/Editor.cpp index 1d88ac9..eec9d74 100644 --- a/src/Editor.cpp +++ b/src/Editor.cpp @@ -21,8 +21,8 @@ #include "IMap.hpp" #include "Maths.hpp" #include "ILight.hpp" -#include "BuildingPanel.hpp" #include "ModelViewer.hpp" +#include "IBuilding.hpp" #include @@ -118,12 +118,10 @@ void addEditorGUI() theToolMenu = new Fl_Menu_Button(0, 0, panelW, 32); theToolMenu->copy(theTools); - theToolMenu->label("Track"); - - debug() << theToolMenu->value(); + theToolMenu->label("Track"); theModelViewer = new ModelViewer(0, 40, panelW, 200); - theModelViewer->setModel(loadModel("house.obj")); + theModelViewer->setModel(loadBuilding("white_house")->model()); } Editor::Editor(IMapPtr aMap, const string& aFileName) diff --git a/src/Main.cpp b/src/Main.cpp index 1c6bf13..6fc5739 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -18,6 +18,7 @@ #include "IWindow.hpp" #include "ILogger.hpp" #include "GameScreens.hpp" +#include "Resources.hpp" #include @@ -42,6 +43,8 @@ int main(int argc, char** argv) #ifndef WIN32 if (argc != 3) throw runtime_error("Usage: TrainGame (edit|play) [map]"); + + initResources(); const string mapFile(argv[2]); const string cmd(argv[1]); diff --git a/src/Resources.cpp b/src/Resources.cpp new file mode 100644 index 0000000..fe1e904 --- /dev/null +++ b/src/Resources.cpp @@ -0,0 +1,120 @@ +// +// Copyright (C) 2009 Nick Gasson +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "Resources.hpp" +#include "ILogger.hpp" + +#include +#include + +#include + +using namespace boost::filesystem; + +// A resource that reads data from a filesystem directory +class FilesystemResource : public IResource { +public: + FilesystemResource(const path& aPath) + : myPath(aPath) + { + + } + + // IResource interface + string name() const { return myPath.filename(); } + string xmlFileName() const + { + return (myPath / (name() + ".xml")).file_string(); + } +private: + const path myPath; +}; + +namespace { + const char* classes[] = { + "maps", "buildings", "engines", "waggons", + NULL + }; + + typedef map ResourceMap; + ResourceMap theResources; + + ResourceList& resClassList(const string& aClass) + { + if (theResources.find(aClass) == theResources.end()) + theResources[aClass] = ResourceList(); + return theResources[aClass]; + } + + void addResource(const char* aClass, IResourcePtr aRes) + { + resClassList(aClass).push_back(aRes); + } + + void addResourceDir(const char* aClass, const path& aPath) + { + debug() << "Add " << aClass << " from " << aPath; + + const path xmlFile = aPath / (aPath.filename() + ".xml"); + + if (!exists(xmlFile)) + warn() << "Missing resource XML file: " << xmlFile; + else + addResource(aClass, IResourcePtr(new FilesystemResource(aPath))); + } + + void lookInDir(const path& aPath) + { + log() << "Looking for resources in " << aPath; + + for (const char** p = classes; *p != NULL; ++p) { + if (exists(aPath / *p)) { + debug() << "Adding class " << *p; + + for (directory_iterator it(aPath / *p); + it != directory_iterator(); ++it) + if (is_directory(it->status())) + addResourceDir(*p, *it); + } + } + } +} + +// Set up the resource database and cache available objects +void initResources() +{ + lookInDir(current_path()); +} + +// Find all the resources of the given type +void enumResources(const string& aClass, ResourceList& aList) +{ + +} + +// Find a resource of a particular type +IResourcePtr findResource(const string& aResId, const string& aClass) +{ + ResourceList& rlist = resClassList(aClass); + for (ResourceListIt it = rlist.begin(); it != rlist.end(); ++it) { + if ((*it)->name() == aResId) + return *it; + } + + throw runtime_error("Failed to find resource " + aResId + + " in class " + aClass); +} -- 2.39.2