diff --git a/Makefile b/Makefile index b50119831..201b6f004 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # Designed for GNU Make # Compiler settings -CXXFLAGS?= -g -Iutil/ +CXXFLAGS?= -g DMD=gdmd -version=Posix # Some extra flags for niftool and bsatool @@ -32,8 +32,7 @@ ogre_cpp=ogre framelistener interface bsaarchive mygui_cpp=mygui console # Ditto for the landscape engine, in terrain/cpp_X.cpp -terrain_cpp=baseland esm generator landdata quad terrain terrainmesh \ -archive cachewriter +terrain_cpp=baseland terrain mesh # FFmpeg files, in the form sound/cpp_X.cpp. avcodec_cpp=avcodec @@ -46,7 +45,7 @@ bullet_cpp=bullet player scale ogre_cpp_files=\ $(ogre_cpp:%=ogre/cpp_%.cpp) \ $(mygui_cpp:%=gui/cpp_%.cpp) \ - $(terrain_cpp:%=terrain/cpp_%.cpp) util/outbuffer.h util/mmfile.h + $(terrain_cpp:%=terrain/cpp_%.cpp) avcodec_cpp_files=$(avcodec_cpp:%=sound/cpp_%.cpp) bullet_cpp_files=$(bullet_cpp:%=bullet/cpp_%.cpp) diff --git a/bullet/cpp_bullet.cpp b/bullet/cpp_bullet.cpp index d61aa6baa..50af01b57 100644 --- a/bullet/cpp_bullet.cpp +++ b/bullet/cpp_bullet.cpp @@ -25,7 +25,7 @@ #include -#include "dbg.h" +#include "../util/dbg.h" using namespace std; diff --git a/ogre/cpp_ogre.cpp b/ogre/cpp_ogre.cpp index 7338517b3..c70c7d5a6 100644 --- a/ogre/cpp_ogre.cpp +++ b/ogre/cpp_ogre.cpp @@ -35,7 +35,7 @@ #include -#include "dbg.h" +#include "../util/dbg.h" using namespace Ogre; diff --git a/terrain/archive.d b/terrain/archive.d new file mode 100644 index 000000000..ad2cd5ea0 --- /dev/null +++ b/terrain/archive.d @@ -0,0 +1,463 @@ +/* + OpenMW - The completely unofficial reimplementation of Morrowind + Copyright (C) 2009 Nicolay Korslund + WWW: http://openmw.sourceforge.net/ + + This file (archive.d) 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/ . + +*/ + +// This should also be part of the generic cache system. +const int CACHE_MAGIC = 0x345AF815; + +import std.mmfile; +import std.stream; +import std.string; + +version(Windows) + static int pageSize = 64*1024; +else + static int pageSize = 4*1024; + +// Info about the entire quad. TODO: Some of this (such as the texture +// scale and probably the width and radius) can be generated at +// loadtime and is common for all quads on the same level. We could +// just make a QuadLevelInfo struct. +struct QuadInfo +{ + // Basic info + int cellX, cellY; + int level; + + // Bounding box info + float minHeight, maxHeight; + float worldWidth; + float boundingRadius; + + // Texture scale for this quad + float texScale; + + // True if we should make the given child + bool hasChild[4]; + + // Number of mesh segments in this quad + int meshNum; + + // Location of this quad in the main archive file. The size includes + // everything related to this quad, including mesh data, alpha maps, + // etc. + size_t offset, size; +} + + +// Info about an alpha map belonging to a mesh +struct AlphaInfo +{ + size_t bufSize, bufOffset; + + // The texture name for this layer. The actual string is stored in + // the archive's string buffer. + int texName; + int alphaName; + + // Fill the alpha texture buffer + void fillAlphaBuffer(ubyte *abuf) + { + g_archive.copy(abuf, bufOffset, bufSize); + } + + // Get the texture for this alpha layer + char[] getTexName() + { + return g_archive.getString(texName); + } + + // Get the material name to give the alpha texture + char[] getAlphaName() + { + return g_archive.getString(alphaName); + } +} + +// Info about each submesh +struct MeshInfo +{ + // Bounding box info + float minHeight, maxHeight; + float worldWidth; + + // Vertex and index numbers + int vertRows, vertCols; + int indexCount; + + // Scene node position (relative to the parent node) + float x, y; + + // Height offset to apply to all vertices + float heightOffset; + + // Size and offset of the vertex buffer + size_t vertBufSize, vertBufOffset; + + // Number and offset of AlphaInfo blocks + int alphaNum; + size_t alphaOffset; + + // Texture name. Index to the string table. + int texName; + + // Fill the given vertex buffer + void fillVertexBuffer(float *vbuf) + { + //g_archive.copy(vbuf, vertBufOffset, vertBufSize); + + // The height map and normals from the archive + char *hmap = cast(char*)g_archive.getRelSlice(vertBufOffset, vertBufSize).ptr; + + int level = getLevel(); + + // The generic part, containing the x,y coordinates and the uv + // maps. + float *gmap = g_archive.getVertexBuffer(level).ptr; + + // Calculate the factor to multiply each height value with. The + // heights are very limited in range as they are stored in a + // single byte. Normal MW data uses a factor of 8, but we have to + // double this for each successive level since we're splicing + // several vertices together and need to allow larger differences + // for each vertex. The formula is 8*2^(level-1). + float scale = 4.0 * (1<= 0); + assert(getLevel() == 1); + AlphaInfo *res = cast(AlphaInfo*)g_archive.getRelSlice + (alphaOffset, alphaNum*AlphaInfo.sizeof); + res += num; + return res; + } + + // Get the size of the alpha textures (in pixels). + int getAlphaSize() + { return g_archive.alphaSize; } + + // Get the texture and material name to use for this mesh. + char[] getTexName() + { return g_archive.getString(texName); } + + float getTexScale() + { return g_archive.curQuad.texScale; } + + char[] getBackgroundTex() + { return "_land_default.dds"; } +} + +struct ArchiveHeader +{ + // "Magic" number to make sure we're actually reading an archive + // file + int magic; + + // Total number of quads in the archive + int quads; + + // Level of the 'root' quad. There will only be one quad on this + // level. + int rootLevel; + + // Size of the alpha maps, in pixels along one side. + int alphaSize; + + // Number of strings in the string table + int stringNum; + + // Size of the string buffer + size_t stringSize; +} + +TerrainArchive g_archive; + +// This class handles the cached terrain data. +struct TerrainArchive +{ + MeshInfo *curMesh; + QuadInfo *curQuad; + QuadInfo *rootQuad; + + void openFile(char[] name) + { + mmf = new MmFile(name, + MmFile.Mode.Read, + 0, null, pageSize); + + // Read the index file first + File ifile = new File(name ~ ".index"); + + ArchiveHeader head; + ifile.readExact(&head, head.sizeof); + + // Sanity check + assert(head.magic == CACHE_MAGIC); + assert(head.quads > 0 && head.quads < 8192); + + // Store header info + alphaSize = head.alphaSize; + + // Read all the quads + quadList = new QuadInfo[head.quads]; + ifile.readExact(quadList.ptr, head.quads*QuadInfo.sizeof); + + // Create an index of all the quads + foreach(int index, qn; quadList) + { + int x = qn.cellX; + int y = qn.cellY; + int l = qn.level; + + assert(l >= 1); + + quadMap[l][x][y] = index; + + // Store the root quad + if(l == head.rootLevel) + { + assert(rootQuad == null); + rootQuad = &quadList[index]; + } + else + assert(l < head.rootLevel); + } + + // Make sure the root was set + assert(rootQuad !is null); + + // Next read the string table + stringBuf = new char[head.stringSize]; + strings.length = head.stringNum; + + // First read the main string buffer + ifile.readExact(stringBuf.ptr, head.stringSize); + + // Then read the string offsets + int[] offsets = new int[head.stringNum]; + ifile.readExact(offsets.ptr, offsets.length*int.sizeof); + + // Set up the string table + char *strptr = stringBuf.ptr; + foreach(int i, ref str; strings) + { + // toString(char*) returns the string up to the zero + // terminator byte + str = toString(strptr + offsets[i]); + } + delete offsets; + + // Read the vertex buffer data + int bufNum = head.rootLevel; + assert(bufNum == 7); + vertBufData.length = bufNum; + indexBufData.length = bufNum; + + // Fill the buffers. Start at level 1. + for(int i=1;i=1 && level=1 && level= 0); + assert(index < strings.length); + + return strings[index]; + } + + void doMap(size_t offset, size_t size) + { + assert(mmf !is null); + assert(size); + mapped = cast(ubyte[])mmf[offset..offset+size]; + assert(mapped.length == size); + } + + // Get a slice of a given buffer within the mapped window. The + // offset is relative to the start of the window, and the size must + // fit inside the window. + ubyte[] getRelSlice(size_t offset, size_t size) + { + assert(mapped.length); + + return mapped[offset..offset+size]; + } + + // Copy a given buffer from the file. The buffer might be a + // compressed stream, so it's important that the buffers are written + // the same as they are read. (Ie. you can't write a buffer as one + // operation and read it as two, or vice versa. Also, buffers cannot + // overlap.) The offset is relative to the current mapped file + // window. + void copy(void *dst, size_t offset, size_t inSize) + { + ubyte source[] = getRelSlice(offset, inSize); + + // Just copy it for now + ubyte* dest = cast(ubyte*)dst; + dest[0..source.length] = source[]; + } +} diff --git a/terrain/cachewriter.d b/terrain/cachewriter.d new file mode 100644 index 000000000..ee9f72077 --- /dev/null +++ b/terrain/cachewriter.d @@ -0,0 +1,331 @@ +/* + OpenMW - The completely unofficial reimplementation of Morrowind + Copyright (C) 2009 Nicolay Korslund + WWW: http://openmw.sourceforge.net/ + + This file (cachewriter.d) 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/ . + +*/ + +import terrain.archive; + +import terrain.outbuffer; +import std.stream; +import monster.util.string; + +// Helper structs +struct AlphaHolder +{ + AlphaInfo info; + + // Actual pixel buffer + ubyte[] buffer; +} + +struct MeshHolder +{ + MeshInfo info; + + // Actual buffers + byte[] vertexBuffer; + + // Texture name + char[] texName; + + // Alpha maps (if any) + AlphaHolder alphas[]; +} + +// A struct that gathers all the relevant quad data in one place. +struct QuadHolder +{ + QuadInfo info; + + MeshHolder meshes[]; +} + +struct CacheWriter +{ + // Opens the main archive file for output + void openFile(char[] fname) + { + mainFile = new File(fname, FileMode.OutNew); + iname = fname ~ ".index"; + + buf = new OutBuffer; + } + + void setParams(int mxLev, int alphSize) + { + maxLevel = mxLev; + alphaSize = alphSize; + + vertBuf.length = maxLevel; + indexBuf.length = maxLevel; + } + + // Closes the main archive file and writes the index. + void finish() + { + mainFile.close(); + + // Write the index file + scope File ofile = new File(iname, FileMode.OutNew); + + // Header first + ArchiveHeader head; + head.magic = CACHE_MAGIC; + head.quads = quadList.length; + head.rootLevel = maxLevel; + head.alphaSize = alphaSize; + head.stringNum = stringList.length; + head.stringSize = totalStringLength; + ofile.writeExact(&head, head.sizeof); + + // Write the quads + foreach(qi; quadList) + ofile.writeExact(&qi, qi.sizeof); + + // String table next. We need to sort it in order of the indices + // first. + char[][] strVector; + strVector.length = head.stringNum; + + foreach(char[] key, int value; stringList) + strVector[value] = key; + + // Next, write the strings to file while we fill in the offset + // list + int[] offsets = new int[head.stringNum]; + + size_t curOffs = 0; + for(int i=0; i level); + vertBuf[level] = buf; + } + + // Add a common vertex buffer for a given level + void addIndexBuffer(int level, void[] buf) + { + assert(indexBuf.length > level); + indexBuf[level] = buf; + } + + // Write a finished quad to the archive file. All the offsets and + // numbers in the *Info structs are filled in automatically based on + // the additional data in the Holder structs. + void writeQuad(ref QuadHolder qh) + { + // Make outbuffer a simple struct that uses a region and keeps + // track of all the slices we allocate. + OutBuffer buf; + + // Write the MeshInfo's first + int meshNum = qh.meshes.length; + + MeshInfo meshes[] = buf.write!(MeshInfo)(meshNum); + + // Then write the mesh data in approximately the order it's read + for(int i=0; i alphas; -}; - -// A struct that gathers all the relevant quad data in one place. -struct QuadHolder -{ - QuadInfo info; - - std::vector meshes; -}; - -class CacheWriter -{ -public: - // Opens the main archive file for output - void openFile(const std::string &fname) - { - mainFile.open(fname.c_str(), std::ios::binary); - iname = fname + ".index"; - fileOffset = 0; - totalStringLength = 0; - } - - void setParams(int mxLev, int alphSize) - { - maxLevel = mxLev; - alphaSize = alphSize; - - vertBufData.resize(maxLevel); - indexBufData.resize(maxLevel); - vertBufSize.resize(maxLevel); - indexBufSize.resize(maxLevel); - } - - // Closes the main archive file and writes the index. - void finish() - { - mainFile.close(); - - // Write the index file - std::ofstream ofile(iname.c_str(), std::ios::binary); - - // Header first - ArchiveHeader head; - head.magic = CACHE_MAGIC; - head.quads = quadList.size(); - head.rootLevel = maxLevel; - head.alphaSize = alphaSize; - head.stringNum = stringList.size(); - head.stringSize = totalStringLength; - ofile.write((char*)&head, sizeof(head)); - - // Write the quads - for(QuadList::iterator it = quadList.begin(); - it != quadList.end(); it++) - { - QuadInfo qi = *it; - ofile.write((char*)&qi, sizeof(QuadInfo)); - } - - // String table next. We need to sort it in order of the indices - // first. - std::vector strVector; - strVector.resize(head.stringNum); - - for(StringList::iterator it = stringList.begin(); - it != stringList.end(); it++) - { - strVector[it->second] = it->first; - } - - // Next, write the strings to file while we fill inn the offset - // list - std::vector offsets; - offsets.resize(head.stringNum); - size_t curOffs = 0; - - for(int i=0; i level); - - vertBufData[level] = ptr; - vertBufSize[level] = size; - } - - // Add a common vertex buffer for a given level - void addIndexBuffer(int level, void *ptr, int size) - { - assert(indexBufData.size() > level); - - indexBufData[level] = ptr; - indexBufSize[level] = size; - } - - // Write a finished quad to the archive file. All the offsets and - // numbers in the *Info structs are filled in automatically based on - // the additional data in the Holder structs. - void writeQuad(const QuadHolder &qh) - { - TRACE("writeQuad"); - - // See util/outbuffer.h - OutBuffer buf; - - // Write the MeshInfo's first - int meshNum = qh.meshes.size(); - - MeshInfo *meshes = buf.write(meshNum); - - // Then write the mesh data in approximately the order it's read - for(int i=0; i(alphaNum); - - // Loop through the alpha maps - for(int k=0; ksecond; - - // Nope, insert it - int index = stringList.size(); - stringList[str] = index; - stringLookup[index] = str; - - // Sum up the string lengths + 1 byte for the zero - totalStringLength += str.length() + 1; - - return index; - } - - const std::string &getString(int index) - { - const std::string &res = stringLookup[index]; - assert(stringList[res] == index); - return res; - } - -private: - // Write the given block of memory to 'buf', possibly compressing - // the data. - void writeBuf(OutBuffer &buf, const void *ptr, size_t size) - { - // Reserve the maximum bytes needed. - void *toPtr = buf.reserve(size); - - // Store the data - memcpy(toPtr, ptr, size); - - // Add the actual number of bytes stored - buf.add(size); - } - - std::vector vertBufData; - std::vector indexBufData; - std::vector vertBufSize; - std::vector indexBufSize; - - // Variables that must be set during the gen phase - int maxLevel; - int alphaSize; - - // Contains a unique index for each string - typedef std::map StringList; - StringList stringList; - std::map stringLookup; - size_t totalStringLength; - - // List of all quads - typedef std::list QuadList; - QuadList quadList; - - // Output file - std::ofstream mainFile; - size_t fileOffset; - - // Index file name - std::string iname; -}; diff --git a/terrain/cpp_terrainmesh.cpp b/terrain/cpp_mesh.cpp similarity index 100% rename from terrain/cpp_terrainmesh.cpp rename to terrain/cpp_mesh.cpp diff --git a/terrain/cpp_point2.cpp b/terrain/cpp_point2.cpp deleted file mode 100644 index a113d96e8..000000000 --- a/terrain/cpp_point2.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - Copyright (c) Jacob Essex 2009 - - This file is part of MWLand. - - MWLand 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. - - MWLand 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 MWLand. If not, see . -*/ - -/** -* @brief utility class for holding two values -* -* This is mainly used for querying the position of the quad. -* Each quad has a center position, which we can use as a unique identifier -*/ -template -struct Point2 { - T x, y; //held values. - - inline Point2() {} - inline Point2(T ix, T iy) { - x = ix; - y = iy; - } - inline Point2(const Point2& i) { - x = i.x; - y = i.y; - } - - /** - * @brief comparison operator. Although not used directly, this - * class is used in std::map a lot, which used the < operator - */ - - inline bool operator<(const Point2& rhs) const{ - return ( x < rhs.x || !( rhs.x < x) && y < rhs.y ); - } - - inline Point2 operator + (const Point2& rhs) { - return Point2(x + rhs.x, y + rhs.y); - } -}; diff --git a/terrain/cpp_terrain.cpp b/terrain/cpp_terrain.cpp index a24f4c3e0..a59f88d8c 100644 --- a/terrain/cpp_terrain.cpp +++ b/terrain/cpp_terrain.cpp @@ -67,6 +67,7 @@ std::string g_cacheFile; #define RTRACE(x) //#define RTRACE TRACE +/* // Prerequisites #include #include @@ -94,7 +95,7 @@ BaseLand *g_baseLand; SceneNode *g_rootTerrainNode; #include "cpp_baseland.cpp" -#include "cpp_terrainmesh.cpp" +#include "cpp_mesh.cpp" #include "cpp_quad.cpp" class TerrainFrameListener : public FrameListener @@ -109,6 +110,7 @@ protected: }; extern "C" void d_superman(); +*/ extern "C" void terr_setCacheDir(char *cacheDir) { @@ -119,6 +121,7 @@ extern "C" void terr_setCacheDir(char *cacheDir) // Set up the rendering system extern "C" void terr_setupRendering() { + /* // Add the terrain directory ResourceGroupManager::getSingleton(). addResourceLocation(g_cacheDir, "FileSystem", "General"); @@ -142,8 +145,10 @@ extern "C" void terr_setupRendering() mCamera->setFarClipDistance(32*CELL_WIDTH); //ogre_setFog(0.7, 0.7, 0.7, 200, 32*CELL_WIDTH); d_superman(); + */ } +/* // Generate all cached data. extern "C" void terr_genData() { @@ -170,3 +175,4 @@ extern "C" void terr_genData() mhm.generate(g_cacheFile); } +*/ diff --git a/terrain/generator.d b/terrain/generator.d new file mode 100644 index 000000000..4f62afd27 --- /dev/null +++ b/terrain/generator.d @@ -0,0 +1,68 @@ +/* + OpenMW - The completely unofficial reimplementation of Morrowind + Copyright (C) 2008-2009 Nicolay Korslund + Email: < korslund@gmail.com > + WWW: http://openmw.snaptoad.com/ + + This file (generator.d) 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/ . + + */ + +// This module is responsible for generating the cache files. +module terrain.generator; + +import std.stdio; +import std.file; +import monster.util.string; + +char[] cacheDir = "cache/terrain/"; + +void generate() +{ + makePath(cacheDir); + terr_setCacheDir(cacheDir.ptr); +} + +// Move elsewhere, make part of the general cache system later +void makeDir(char[] pt) +{ + if(exists(pt)) + { + if(!isdir(pt)) + fail(pt ~ " is not a directory"); + } + else + mkdir(pt); +} + +void fail(char[] msg) +{ + throw new Exception(msg); +} + +void makePath(char[] pt) +{ + assert(!pt.begins("/")); + foreach(int i, char c; pt) + if(c == '/') + makeDir(pt[0..i]); + + if(!pt.ends("/")) + makeDir(pt); +} + +extern(C): +void terr_setCacheDir(char *dir); diff --git a/terrain/outbuffer.d b/terrain/outbuffer.d new file mode 100644 index 000000000..885a92fea --- /dev/null +++ b/terrain/outbuffer.d @@ -0,0 +1,92 @@ +/* + OpenMW - The completely unofficial reimplementation of Morrowind + Copyright (C) 2008-2009 Nicolay Korslund + Email: < korslund@gmail.com > + WWW: http://openmw.sourceforge.net/ + + This file (outbuffer.d) 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/ . + */ + +/* + This files provides a simple buffer class used for writing the cache + files. It lets you 'write' data to a growing memory buffer and + allows you to change the written data after the fact (since it's + retained in memory.) When you're done, you can write the entire + buffer to a stream in one operation. + */ + +import util.regions; +import std.stream; + +class OutBuffer +{ + private: + RegionManager reg; + long used; + void[][] buffers; + + public: + this() + { + reg = new RegionManager("Outbuf", 200*1024); + } + + void reset() + { + if(buffers.length) + delete buffers; + + reg.freeAll(); + used = 0; + buffers = null; + } + + // Write everyting to a stream as one buffer + void writeTo(Stream str) + { + foreach(void[] v; buffers) + str.writeExact(v.ptr, v.length); + + reset(); + } + + // Get a pointer to a new block at least 'bytes' large, but don't + // add it to the list. + void[] reserve(size_t bytes) + { return reg.allocate(bytes); } + + // Get a new block which is 'bytes' size large. + void[] add(size_t bytes) + { + void[] p = reserve(bytes); + add(p); + return p; + } + + // Add an existing block to the write list + void add(void[] p) + { + buffers ~= p; + used += p.length; + } + + T[] write(T)(size_t num) + { + return cast(T[])add(num * T.sizeof); + } + + size_t size() { return used; } +} diff --git a/terrain/terrain.d b/terrain/terrain.d index ad4d5126c..159a01f07 100644 --- a/terrain/terrain.d +++ b/terrain/terrain.d @@ -23,49 +23,16 @@ module terrain.terrain; -import std.stdio; -import std.file; -import monster.util.string; - -char[] cacheDir = "cache/terrain/"; +import terrain.generator; void initTerrain(bool doGen) { if(doGen) - terr_genData(); - - terr_setupRendering(); -} - -// Move elsewhere, make part of the general cache system later -void makeDir(char[] pt) -{ - if(exists(pt)) - { - if(!isdir(pt)) - fail(pt ~ " is not a directory"); - } - else - mkdir(pt); -} - -void fail(char[] msg) -{ - throw new Exception(msg); -} - -void makePath(char[] pt) -{ - assert(!pt.begins("/")); - foreach(int i, char c; pt) - if(c == '/') - makeDir(pt[0..i]); + generate(); - if(!pt.ends("/")) - makeDir(pt); + //terr_setupRendering(); } extern(C): -void terr_setCacheDir(char *dir); void terr_genData(); void terr_setupRendering(); diff --git a/util/c_mmfile.d b/util/c_mmfile.d deleted file mode 100644 index 2c69bca05..000000000 --- a/util/c_mmfile.d +++ /dev/null @@ -1,69 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2009 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ - - This file (c_mmfile.d) 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/ . - - */ - -/* - This file provides a simple interface to memory mapped files - through C functions. Since D's MmFile is superior in terms of - usability and platform independence, we use it even for C++ code. -*/ - -module util.c_mmfile; - -import std.mmfile; -import std.string; - -version(Windows) - static int pageSize = 64*1024; -else - static int pageSize = 4*1024; - -// List of all MMFs in existence, to keep the GC from killing them -int[MmFile] mf_list; - -extern(C): - -// Open a new memory mapped file -MmFile mmf_open(char *fileName) -{ - auto mmf = new MmFile(toString(fileName), - MmFile.Mode.Read, - 0, null, pageSize); - mf_list[mmf] = 1; - return mmf; -} - -// Close a file. Do not use the handle after calling this function, as -// the object gets deleted -void mmf_close(MmFile mmf) -{ - mf_list.remove(mmf); - delete mmf; -} - -// Map a region of the file. Do NOT attempt to access several regions -// at once. Map will almost always unmap the current mapping (thus -// making all current pointers invalid) when a new map is requested. -void* mmf_map(MmFile mmf, ulong offset, ulong size) -{ - return mmf[offset..offset+size].ptr; -} diff --git a/util/mmfile.h b/util/mmfile.h deleted file mode 100644 index 88b631b2f..000000000 --- a/util/mmfile.h +++ /dev/null @@ -1,44 +0,0 @@ - -typedef void* D_MmFile; - -// These functions are implemented in util/c_mmfile.d -extern "C" -{ - // Open a new memory mapped file - D_MmFile mmf_open(const char *fileName); - - // Close a file. Do not use the handle after calling this function, - // as the object gets deleted - void mmf_close(D_MmFile mmf); - - // Map a region of the file. Do NOT attempt to access several - // regions at once. Map will almost always unmap the current mapping - // (thus making all current pointers invalid) when a new map is - // requested. - void* mmf_map(D_MmFile mmf, int64_t offset, int64_t size); -} - -// This struct allows you to open, read and close a memory mapped -// file. It uses the D MmFile class to achieve platform independence -// and an abstract interface. -struct MmFile -{ - MmFile(const std::string &file) - { - mmf = mmf_open(file.c_str()); - } - - ~MmFile() - { - mmf_close(mmf); - } - - void *map(int64_t offset, int64_t size) - { - return mmf_map(mmf, offset, size); - } - - private: - - D_MmFile mmf; -}; diff --git a/util/outbuffer.h b/util/outbuffer.h deleted file mode 100644 index a25659ea7..000000000 --- a/util/outbuffer.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2009 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ - - This file (outbuffer.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/ . - */ - -/* - This files provides a simple buffer class used for writing the cache - files. It lets you 'write' data to a growing memory buffer and - allows you to change the written data after the fact (since it's - retained in memory.) When you're done, you can write the entire - buffer to a stream in one operation. - */ - -// This is sort of like a mini-version of the Region class in -// D. FIXME: And it doesn't need to be. Rewrite this to add buffers of -// the exact size requested instead of filling a buffer of predefined -// size. -class OutBuffer -{ - public: - OutBuffer() : used(0), left(0), buffers(), sizes() - {} - - ~OutBuffer() - { - deallocate(); - } - - // Write everyting to a stream as one buffer - void writeTo(std::ostream &str) - { - for(int i=0;i= bytes) - return curPtr; - - // Not enough space left. Allocate a new buffer. - curPtr = (char*)malloc(bufSize); - left = bufSize; - - // Store the new buffer in the lists - buffers.push_back(curPtr); - sizes.push_back(0); - - return curPtr; - } - - // Get a new block which is 'bytes' size large. The block will be - // marked as 'used'. - void *add(size_t bytes) - { - void *res = reserve(bytes); - - if(bytes == 0) - return res; - - assert(left >= bytes); - curPtr += bytes; - left -= bytes; - - // We keep a count of the total number of bytes used - used += bytes; - - // Keep a count for each buffer as well - sizes[sizes.size()-1] += bytes; - - return res; - } - - template - T* write(size_t num) - { - return (T*)add(num*sizeof(T)); - } - - void deallocate() - { - for(int i=0;i buffers; - std::vector sizes; - size_t used, left; - char *curPtr; - - static const size_t bufSize = 200*1024; -}; - -std::ostream& operator<<(std::ostream& os, OutBuffer& buf) -{ - buf.writeTo(os); - return os; -} - diff --git a/util/regions.d b/util/regions.d index b644dc76d..b975e499c 100644 --- a/util/regions.d +++ b/util/regions.d @@ -72,7 +72,7 @@ class RegionBuffer(T) // Check if the buffer can hold 'size' more elements. If not, // increase it. NOTE: This works even if data = null, and inUse // is not. This allows us to make copy-on-resize slices. - private void alloc(uint size) + private void alloc(ulong size) { if(inUse.length + size <= buffer.length) { @@ -137,9 +137,9 @@ class RegionBuffer(T) return b; } - uint length() { return inUse.length; } + ulong length() { return inUse.length; } - void length(uint size) + void length(ulong size) { // Grow array if(size > inUse.length) alloc(size - inUse.length); @@ -169,15 +169,15 @@ class RegionManager char[] name; // Use a default buffer size of one meg. Might change later. - const uint defaultBufferSize = 1024*1024; + const ulong defaultBufferSize = 1024*1024; // The size to use for new buffers. - uint bufferSize; + ulong bufferSize; // Current amount of space that is 'lost' in unused end-of-buffer // areas. Since we have proceeded to other buffers, this space will // remain unused until freeAll is called. - uint lost; + ulong lost; ubyte[][] buffers; // Actual memory buffers void *gcRanges[]; // List of ranges added to gc @@ -222,7 +222,7 @@ class RegionManager public: - this(char[] name = "", uint bufferSize = defaultBufferSize) + this(char[] name = "", ulong bufferSize = defaultBufferSize) { this.name = name; this.bufferSize = bufferSize; @@ -249,8 +249,10 @@ class RegionManager delete gcRanges; } + ulong getBufferSize() { return bufferSize; } + // Allocates an array from the region. - ubyte[] allocate(uint size) + ubyte[] allocate(ulong size) { if(size > bufferSize) fail(format("Tried to allocate %d, but maximum allowed allocation size is %d", @@ -271,7 +273,7 @@ class RegionManager // Allocate an array and add it to the GC as a root region. This // should be used for classes and other data that might contain // pointers / class references to GC-managed data. - ubyte[] allocateGC(uint size) + ubyte[] allocateGC(ulong size) { if(currentRange >= gcRanges.length) fail("No more available GC ranges"); @@ -290,7 +292,7 @@ class RegionManager // int[] array = allocateT!(int)(4); template allocateT(T) { - T[] allocateT(uint number) + T[] allocateT(ulong number) { return cast(T[])allocate(number * T.sizeof); } @@ -309,7 +311,7 @@ class RegionManager template allocateGCT(T) { - T[] allocateGCT(uint number) + T[] allocateGCT(ulong number) { return cast(T[])allocateGC(number * T.sizeof); } @@ -359,12 +361,12 @@ class RegionManager } // Number of used buffers, including the current one - uint usedBuffers() { return currentBuffer; } + ulong usedBuffers() { return currentBuffer; } // Total number of allocated buffers - uint totalBuffers() + ulong totalBuffers() { - uint i; + ulong i; // Count number of allocated buffers while(i < buffers.length && buffers[i].length) i++; @@ -373,7 +375,7 @@ class RegionManager } // Total number of allocated bytes - uint poolSize() + ulong poolSize() { return bufferSize * totalBuffers(); } @@ -381,25 +383,25 @@ class RegionManager // Total number of bytes that are unavailable for use. (They might // not be used, as such, if they are at the end of a buffer but the // next buffer is in use.) - uint usedSize() + ulong usedSize() { return currentBuffer*bufferSize - left.length; } // The total size of data that the user has requested. - uint dataSize() + ulong dataSize() { return usedSize() - lostSize(); } // Number of lost bytes - uint lostSize() + ulong lostSize() { return lost; } // Total amount of allocated space that is not used - uint wastedSize() + ulong wastedSize() { return poolSize() - dataSize(); }