diff --git a/CMakeLists.txt b/CMakeLists.txt index 10abb8568..66254f4fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,17 +68,14 @@ set(INPUT_HEADER components/engine/input/oismanager.hpp components/engine/input/ components/engine/input/dispatcher.hpp components/engine/input/poller.hpp) source_group(input FILES ${INPUT} ${INPUT_HEADER}) -set(MISC components/misc/stringops.cpp components/misc/fileops.cpp) -set(MISC_HEADER components/misc/fileops.hpp components/misc/slice_array.hpp - components/misc/stringops.hpp) -source_group(misc FILES ${MISC} ${MISC_HEADER}) - set(COMPONENTS ${BSA} ${NIF} ${NIFOGRE} ${ESM_STORE} ${OGRE} ${INPUT} ${MISC}) set(COMPONENTS_HEADER ${BSA_HEADER} ${NIF_HEADER} ${NIFOGRE_HEADER} ${ESM_STORE_HEADER} ${ESM_HEADER} ${OGRE_HEADER} ${INPUT_HEADER} ${MISC_HEADER}) # source directory: libs +ADD_SUBDIRECTORY( libs/platform ) + set(MANGLE_VFS libs/mangle/vfs/servers/ogre_vfs.cpp) source_group(mangle_vfs FILES ${MANGLE_VFS}) @@ -148,6 +145,7 @@ target_link_libraries(openmw ${OGRE_LIBRARIES} ${OIS_LIBRARIES} ${Boost_LIBRARIES} + platform caelum) if (APPLE) diff --git a/Docs/Doxyfile b/Docs/Doxyfile index f1f5fda07..5adeea871 100644 --- a/Docs/Doxyfile +++ b/Docs/Doxyfile @@ -573,7 +573,10 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = .. +INPUT = ..\apps + ..\components + ..\libs + ..\docs # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 143f62792..6e6568ac8 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -7,7 +7,7 @@ #include "components/esm_store/cell_store.hpp" #include "components/bsa/bsa_archive.hpp" #include "components/engine/ogre/renderer.hpp" -#include "components/misc/fileops.hpp" +#include "libs/platform/fileops.hpp" #include "apps/openmw/mwrender/interior.hpp" #include "mwinput/inputmanager.hpp" @@ -104,7 +104,7 @@ void OMW::Engine::go() const char* plugCfg = "plugins.cfg"; - mOgre.configure(!isFile("ogre.cfg"), plugCfg, false); + mOgre.configure(!OMW::Platform::isFile("ogre.cfg"), plugCfg, false); addResourcesDirectory (mDataDir / "Meshes"); addResourcesDirectory (mDataDir / "Textures"); diff --git a/components/esm/esm_reader.hpp b/components/esm/esm_reader.hpp index c03f1d162..033675222 100644 --- a/components/esm/esm_reader.hpp +++ b/components/esm/esm_reader.hpp @@ -12,7 +12,7 @@ #include #include #include -#include "components/misc/stringops.hpp" +#include "libs/platform/stringops.hpp" #ifdef __APPLE__ // need our own implementation of strnlen @@ -218,6 +218,8 @@ public: /// parse the header. void openRaw(Mangle::Stream::StreamPtr _esm, const std::string &name) { + using namespace OMW::Platform; + close(); esm = _esm; c.filename = name; diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 8396a0a7b..67f2dec36 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -30,8 +30,9 @@ namespace Nif { /// Anything that has a controller -struct Controlled : Extra +class Controlled : public Extra { +public: ControllerPtr controller; void read(NIFFile *nif) @@ -42,8 +43,9 @@ struct Controlled : Extra }; /// Has name, extra-data and controller -struct Named : Controlled +class Named : public Controlled { +public: SString name; void read(NIFFile *nif) @@ -54,8 +56,9 @@ struct Named : Controlled }; typedef Named NiSequenceStreamHelper; -struct NiParticleGrowFade : Controlled +class NiParticleGrowFade : public Controlled { +public: void read(NIFFile *nif) { Controlled::read(nif); @@ -65,8 +68,9 @@ struct NiParticleGrowFade : Controlled } }; -struct NiParticleColorModifier : Controlled +class NiParticleColorModifier : public Controlled { +public: NiColorDataPtr data; void read(NIFFile *nif) @@ -76,8 +80,9 @@ struct NiParticleColorModifier : Controlled } }; -struct NiGravity : Controlled +class NiGravity : public Controlled { +public: void read(NIFFile *nif) { Controlled::read(nif); @@ -88,8 +93,9 @@ struct NiGravity : Controlled }; // NiPinaColada -struct NiPlanarCollider : Controlled +class NiPlanarCollider : public Controlled { +public: void read(NIFFile *nif) { Controlled::read(nif); @@ -99,8 +105,9 @@ struct NiPlanarCollider : Controlled } }; -struct NiParticleRotation : Controlled +class NiParticleRotation : public Controlled { +public: void read(NIFFile *nif) { Controlled::read(nif); diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 49a38cfaa..d6fb22255 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -31,8 +31,9 @@ namespace Nif { -struct Controller : Record +class Controller : public Record { +public: ControllerPtr next; int flags; float frequency, phase; @@ -54,8 +55,9 @@ struct Controller : Record } }; -struct NiBSPArrayController : Controller +class NiBSPArrayController : public Controller { +public: void read(NIFFile *nif) { Controller::read(nif); @@ -68,8 +70,9 @@ struct NiBSPArrayController : Controller }; typedef NiBSPArrayController NiParticleSystemController; -struct NiMaterialColorController : Controller +class NiMaterialColorController : public Controller { +public: NiPosDataPtr data; void read(NIFFile *nif) @@ -79,8 +82,9 @@ struct NiMaterialColorController : Controller } }; -struct NiPathController : Controller +class NiPathController : public Controller { +public: NiPosDataPtr posData; NiFloatDataPtr floatData; @@ -99,8 +103,9 @@ struct NiPathController : Controller } }; -struct NiUVController : Controller +class NiUVController : public Controller { +public: NiUVDataPtr data; void read(NIFFile *nif) @@ -112,8 +117,9 @@ struct NiUVController : Controller } }; -struct NiKeyframeController : Controller +class NiKeyframeController : public Controller { +public: NiKeyframeDataPtr data; void read(NIFFile *nif) @@ -123,8 +129,9 @@ struct NiKeyframeController : Controller } }; -struct NiAlphaController : Controller +class NiAlphaController : public Controller { +public: NiFloatDataPtr data; void read(NIFFile *nif) @@ -134,8 +141,9 @@ struct NiAlphaController : Controller } }; -struct NiGeomMorpherController : Controller +class NiGeomMorpherController : public Controller { +public: NiMorphDataPtr data; void read(NIFFile *nif) @@ -146,8 +154,9 @@ struct NiGeomMorpherController : Controller } }; -struct NiVisController : Controller +class NiVisController : public Controller { +public: NiVisDataPtr data; void read(NIFFile *nif) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 920c7cf45..18e78b7ab 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -29,8 +29,10 @@ namespace Nif { -struct NiSourceTexture : Named +class NiSourceTexture : public Named { +public: + // Is this an external (references a separate texture file) or // internal (data is inside the nif itself) texture? bool external; @@ -65,7 +67,7 @@ struct NiSourceTexture : Named { Named::read(nif); - external = nif->getByte(); + external = !!nif->getByte(); if(external) filename = nif->getString(); else @@ -83,8 +85,9 @@ struct NiSourceTexture : Named }; // Common ancestor for several data classes -struct ShapeData : Record +class ShapeData : public Record { +public: FloatArray vertices, normals, colors, uvlist; const Vector *center; float radius; @@ -116,8 +119,9 @@ struct ShapeData : Record } }; -struct NiTriShapeData : ShapeData +class NiTriShapeData : public ShapeData { +public: // Triangles, three vertex indices per triangle SliceArray triangles; @@ -150,8 +154,9 @@ struct NiTriShapeData : ShapeData } }; -struct NiAutoNormalParticlesData : ShapeData +class NiAutoNormalParticlesData : public ShapeData { +public: int activeCount; void read(NIFFile *nif) @@ -171,8 +176,9 @@ struct NiAutoNormalParticlesData : ShapeData } }; -struct NiRotatingParticlesData : NiAutoNormalParticlesData +class NiRotatingParticlesData : public NiAutoNormalParticlesData { +public: void read(NIFFile *nif) { NiAutoNormalParticlesData::read(nif); @@ -185,8 +191,9 @@ struct NiRotatingParticlesData : NiAutoNormalParticlesData } }; -struct NiPosData : Record +class NiPosData : public Record { +public: void read(NIFFile *nif) { int count = nif->getInt(); @@ -210,8 +217,9 @@ struct NiPosData : Record } }; -struct NiUVData : Record +class NiUVData : public Record { +public: void read(NIFFile *nif) { // TODO: This is claimed to be a "float animation key", which is @@ -235,8 +243,9 @@ struct NiUVData : Record } }; -struct NiFloatData : Record +class NiFloatData : public Record { +public: void read(NIFFile *nif) { int count = nif->getInt(); @@ -245,8 +254,9 @@ struct NiFloatData : Record } }; -struct NiPixelData : Record +class NiPixelData : public Record { +public: unsigned int rmask, gmask, bmask, amask; int bpp, mips; @@ -283,8 +293,9 @@ struct NiPixelData : Record } }; -struct NiColorData : Record +class NiColorData : public Record { +public: struct ColorData { float time; @@ -302,8 +313,9 @@ struct NiColorData : Record } }; -struct NiVisData : Record +class NiVisData : public Record { +public: void read(NIFFile *nif) { int count = nif->getInt(); @@ -319,8 +331,9 @@ struct NiVisData : Record } }; -struct NiSkinInstance : Record +class NiSkinInstance : public Record { +public: NiSkinDataPtr data; NodePtr root; NodeList bones; @@ -338,8 +351,9 @@ struct NiSkinInstance : Record void post(NIFFile *nif); }; -struct NiSkinData : Record +class NiSkinData : public Record { +public: // This is to make sure the structs are packed, ie. that the // compiler doesn't mess them up with extra alignment bytes. #pragma pack(push) @@ -395,8 +409,9 @@ struct NiSkinData : Record } }; -struct NiMorphData : Record +class NiMorphData : public Record { +public: void read(NIFFile *nif) { int morphCount = nif->getInt(); @@ -416,8 +431,9 @@ struct NiMorphData : Record } }; -struct NiKeyframeData : Record +class NiKeyframeData : public Record { +public: void read(NIFFile *nif) { // Rotations first diff --git a/components/nif/extra.hpp b/components/nif/extra.hpp index 788fe3113..25375c325 100644 --- a/components/nif/extra.hpp +++ b/components/nif/extra.hpp @@ -35,15 +35,17 @@ namespace Nif themselves decend from the Extra class, and all the extra data connected to an object form a linked list */ -struct Extra : Record +class Extra : public Record { +public: ExtraPtr extra; void read(NIFFile *nif) { extra.read(nif); } }; -struct NiVertWeightsExtraData : Extra +class NiVertWeightsExtraData : public Extra { +public: void read(NIFFile *nif) { Extra::read(nif); @@ -57,8 +59,9 @@ struct NiVertWeightsExtraData : Extra } }; -struct NiTextKeyExtraData : Extra +class NiTextKeyExtraData : public Extra { +public: struct TextKey { float time; @@ -83,8 +86,9 @@ struct NiTextKeyExtraData : Extra } }; -struct NiStringExtraData : Extra +class NiStringExtraData : public Extra { +public: /* Two known meanings: "MRK" - marker, only visible in the editor, not rendered in-game "NCO" - no collision diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index 12845e617..027f64760 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -23,7 +23,7 @@ #include "nif_file.hpp" #include "record.hpp" -#include "components/misc/stringops.hpp" +#include "libs/platform/stringops.hpp" #include "extra.hpp" #include "controlled.hpp" @@ -44,6 +44,8 @@ using namespace Nif; void NIFFile::parse() { + using namespace OMW::Platform; + // Check the header string const char* head = getString(40); if(!begins(head, "NetImmerse File Format")) diff --git a/components/nif/nif_file.hpp b/components/nif/nif_file.hpp index f6ee80a9e..858ccb36a 100644 --- a/components/nif/nif_file.hpp +++ b/components/nif/nif_file.hpp @@ -28,7 +28,7 @@ #include #include -#include "../misc/slice_array.hpp" +#include "libs/platform/slice_array.hpp" #include #include diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 9e6b48885..f0ad54655 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -34,8 +34,9 @@ namespace Nif parent node (unless it's the root), and transformation (location and rotation) relative to it's parent. */ -struct Node : Named +class Node : public Named { +public: // Node flags. Interpretation depends somewhat on the type of node. int flags; const Transformation *trafo; @@ -55,7 +56,7 @@ struct Node : Named trafo = nif->getTrafo(); props.read(nif); - hasBounds = nif->getInt(); + hasBounds = !!nif->getInt(); if(hasBounds) { nif->getInt(); // always 1 diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 3500a25b7..1a16854af 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -29,8 +29,9 @@ namespace Nif { -struct Property : Named +class Property : public Named { +public: // The meaning of these depends on the actual property type. int flags; @@ -41,8 +42,9 @@ struct Property : Named } }; -struct NiTexturingProperty : Property +class NiTexturingProperty : public Property { +public: // A sub-texture struct Texture { @@ -67,7 +69,7 @@ struct NiTexturingProperty : Property void read(NIFFile *nif) { - inUse = nif->getInt(); + inUse = !!nif->getInt(); if(!inUse) return; texture.read(nif); diff --git a/libs/platform/CMakeLists.txt b/libs/platform/CMakeLists.txt new file mode 100755 index 000000000..42d56e8a8 --- /dev/null +++ b/libs/platform/CMakeLists.txt @@ -0,0 +1,14 @@ +project(Platform) + +file(GLOB_RECURSE SOURCES src/*) +file(GLOB_RECURSE CAELUM_HDR include/*) + +set(SOURCES + fileops.cpp + fileops.hpp + slice_array.hpp + stdint.h + stringops.cpp + stringops.hpp + strings.h) +add_library(platform STATIC ${SOURCES}) \ No newline at end of file diff --git a/libs/platform/fileops.cpp b/libs/platform/fileops.cpp new file mode 100644 index 000000000..52609488b --- /dev/null +++ b/libs/platform/fileops.cpp @@ -0,0 +1,11 @@ +#include "fileops.hpp" +#include + +namespace OMW { namespace Platform { + + bool isFile(const char *name) + { + boost::filesystem::path cfg_file_path(name); + return boost::filesystem::exists(cfg_file_path); + } +}} diff --git a/libs/platform/fileops.hpp b/libs/platform/fileops.hpp new file mode 100644 index 000000000..65f4b2ac7 --- /dev/null +++ b/libs/platform/fileops.hpp @@ -0,0 +1,10 @@ +#ifndef __FILEOPS_H_ +#define __FILEOPS_H_ + +namespace OMW { namespace Platform { + + /// Check if a given path is an existing file (not a directory) + bool isFile(const char *name); +}} + +#endif diff --git a/libs/platform/slice_array.hpp b/libs/platform/slice_array.hpp new file mode 100644 index 000000000..4dde8143b --- /dev/null +++ b/libs/platform/slice_array.hpp @@ -0,0 +1,75 @@ +/* + OpenMW - The completely unofficial reimplementation of Morrowind + Copyright (C) 2008-2010 Nicolay Korslund + Email: < korslund@gmail.com > + WWW: http://openmw.sourceforge.net/ + + This file (slice_array.h) is part of the OpenMW package. + + OpenMW is distributed as free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License + version 3, as published by the Free Software Foundation. + + 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 + version 3 along with this program. If not, see + http://www.gnu.org/licenses/ . + + */ + +#ifndef _SLICE_ARRAY_H_ +#define _SLICE_ARRAY_H_ + +// A simple array implementation containing a pointer and a +// length. Used for holding slices into a data buffer. +#include +template +struct SliceArray +{ + const T* ptr; + size_t length; + + /// Initialize to zero length + SliceArray() : ptr(0), length(0) {} + + /// Initialize from pointer + length + SliceArray(const T* _ptr, size_t _length) + : ptr(_ptr), length(_length) {} + + /// Initialize from null-terminated string + SliceArray(const char* str) + { + ptr = str; + length = strlen(str); + } + + bool operator==(SliceArray &t) + { + return + length == t.length && + (memcmp(ptr,t.ptr, length*sizeof(T)) == 0); + } + + /// Only use this for stings + bool operator==(const char* str) + { + return + str[length] == 0 && + (strncmp(ptr, str, length) == 0); + } + + /** This allocates a copy of the data. Only use this for debugging + and error messages. */ + std::string toString() + { return std::string(ptr,length); } +}; + +typedef SliceArray SString; +typedef SliceArray IntArray; +typedef SliceArray FloatArray; + +#endif diff --git a/libs/platform/stringops.cpp b/libs/platform/stringops.cpp new file mode 100644 index 000000000..16010aef7 --- /dev/null +++ b/libs/platform/stringops.cpp @@ -0,0 +1,63 @@ +#include "stringops.hpp" + +#include +#include "strings.h" + +namespace OMW { namespace Platform { + + bool begins(const char* str1, const char* str2) + { + while(*str2) + { + if(*str1 == 0 || *str1 != *str2) return false; + + str1++; + str2++; + } + return true; + } + + bool ends(const char* str1, const char* str2) + { + int len1 = strlen(str1); + int len2 = strlen(str2); + + if(len1 < len2) return false; + + return strcmp(str2, str1+len1-len2) == 0; + } + + // True if the given chars match, case insensitive + static bool icmp(char a, char b) + { + if(a >= 'A' && a <= 'Z') + a += 'a' - 'A'; + if(b >= 'A' && b <= 'Z') + b += 'a' - 'A'; + + return a == b; + } + + bool ibegins(const char* str1, const char* str2) + { + while(*str2) + { + if(*str1 == 0 || !icmp(*str1,*str2)) return false; + + str1++; + str2++; + } + return true; + } + + bool iends(const char* str1, const char* str2) + { + int len1 = strlen(str1); + int len2 = strlen(str2); + + if(len1 < len2) return false; + + return strcasecmp(str2, str1+len1-len2) == 0; + } + +}} diff --git a/libs/platform/stringops.hpp b/libs/platform/stringops.hpp new file mode 100644 index 000000000..8b53bd7e9 --- /dev/null +++ b/libs/platform/stringops.hpp @@ -0,0 +1,19 @@ +#ifndef __STRINGOPS_H +#define __STRINGOPS_H + +namespace OMW { namespace Platform { + + /// Returns true if str1 begins with substring str2 + bool begins(const char* str1, const char* str2); + + /// Returns true if str1 ends with substring str2 + bool ends(const char* str1, const char* str2); + + /// Case insensitive, returns true if str1 begins with substring str2 + bool ibegins(const char* str1, const char* str2); + + /// Case insensitive, returns true if str1 ends with substring str2 + bool iends(const char* str1, const char* str2); +}} + +#endif diff --git a/libs/platform/tests/.gitignore b/libs/platform/tests/.gitignore new file mode 100644 index 000000000..814490404 --- /dev/null +++ b/libs/platform/tests/.gitignore @@ -0,0 +1 @@ +*_test diff --git a/libs/platform/tests/output/slice_test.out b/libs/platform/tests/output/slice_test.out new file mode 100644 index 000000000..7b054082b --- /dev/null +++ b/libs/platform/tests/output/slice_test.out @@ -0,0 +1,6 @@ +hello, len=5 +001 +hell, len=4 +010 +01 +4 3 diff --git a/libs/platform/tests/output/strops_test.out b/libs/platform/tests/output/strops_test.out new file mode 100644 index 000000000..e69de29bb diff --git a/libs/platform/tests/slice_test.cpp b/libs/platform/tests/slice_test.cpp new file mode 100644 index 000000000..950194279 --- /dev/null +++ b/libs/platform/tests/slice_test.cpp @@ -0,0 +1,30 @@ +#include + +using namespace std; + +#include + +#include "../slice_array.hpp" + +int main() +{ + SString s, t; + s = SString("hello"); + cout << s.toString() << ", len=" << s.length << endl; + cout << (s=="hel") << (s=="hell") << (s=="hello") << endl; + t = s; + + s = SString("othello"+2, 4); + cout << s.toString() << ", len=" << s.length << endl; + cout << (s=="hel") << (s=="hell") << (s=="hello") << endl; + + cout << (s==t) << (SString("hello")==t) << endl; + + const int arr[4] = {1,2,3,4}; + + IntArray ia(arr,4); + + cout << ia.length << " " << ia.ptr[2] << endl; + + return 0; +} diff --git a/libs/platform/tests/strops_test.cpp b/libs/platform/tests/strops_test.cpp new file mode 100644 index 000000000..ca5bd55a9 --- /dev/null +++ b/libs/platform/tests/strops_test.cpp @@ -0,0 +1,48 @@ +#include + +#include "../stringops.hpp" + +int main() +{ + assert(begins("abc", "a")); + assert(begins("abc", "ab")); + assert(begins("abc", "abc")); + assert(begins("abcd", "abc")); + + assert(!begins("abc", "b")); + assert(!begins("abc", "bc")); + assert(!begins("abc", "bcd")); + assert(!begins("abc", "abcd")); + + assert(ibegins("Abc", "a")); + assert(ibegins("aBc", "ab")); + assert(ibegins("abC", "abc")); + assert(ibegins("abcD", "abc")); + + assert(!ibegins("abc", "b")); + assert(!ibegins("abc", "bc")); + assert(!ibegins("abc", "bcd")); + assert(!ibegins("abc", "abcd")); + + assert(ends("abc", "c")); + assert(ends("abc", "bc")); + assert(ends("abc", "abc")); + assert(ends("abcd", "abcd")); + + assert(!ends("abc", "b")); + assert(!ends("abc", "ab")); + assert(!ends("abc", "bcd")); + assert(!ends("abc", "abcd")); + + assert(iends("Abc", "c")); + assert(iends("aBc", "bc")); + assert(iends("abC", "abc")); + assert(iends("abcD", "abcd")); + + assert(!iends("abc", "b")); + assert(!iends("abc", "ab")); + assert(!iends("abc", "bcd")); + assert(!iends("abc", "abcd")); + + return 0; +} diff --git a/libs/platform/tests/test.sh b/libs/platform/tests/test.sh new file mode 100755 index 000000000..2d07708ad --- /dev/null +++ b/libs/platform/tests/test.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +make || exit + +mkdir -p output + +PROGS=*_test + +for a in $PROGS; do + if [ -f "output/$a.out" ]; then + echo "Running $a:" + ./$a | diff output/$a.out - + else + echo "Creating $a.out" + ./$a > "output/$a.out" + git add "output/$a.out" + fi +done