From e6305d29a53c9a0c5e607629d30fec70e01cccab Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 7 Mar 2014 18:37:18 +0100 Subject: Added the first skeleton code for PieceGenerator. This is a WIP and won't work / isn't used at all. --- src/Generating/PieceGenerator.cpp | 332 ++++++++++++++++++++++++++++++++++++++ src/Generating/PieceGenerator.h | 213 ++++++++++++++++++++++++ 2 files changed, 545 insertions(+) create mode 100644 src/Generating/PieceGenerator.cpp create mode 100644 src/Generating/PieceGenerator.h diff --git a/src/Generating/PieceGenerator.cpp b/src/Generating/PieceGenerator.cpp new file mode 100644 index 000000000..04513666d --- /dev/null +++ b/src/Generating/PieceGenerator.cpp @@ -0,0 +1,332 @@ + +// PieceGenerator.cpp + +// Implements the cBFSPieceGenerator class and cDFSPieceGenerator class +// representing base classes for generating structures composed of individual "pieces" + +#include "Globals.h" +#include "PieceGenerator.h" + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cPiece: + +cPiece::cConnector cPiece::RotateMoveConnector(const cConnector & a_Connector, int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const +{ + cPiece::cConnector res(a_Connector); + + // Rotate the res connector: + Vector3i Size = GetSize(); + switch (a_NumCCWRotations) + { + case 0: + { + // No rotation needed + break; + } + case 1: + { + // 1 CCW rotation: + int NewX = Size.z - res.m_X; + int NewZ = res.m_Z; + res.m_X = NewX; + res.m_Z = NewZ; + res.m_Direction = RotateBlockFaceCCW(res.m_Direction); + break; + } + case 2: + { + // 2 rotations ( = axis flip): + res.m_X = Size.x - res.m_X; + res.m_Z = Size.z - res.m_Z; + res.m_Direction = MirrorBlockFaceY(res.m_Direction); + break; + } + case 3: + { + // 1 CW rotation: + int NewX = res.m_Z; + int NewZ = Size.x - res.m_X; + res.m_X = NewX; + res.m_Z = NewZ; + res.m_Direction = RotateBlockFaceCW(res.m_Direction); + break; + } + } + + // Move the res connector: + res.m_X += a_MoveX; + res.m_Y += a_MoveY; + res.m_Z += a_MoveZ; + + return res; +} + + + + + +cCuboid cPiece::RotateHitBoxToConnector( + const cPiece::cConnector & a_MyConnector, + const cPiece::cConnector & a_ToConnector, + int a_NumCCWRotations +) const +{ + cCuboid res = GetHitBox(); + switch (a_NumCCWRotations) + { + case 0: + { + // No rotation, return the hitbox as-is + break; + } + case 1: + { + // 1 CCW rotation: + // TODO: res.p1.x = + break; + } + } + return res; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cPlacedPiece: + +cPlacedPiece::cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece, const Vector3i & a_Coords, int a_NumCCWRotations) : + m_Parent(a_Parent), + m_Piece(&a_Piece), + m_Coords(a_Coords), + m_NumCCWRotations(a_NumCCWRotations) +{ + m_Depth = (m_Parent == NULL) ? 0 : (m_Parent->GetDepth() + 1); +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cPieceGenerator: + +cPieceGenerator::cPieceGenerator(cPiecePool & a_PiecePool, int a_Seed) : + m_PiecePool(a_PiecePool), + m_Noise(a_Seed), + m_Seed(a_Seed) +{ +} + + + + + +cPlacedPiece cPieceGenerator::PlaceStartingPiece(int a_BlockX, int a_BlockY, int a_BlockZ, cFreeConnectors & a_OutConnectors) +{ + m_PiecePool.Reset(); + int rnd = m_Noise.IntNoise3DInt(a_BlockX, a_BlockY, a_BlockZ) / 7; + + // Choose a random one of the starting pieces: + cPieces StartingPieces = m_PiecePool.GetStartingPieces(); + cPiece * StartingPiece = StartingPieces[rnd % StartingPieces.size()]; + rnd = rnd >> 16; + + // Choose a random supported rotation: + int Rotations[4] = {0}; + int NumRotations = 1; + for (int i = 1; i < ARRAYCOUNT(Rotations); i++) + { + if (StartingPiece->CanRotateCCW(i)) + { + Rotations[NumRotations] = i; + NumRotations += 1; + } + } + int Rotation = Rotations[rnd % NumRotations]; + + cPlacedPiece res(NULL, *StartingPiece, Vector3i(a_BlockX, a_BlockY, a_BlockZ), Rotation); + + // Place the piece's connectors into a_OutConnectors: + const cPiece::cConnectors & Conn = StartingPiece->GetConnectors(); + for (cPiece::cConnectors::const_iterator itr = Conn.begin(), end = Conn.end(); itr != end; ++itr) + { + a_OutConnectors.push_back( + cFreeConnector(res, StartingPiece->RotateMoveConnector(*itr, Rotation, a_BlockX, a_BlockY, a_BlockZ)) + ); + } + + return res; +} + + + + + +bool cPieceGenerator::TryPlacePieceAtConnector(const cPlacedPiece & a_ParentPiece, const cPiece::cConnector & a_Connector, cPlacedPieces & a_OutPieces) +{ + // Translation of direction - direction -> number of CCW rotations needed: + // You need DirectionRotationTable[rot1][rot2] CCW turns to get from rot1 to rot2 + static const int DirectionRotationTable[6][6] = + { + /* YM, YP, ZM, ZP, XM, XP + /* YM */ { 0, 0, 0, 0, 0, 0}, + /* YP */ { 0, 0, 0, 0, 0, 0}, + /* ZM */ { 0, 0, 0, 2, 1, 3}, + /* ZP */ { 0, 0, 2, 0, 3, 1}, + /* XM */ { 0, 0, 3, 1, 0, 2}, + /* XP */ { 0, 0, 1, 3, 2, 0}, + }; + + // Get a list of available connections: + const int * RotTable = DirectionRotationTable[a_Connector.m_Direction]; + cConnections Connections; + cPieces AvailablePieces = m_PiecePool.GetPiecesWithConnector(a_Connector.m_Type); + Connections.reserve(AvailablePieces.size()); + for (cPieces::iterator itrP = AvailablePieces.begin(), endP = AvailablePieces.end(); itrP != endP; ++itrP) + { + cPiece::cConnectors Connectors = (*itrP)->GetConnectors(); + for (cPiece::cConnectors::iterator itrC = Connectors.begin(), endC = Connectors.end(); itrC != endC; ++itrC) + { + if (itrC->m_Type != a_Connector.m_Type) + { + continue; + } + // This is a same-type connector, find out how to rotate to it: + int NumCCWRotations = RotTable[itrC->m_Direction]; + if (!(*itrP)->CanRotateCCW(NumCCWRotations)) + { + // Doesn't support this rotation + continue; + } + if (!CheckConnection(a_Connector, **itrP, *itrC, NumCCWRotations, a_OutPieces)) + { + // Doesn't fit in this rotation + continue; + } + Connections.push_back(cConnection(**itrP, *itrC, NumCCWRotations)); + } // for itrC - Connectors[] + } // for itrP - AvailablePieces[] + if (Connections.empty()) + { + // No available connections, bail out + return false; + } + + // Choose a random connection from the list: + int rnd = m_Noise.IntNoise3DInt(a_Connector.m_X, a_Connector.m_Y, a_Connector.m_Z) / 7; + cConnection & Conn = Connections[rnd % Connections.size()]; + + // Place the piece: + cPiece::cConnector NewConnector = Conn.m_Piece->RotateMoveConnector(*(Conn.m_Connector), Conn.m_NumCCWRotations, 0, 0, 0); + Vector3i Coords = a_ParentPiece.GetCoords(); + Coords.x -= NewConnector.m_X; + Coords.y -= NewConnector.m_Y; + Coords.z -= NewConnector.m_Z; + a_OutPieces.push_back(cPlacedPiece(&a_ParentPiece, *(Conn.m_Piece), Coords, Conn.m_NumCCWRotations)); + return false; +} + + + + + +bool cPieceGenerator::CheckConnection( + const cPiece::cConnector & a_ExistingConnector, + const cPiece & a_Piece, + const cPiece::cConnector & a_NewConnector, + int a_NumCCWRotations, + const cPlacedPieces & a_OutPieces +) +{ + // For each placed piece, test the hitbox against the new piece: + cCuboid RotatedHitBox = a_Piece.RotateHitBoxToConnector(a_NewConnector, a_ExistingConnector, a_NumCCWRotations); + for (cPlacedPieces::const_iterator itr = a_OutPieces.begin(), end = a_OutPieces.end(); itr != end; ++itr) + { + if (itr->GetHitBox().DoesIntersect(RotatedHitBox)) + { + return false; + } + } + return true; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cPieceGenerator::cConnection: + +cPieceGenerator::cConnection::cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations) : + m_Piece(&a_Piece), + m_Connector(&a_Connector), + m_NumCCWRotations(a_NumCCWRotations) +{ +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cPieceGenerator::cFreeConnector: + +cPieceGenerator::cFreeConnector::cFreeConnector(cPlacedPiece & a_Piece, const cPiece::cConnector & a_Connector) : + m_Piece(&a_Piece), + m_Connector(a_Connector) +{ +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cBFSPieceGenerator: + +cBFSPieceGenerator::cBFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed) : + super(a_PiecePool, a_Seed) +{ +} + + + + + +void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, cPlacedPieces & a_OutPieces) +{ + a_OutPieces.clear(); + cFreeConnectors ConnectorPool; + + // Place the starting piece: + a_OutPieces.push_back(PlaceStartingPiece(a_BlockX, a_BlockY, a_BlockZ, ConnectorPool)); + + // Place pieces at the available connectors: + /* + Instead of removing them one by one from the pool, we process them sequentially and take note of the last + processed one. To save on memory, once the number of processed connectors reaches a big number, a chunk + of the connectors is removed. + */ + size_t NumProcessed = 0; + while (ConnectorPool.size() > NumProcessed) + { + cFreeConnector & Conn = ConnectorPool[NumProcessed]; + TryPlacePieceAtConnector(*Conn.m_Piece, Conn.m_Connector, a_OutPieces); + NumProcessed++; + if (NumProcessed > 1000) + { + ConnectorPool.erase(ConnectorPool.begin(), ConnectorPool.begin() + NumProcessed); + NumProcessed = 0; + } + } +} + + + + diff --git a/src/Generating/PieceGenerator.h b/src/Generating/PieceGenerator.h new file mode 100644 index 000000000..3bc71a0ab --- /dev/null +++ b/src/Generating/PieceGenerator.h @@ -0,0 +1,213 @@ + +// PieceGenerator.h + +// Declares the cBFSPieceGenerator class and cDFSPieceGenerator class +// representing base classes for generating structures composed of individual "pieces" + +/* +Each uses a slightly different approach to generating: + - DFS extends pieces one by one until it hits the configured depth (or can't connect another piece anymore), + then starts looking at adjacent connectors (like depth-first search). + - BFS keeps a pool of currently-open connectors, chooses one at random and tries to place a piece on it, + thus possibly extending the pool of open connectors (like breadth-first search). +*/ + + + + + +#pragma once + +#include "../Defines.h" +#include "../Cuboid.h" +#include "../Noise.h" + + + + + +/** Represents a single piece. Can have multiple connectors of different types where other pieces can connect. */ +class cPiece +{ +public: + struct cConnector + { + int m_X; + int m_Y; + int m_Z; + int m_Type; + eBlockFace m_Direction; + + cConnector(int a_X, int a_Y, int a_Z, int a_Type, eBlockFace m_Direction); + }; + + typedef std::vector cConnectors; + + /** Returns all of the available connectors that the piece has. + Each connector has a (relative) position in the piece, and a type associated with it. */ + virtual cConnectors GetConnectors(void) const = 0; + + /** Returns the dimensions of this piece. + The dimensions cover the entire piece, there is no block that the piece generates outside of this size. */ + virtual Vector3i GetSize(void) const = 0; + + /** Returns the "hitbox" of this piece. + A hitbox is what is compared and must not intersect other pieces' hitboxes when generating. */ + virtual cCuboid GetHitBox(void) const = 0; + + /** Returns true if the piece can be rotated CCW the specific number of 90-degree turns. */ + virtual bool CanRotateCCW(int a_NumRotations) const = 0; + + /** Returns a copy of the connector that is rotated and then moved by the specified amounts. */ + cConnector RotateMoveConnector(const cConnector & a_Connector, int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const; + + /** Returns the hitbox after the specified number of rotations and moved so that a_MyConnector is placed at a_ToConnector*/ + cCuboid RotateHitBoxToConnector(const cConnector & a_MyConnector, const cConnector & a_ToConnector, int a_NumCCWRotations) const; +}; + +typedef std::vector cPieces; + + + + + +class cPiecePool +{ +public: + /** Returns a list of pieces that contain the specified connector type. + The cPiece pointers returned are managed by the pool and the caller doesn't free them. */ + virtual cPieces GetPiecesWithConnector(int a_ConnectorType) = 0; + + /** Returns the pieces that should be used as the starting point. + Multiple starting points are supported, one of the returned piece will be chosen. */ + virtual cPieces GetStartingPieces(void) = 0; + + /** Called after a piece is placed, to notify the pool that it has been used. + The pool may adjust the pieces it will return the next time. */ + virtual void PiecePlaced(const cPiece & a_Piece) = 0; + + /** Called when the pool has finished the current structure and should reset any piece-counters it has + for a new structure. */ + virtual void Reset(void) = 0; +}; + + + + + +/** Represents a single piece that has been placed to specific coords in the world. */ +class cPlacedPiece +{ +public: + cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece, const Vector3i & a_Coords, int a_NumCCWRotations); + + const cPiece & GetPiece (void) const { return *m_Piece; } + const Vector3i & GetCoords (void) const { return m_Coords; } + const int GetNumCCWRotations(void) const { return m_NumCCWRotations; } + const cCuboid & GetHitBox (void) const { return m_HitBox; } + const int GetDepth (void) const { return m_Depth; } + +protected: + const cPlacedPiece * m_Parent; + const cPiece * m_Piece; + Vector3i m_Coords; + int m_NumCCWRotations; + cCuboid m_HitBox; + int m_Depth; +}; + +typedef std::vector cPlacedPieces; + + + + + +class cPieceGenerator +{ +public: + cPieceGenerator(cPiecePool & a_PiecePool, int a_Seed); + +protected: + /** The type used for storing a connection from one piece to another, while building the piece tree. */ + struct cConnection + { + cPiece * m_Piece; // The piece being connected + cPiece::cConnector * m_Connector; // The piece's connector being used + int m_NumCCWRotations; // Number of rotations necessary to match the two connectors + + cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations); + }; + typedef std::vector cConnections; + + /** The type used for storing a pool of connectors that will be attempted to expand by another piece. */ + struct cFreeConnector + { + cPlacedPiece * m_Piece; + cPiece::cConnector m_Connector; + + cFreeConnector(cPlacedPiece & a_Piece, const cPiece::cConnector & a_Connector); + }; + typedef std::vector cFreeConnectors; + + + cPiecePool & m_PiecePool; + cNoise m_Noise; + int m_Seed; + + + /** Selects a starting piece and places it, including the rotations. + Also puts the piece's connectors in a_OutConnectors. */ + cPlacedPiece PlaceStartingPiece(int a_BlockX, int a_BlockY, int a_BlockZ, cFreeConnectors & a_OutConnectors); + + /** Tries to place a new piece at the specified (placed) connector. Returns true if successful. */ + bool TryPlacePieceAtConnector( + const cPlacedPiece & a_ParentPiece, + const cPiece::cConnector & a_Connector, + cPlacedPieces & a_OutPieces + ); + + /** Checks if the specified piece would fit with the already-placed pieces, using the specified connector + and number of CCW rotations. + Returns true if the piece fits, false if not. */ + bool CheckConnection( + const cPiece::cConnector & a_ExistingConnector, // The existing connector + const cPiece & a_Piece, // The new piece + const cPiece::cConnector & a_NewConnector, // The connector of the new piece + int a_NumCCWRotations, // Number of rotations for the new piece to align the connector + const cPlacedPieces & a_OutPieces // All the already-placed pieces to check + ); +} ; + + + + + +class cBFSPieceGenerator : + public cPieceGenerator +{ + typedef cPieceGenerator super; + +public: + cBFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed); + + /** Generates a placement for pieces at the specified coords. */ + void PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, cPlacedPieces & a_OutPieces); +}; + + + + + +class cDFSPieceGenerator : + public cPieceGenerator +{ +public: + cDFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed); + + /** Generates a placement for pieces at the specified coords. */ + void PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, cPlacedPieces & a_OutPieces); +}; + + + + -- cgit v1.2.3 From 93f0de521a0e2abb9c35dfb06bd3d306c548bf1b Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 7 Mar 2014 21:43:15 +0100 Subject: Added Vector3i::Move(). --- src/Vector3i.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++++++----- src/Vector3i.h | 47 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 82 insertions(+), 17 deletions(-) diff --git a/src/Vector3i.cpp b/src/Vector3i.cpp index 4ce1e2cf3..2106aea6d 100644 --- a/src/Vector3i.cpp +++ b/src/Vector3i.cpp @@ -1,6 +1,11 @@ +// Vector3i.cpp + +// Implements the Vector3i class representing an int-based 3D vector + #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules +#include "math.h" #include "Vector3i.h" #include "Vector3d.h" @@ -8,9 +13,46 @@ -Vector3i::Vector3i( const Vector3d & v ) - : x( (int)v.x ) - , y( (int)v.y ) - , z( (int)v.z ) +Vector3i::Vector3i(const Vector3d & v) : + x((int)v.x), + y((int)v.y), + z((int)v.z) +{ +} + + + + + +Vector3i::Vector3i(void) : + x(0), + y(0), + z(0) +{ +} + + + + + +Vector3i::Vector3i(int a_x, int a_y, int a_z) : + x(a_x), + y(a_y), + z(a_z) +{ +} + + + + + +void Vector3i::Move(int a_MoveX, int a_MoveY, int a_MoveZ) { -} \ No newline at end of file + x += a_MoveX; + y += a_MoveY; + z += a_MoveZ; +} + + + + diff --git a/src/Vector3i.h b/src/Vector3i.h index 7d726a7b3..39e138683 100644 --- a/src/Vector3i.h +++ b/src/Vector3i.h @@ -1,22 +1,45 @@ + +// Vector3i.h + +// Declares the Vector3i class representing an int-based 3D vector + + + + + #pragma once -#include + + + +// fwd: class Vector3d; -class Vector3i // tolua_export -{ // tolua_export -public: // tolua_export - Vector3i( const Vector3d & v ); // tolua_export - Vector3i() : x(0), y(0), z(0) {} // tolua_export - Vector3i(int a_x, int a_y, int a_z) : x(a_x), y(a_y), z(a_z) {} // tolua_export - inline void Set(int a_x, int a_y, int a_z) { x = a_x, y = a_y, z = a_z; } // tolua_export - inline float Length() const { return sqrtf( (float)( x * x + y * y + z * z) ); } // tolua_export - inline int SqrLength() const { return x * x + y * y + z * z; } // tolua_export - inline bool Equals( const Vector3i & v ) const { return (x == v.x && y == v.y && z == v.z ); } // tolua_export - inline bool Equals( const Vector3i * v ) const { return (x == v->x && y == v->y && z == v->z ); } // tolua_export + + +// tolua_begin +class Vector3i +{ +public: + /** Creates an int vector based on the floor()-ed coords of a double vector. */ + Vector3i(const Vector3d & v); + + Vector3i(void); + Vector3i(int a_x, int a_y, int a_z); + + inline void Set(int a_x, int a_y, int a_z) { x = a_x, y = a_y, z = a_z; } + inline float Length() const { return sqrtf( (float)( x * x + y * y + z * z) ); } + inline int SqrLength() const { return x * x + y * y + z * z; } + + inline bool Equals( const Vector3i & v ) const { return (x == v.x && y == v.y && z == v.z ); } + inline bool Equals( const Vector3i * v ) const { return (x == v->x && y == v->y && z == v->z ); } + + void Move(int a_MoveX, int a_MoveY, int a_MoveZ); + + // tolua_end void operator += ( const Vector3i& a_V ) { x += a_V.x; y += a_V.y; z += a_V.z; } void operator += ( Vector3i* a_V ) { x += a_V->x; y += a_V->y; z += a_V->z; } -- cgit v1.2.3 From 5be983e7752091adbf7262f3074b3062ea44ae73 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 9 Mar 2014 10:05:30 +0100 Subject: Added BlockFaceToString() translation function. --- src/Defines.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Defines.h b/src/Defines.h index 6ab2274a4..d2fcce576 100644 --- a/src/Defines.h +++ b/src/Defines.h @@ -276,6 +276,26 @@ inline eBlockFace RotateBlockFaceCW(eBlockFace a_BlockFace) +/** Returns the textual representation of the BlockFace constant. */ +inline AString BlockFaceToString(eBlockFace a_BlockFace) +{ + switch (a_BlockFace) + { + case BLOCK_FACE_XM: return "BLOCK_FACE_XM"; + case BLOCK_FACE_XP: return "BLOCK_FACE_XP"; + case BLOCK_FACE_YM: return "BLOCK_FACE_YM"; + case BLOCK_FACE_YP: return "BLOCK_FACE_YP"; + case BLOCK_FACE_ZM: return "BLOCK_FACE_ZM"; + case BLOCK_FACE_ZP: return "BLOCK_FACE_ZP"; + case BLOCK_FACE_NONE: return "BLOCK_FACE_NONE"; + } + return Printf("Unknown BLOCK_FACE: %d", a_BlockFace); +} + + + + + inline bool IsValidBlock(int a_BlockType) { if ( -- cgit v1.2.3 From b9190fc04e1463371cec773d069315a6743a56d5 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 9 Mar 2014 10:11:33 +0100 Subject: PieceGenerator can connect two connectors of the same type. Also added extensive debugging output and a test. --- src/Generating/PieceGenerator.cpp | 347 ++++++++++++++++++++++++++++++++------ src/Generating/PieceGenerator.h | 51 ++++-- 2 files changed, 338 insertions(+), 60 deletions(-) diff --git a/src/Generating/PieceGenerator.cpp b/src/Generating/PieceGenerator.cpp index 04513666d..58ccaf2c2 100644 --- a/src/Generating/PieceGenerator.cpp +++ b/src/Generating/PieceGenerator.cpp @@ -11,9 +11,169 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Self-test: + +static class cPieceGeneratorSelfTest : + public cPiecePool +{ +public: + cPieceGeneratorSelfTest(void) + { + // Prepare the internal state: + InitializePieces(); + + // Generate: + cBFSPieceGenerator Gen(*this, 0); + cPlacedPieces OutPieces; + Gen.PlacePieces(500, 50, 500, 3, OutPieces); + + // Print out the pieces: + printf("OutPieces.size() = %u\n", OutPieces.size()); + size_t idx = 0; + for (cPlacedPieces::const_iterator itr = OutPieces.begin(), end = OutPieces.end(); itr != end; ++itr, ++idx) + { + const Vector3i & Coords = (*itr)->GetCoords(); + cCuboid Hitbox = (*itr)->GetHitBox(); + Hitbox.Sort(); + printf("%u: {%d, %d, %d}, rot %d, hitbox {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n", idx, + Coords.x, Coords.y, Coords.z, + (*itr)->GetNumCCWRotations(), + Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z, + Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z, + Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1 + ); + } // itr - OutPieces[] + printf("Done.\n"); + + // Free the placed pieces properly: + Gen.FreePieces(OutPieces); + } + + ~cPieceGeneratorSelfTest() + { + // Dealloc all the pieces: + for (cPieces::iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr) + { + delete *itr; + } + m_Pieces.clear(); + } + +protected: + class cTestPiece : + public cPiece + { + int m_Size; + public: + cTestPiece(int a_Size) : + m_Size(a_Size) + { + } + + virtual cConnectors GetConnectors(void) const override + { + // Each piece has 4 connectors, one of each type, plus one extra, at the center of its walls: + cConnectors res; + res.push_back(cConnector(m_Size / 2, 1, 0, 0, BLOCK_FACE_ZM)); + res.push_back(cConnector(m_Size / 2, 1, m_Size - 1, 1, BLOCK_FACE_ZP)); + res.push_back(cConnector(0, 1, m_Size / 2, 2, BLOCK_FACE_XM)); + res.push_back(cConnector(m_Size - 1, 1, m_Size / 2, m_Size % 3, BLOCK_FACE_XP)); + return res; + } + + virtual Vector3i GetSize(void) const override + { + return Vector3i(m_Size, 5, m_Size); + } + + virtual cCuboid GetHitBox(void) const override + { + return cCuboid(0, 0, 0, m_Size - 1, 4, m_Size - 1); + } + + virtual bool CanRotateCCW(int a_NumCCWRotations) const override + { + return true; + } + }; + + cPieces m_Pieces; + + virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override + { + // Each piece contains each connector + return m_Pieces; + } + + + virtual cPieces GetStartingPieces(void) override + { + return m_Pieces; + } + + + virtual void PiecePlaced(const cPiece & a_Piece) override + { + UNUSED(a_Piece); + } + + + virtual void Reset(void) override + { + } + + + void InitializePieces(void) + { + m_Pieces.push_back(new cTestPiece(5)); + m_Pieces.push_back(new cTestPiece(7)); + m_Pieces.push_back(new cTestPiece(9)); + } +} g_Test; + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cPiece: + +Vector3i cPiece::RotatePos(const Vector3i & a_Pos, int a_NumCCWRotations) const +{ + Vector3i Size = GetSize(); + switch (a_NumCCWRotations) + { + case 0: + { + // No rotation needed + return a_Pos; + } + case 1: + { + // 1 CCW rotation: + return Vector3i(a_Pos.z, a_Pos.y, Size.x - a_Pos.x - 1); + } + case 2: + { + // 2 rotations ( = axis flip): + return Vector3i(Size.x - a_Pos.x - 1, a_Pos.y, Size.z - a_Pos.z - 1); + } + case 3: + { + // 1 CW rotation: + return Vector3i(Size.z - a_Pos.z - 1, a_Pos.y, a_Pos.x); + } + } + ASSERT(!"Unhandled rotation"); + return a_Pos; +} + + + + + cPiece::cConnector cPiece::RotateMoveConnector(const cConnector & a_Connector, int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const { cPiece::cConnector res(a_Connector); @@ -30,37 +190,28 @@ cPiece::cConnector cPiece::RotateMoveConnector(const cConnector & a_Connector, i case 1: { // 1 CCW rotation: - int NewX = Size.z - res.m_X; - int NewZ = res.m_Z; - res.m_X = NewX; - res.m_Z = NewZ; res.m_Direction = RotateBlockFaceCCW(res.m_Direction); break; } case 2: { // 2 rotations ( = axis flip): - res.m_X = Size.x - res.m_X; - res.m_Z = Size.z - res.m_Z; res.m_Direction = MirrorBlockFaceY(res.m_Direction); break; } case 3: { // 1 CW rotation: - int NewX = res.m_Z; - int NewZ = Size.x - res.m_X; - res.m_X = NewX; - res.m_Z = NewZ; res.m_Direction = RotateBlockFaceCW(res.m_Direction); break; } } + res.m_Pos = RotatePos(a_Connector.m_Pos, a_NumCCWRotations); // Move the res connector: - res.m_X += a_MoveX; - res.m_Y += a_MoveY; - res.m_Z += a_MoveZ; + res.m_Pos.x += a_MoveX; + res.m_Pos.y += a_MoveY; + res.m_Pos.z += a_MoveZ; return res; } @@ -71,25 +222,28 @@ cPiece::cConnector cPiece::RotateMoveConnector(const cConnector & a_Connector, i cCuboid cPiece::RotateHitBoxToConnector( const cPiece::cConnector & a_MyConnector, - const cPiece::cConnector & a_ToConnector, + const Vector3i & a_ToConnectorPos, int a_NumCCWRotations ) const { + ASSERT(a_NumCCWRotations == (a_NumCCWRotations % 4)); + Vector3i ConnPos = RotatePos(a_MyConnector.m_Pos, a_NumCCWRotations); + ConnPos = a_ToConnectorPos - ConnPos; + return RotateMoveHitBox(a_NumCCWRotations, ConnPos.x, ConnPos.y, ConnPos.z); +} + + + + + +cCuboid cPiece::RotateMoveHitBox(int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const +{ + ASSERT(a_NumCCWRotations == (a_NumCCWRotations % 4)); cCuboid res = GetHitBox(); - switch (a_NumCCWRotations) - { - case 0: - { - // No rotation, return the hitbox as-is - break; - } - case 1: - { - // 1 CCW rotation: - // TODO: res.p1.x = - break; - } - } + res.p1 = RotatePos(res.p1, a_NumCCWRotations); + res.p2 = RotatePos(res.p2, a_NumCCWRotations); + res.p1.Move(a_MoveX, a_MoveY, a_MoveZ); + res.p2.Move(a_MoveX, a_MoveY, a_MoveZ); return res; } @@ -97,6 +251,31 @@ cCuboid cPiece::RotateHitBoxToConnector( +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cPiece::cConnector: + +cPiece::cConnector::cConnector(int a_X, int a_Y, int a_Z, int a_Type, eBlockFace a_Direction) : + m_Pos(a_X, a_Y, a_Z), + m_Type(a_Type), + m_Direction(a_Direction) +{ +} + + + + + +cPiece::cConnector::cConnector(const Vector3i & a_Pos, int a_Type, eBlockFace a_Direction) : + m_Pos(a_Pos), + m_Type(a_Type), + m_Direction(a_Direction) +{ +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cPlacedPiece: @@ -107,6 +286,7 @@ cPlacedPiece::cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece m_NumCCWRotations(a_NumCCWRotations) { m_Depth = (m_Parent == NULL) ? 0 : (m_Parent->GetDepth() + 1); + m_HitBox = a_Piece.RotateMoveHitBox(a_NumCCWRotations, a_Coords.x, a_Coords.y, a_Coords.z); } @@ -127,7 +307,20 @@ cPieceGenerator::cPieceGenerator(cPiecePool & a_PiecePool, int a_Seed) : -cPlacedPiece cPieceGenerator::PlaceStartingPiece(int a_BlockX, int a_BlockY, int a_BlockZ, cFreeConnectors & a_OutConnectors) +void cPieceGenerator::FreePieces(cPlacedPieces & a_PlacedPieces) +{ + for (cPlacedPieces::iterator itr = a_PlacedPieces.begin(), end = a_PlacedPieces.end(); itr != end; ++itr) + { + delete *itr; + } // for itr - a_PlacedPieces[] + a_PlacedPieces.clear(); +} + + + + + +cPlacedPiece * cPieceGenerator::PlaceStartingPiece(int a_BlockX, int a_BlockY, int a_BlockZ, cFreeConnectors & a_OutConnectors) { m_PiecePool.Reset(); int rnd = m_Noise.IntNoise3DInt(a_BlockX, a_BlockY, a_BlockZ) / 7; @@ -150,7 +343,7 @@ cPlacedPiece cPieceGenerator::PlaceStartingPiece(int a_BlockX, int a_BlockY, int } int Rotation = Rotations[rnd % NumRotations]; - cPlacedPiece res(NULL, *StartingPiece, Vector3i(a_BlockX, a_BlockY, a_BlockZ), Rotation); + cPlacedPiece * res = new cPlacedPiece(NULL, *StartingPiece, Vector3i(a_BlockX, a_BlockY, a_BlockZ), Rotation); // Place the piece's connectors into a_OutConnectors: const cPiece::cConnectors & Conn = StartingPiece->GetConnectors(); @@ -171,7 +364,7 @@ cPlacedPiece cPieceGenerator::PlaceStartingPiece(int a_BlockX, int a_BlockY, int bool cPieceGenerator::TryPlacePieceAtConnector(const cPlacedPiece & a_ParentPiece, const cPiece::cConnector & a_Connector, cPlacedPieces & a_OutPieces) { // Translation of direction - direction -> number of CCW rotations needed: - // You need DirectionRotationTable[rot1][rot2] CCW turns to get from rot1 to rot2 + // You need DirectionRotationTable[rot1][rot2] CCW turns to connect rot1 to rot2 (they are opposite) static const int DirectionRotationTable[6][6] = { /* YM, YP, ZM, ZP, XM, XP @@ -188,6 +381,12 @@ bool cPieceGenerator::TryPlacePieceAtConnector(const cPlacedPiece & a_ParentPiec cConnections Connections; cPieces AvailablePieces = m_PiecePool.GetPiecesWithConnector(a_Connector.m_Type); Connections.reserve(AvailablePieces.size()); + Vector3i ConnPos = a_Connector.m_Pos; // The position at which the new connector should be placed - 1 block away from the connector + AddFaceDirection(ConnPos.x, ConnPos.y, ConnPos.z, a_Connector.m_Direction); + + // DEBUG: + printf("Placing piece at pos {%d, %d, %d}, direction %s\n", ConnPos.x, ConnPos.y, ConnPos.z, BlockFaceToString(a_Connector.m_Direction).c_str()); + for (cPieces::iterator itrP = AvailablePieces.begin(), endP = AvailablePieces.end(); itrP != endP; ++itrP) { cPiece::cConnectors Connectors = (*itrP)->GetConnectors(); @@ -204,7 +403,7 @@ bool cPieceGenerator::TryPlacePieceAtConnector(const cPlacedPiece & a_ParentPiec // Doesn't support this rotation continue; } - if (!CheckConnection(a_Connector, **itrP, *itrC, NumCCWRotations, a_OutPieces)) + if (!CheckConnection(a_Connector, ConnPos, **itrP, *itrC, NumCCWRotations, a_OutPieces)) { // Doesn't fit in this rotation continue; @@ -219,17 +418,23 @@ bool cPieceGenerator::TryPlacePieceAtConnector(const cPlacedPiece & a_ParentPiec } // Choose a random connection from the list: - int rnd = m_Noise.IntNoise3DInt(a_Connector.m_X, a_Connector.m_Y, a_Connector.m_Z) / 7; + int rnd = m_Noise.IntNoise3DInt(a_Connector.m_Pos.x, a_Connector.m_Pos.y, a_Connector.m_Pos.z) / 7; cConnection & Conn = Connections[rnd % Connections.size()]; // Place the piece: - cPiece::cConnector NewConnector = Conn.m_Piece->RotateMoveConnector(*(Conn.m_Connector), Conn.m_NumCCWRotations, 0, 0, 0); - Vector3i Coords = a_ParentPiece.GetCoords(); - Coords.x -= NewConnector.m_X; - Coords.y -= NewConnector.m_Y; - Coords.z -= NewConnector.m_Z; - a_OutPieces.push_back(cPlacedPiece(&a_ParentPiece, *(Conn.m_Piece), Coords, Conn.m_NumCCWRotations)); - return false; + printf("Chosen connector at {%d, %d, %d}, direction %s, needs %d rotations\n", + Conn.m_Connector.m_Pos.x, Conn.m_Connector.m_Pos.y, Conn.m_Connector.m_Pos.z, + BlockFaceToString(Conn.m_Connector.m_Direction).c_str(), + Conn.m_NumCCWRotations + ); + Vector3i NewPos = Conn.m_Piece->RotatePos(Conn.m_Connector.m_Pos, Conn.m_NumCCWRotations); + ConnPos -= NewPos; + a_OutPieces.push_back(new cPlacedPiece(&a_ParentPiece, *(Conn.m_Piece), ConnPos, Conn.m_NumCCWRotations)); + + // Add the new piece's connectors to the list of free connectors: + // TODO + + return true; } @@ -238,6 +443,7 @@ bool cPieceGenerator::TryPlacePieceAtConnector(const cPlacedPiece & a_ParentPiec bool cPieceGenerator::CheckConnection( const cPiece::cConnector & a_ExistingConnector, + const Vector3i & a_ToPos, const cPiece & a_Piece, const cPiece::cConnector & a_NewConnector, int a_NumCCWRotations, @@ -245,10 +451,10 @@ bool cPieceGenerator::CheckConnection( ) { // For each placed piece, test the hitbox against the new piece: - cCuboid RotatedHitBox = a_Piece.RotateHitBoxToConnector(a_NewConnector, a_ExistingConnector, a_NumCCWRotations); + cCuboid RotatedHitBox = a_Piece.RotateHitBoxToConnector(a_NewConnector, a_ToPos, a_NumCCWRotations); for (cPlacedPieces::const_iterator itr = a_OutPieces.begin(), end = a_OutPieces.end(); itr != end; ++itr) { - if (itr->GetHitBox().DoesIntersect(RotatedHitBox)) + if ((*itr)->GetHitBox().DoesIntersect(RotatedHitBox)) { return false; } @@ -260,12 +466,32 @@ bool cPieceGenerator::CheckConnection( +// DEBUG: +void cPieceGenerator::DebugConnectorPool(const cPieceGenerator::cFreeConnectors & a_ConnectorPool, size_t a_NumProcessed) +{ + printf(" Connector pool: %u items\n", a_ConnectorPool.size() - a_NumProcessed); + size_t idx = 0; + for (cPieceGenerator::cFreeConnectors::const_iterator itr = a_ConnectorPool.begin() + a_NumProcessed, end = a_ConnectorPool.end(); itr != end; ++itr, ++idx) + { + printf(" %u: {%d, %d, %d}, type %d, direction %s\n", + idx, + itr->m_Connector.m_Pos.x, itr->m_Connector.m_Pos.y, itr->m_Connector.m_Pos.z, + itr->m_Connector.m_Type, + BlockFaceToString(itr->m_Connector.m_Direction).c_str() + ); + } // for itr - a_ConnectorPool[] +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cPieceGenerator::cConnection: cPieceGenerator::cConnection::cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations) : m_Piece(&a_Piece), - m_Connector(&a_Connector), + m_Connector(a_Connector), m_NumCCWRotations(a_NumCCWRotations) { } @@ -277,8 +503,8 @@ cPieceGenerator::cConnection::cConnection(cPiece & a_Piece, cPiece::cConnector & /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cPieceGenerator::cFreeConnector: -cPieceGenerator::cFreeConnector::cFreeConnector(cPlacedPiece & a_Piece, const cPiece::cConnector & a_Connector) : - m_Piece(&a_Piece), +cPieceGenerator::cFreeConnector::cFreeConnector(cPlacedPiece * a_Piece, const cPiece::cConnector & a_Connector) : + m_Piece(a_Piece), m_Connector(a_Connector) { } @@ -299,7 +525,7 @@ cBFSPieceGenerator::cBFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed) : -void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, cPlacedPieces & a_OutPieces) +void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MaxDepth, cPlacedPieces & a_OutPieces) { a_OutPieces.clear(); cFreeConnectors ConnectorPool; @@ -307,6 +533,17 @@ void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, c // Place the starting piece: a_OutPieces.push_back(PlaceStartingPiece(a_BlockX, a_BlockY, a_BlockZ, ConnectorPool)); + // DEBUG: + printf("Placed the starting piece at {%d, %d, %d}\n", a_BlockX, a_BlockY, a_BlockZ); + cCuboid Hitbox = a_OutPieces[0]->GetHitBox(); + Hitbox.Sort(); + printf(" Hitbox: {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n", + Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z, + Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z, + Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1 + ); + DebugConnectorPool(ConnectorPool, 0); + // Place pieces at the available connectors: /* Instead of removing them one by one from the pool, we process them sequentially and take note of the last @@ -317,7 +554,23 @@ void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, c while (ConnectorPool.size() > NumProcessed) { cFreeConnector & Conn = ConnectorPool[NumProcessed]; - TryPlacePieceAtConnector(*Conn.m_Piece, Conn.m_Connector, a_OutPieces); + if (Conn.m_Piece->GetDepth() < a_MaxDepth) + { + if (TryPlacePieceAtConnector(*Conn.m_Piece, Conn.m_Connector, a_OutPieces)) + { + const cPlacedPiece * NewPiece = a_OutPieces.back(); + const Vector3i & Coords = NewPiece->GetCoords(); + printf("Placed a new piece at {%d, %d, %d}, rotation %d\n", Coords.x, Coords.y, Coords.z, NewPiece->GetNumCCWRotations()); + cCuboid Hitbox = NewPiece->GetHitBox(); + Hitbox.Sort(); + printf(" Hitbox: {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n", + Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z, + Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z, + Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1 + ); + DebugConnectorPool(ConnectorPool, NumProcessed + 1); + } + } NumProcessed++; if (NumProcessed > 1000) { diff --git a/src/Generating/PieceGenerator.h b/src/Generating/PieceGenerator.h index 3bc71a0ab..0e24510ae 100644 --- a/src/Generating/PieceGenerator.h +++ b/src/Generating/PieceGenerator.h @@ -32,13 +32,18 @@ class cPiece public: struct cConnector { - int m_X; - int m_Y; - int m_Z; + /** Position relative to the piece */ + Vector3i m_Pos; + + /** Type of the connector. Any arbitrary number; the generator connects only connectors of the same type. */ int m_Type; + + /** Direction in which the connector is facing. + Will be matched by the opposite direction for the connecting connector. */ eBlockFace m_Direction; - cConnector(int a_X, int a_Y, int a_Z, int a_Type, eBlockFace m_Direction); + cConnector(int a_X, int a_Y, int a_Z, int a_Type, eBlockFace a_Direction); + cConnector(const Vector3i & a_Pos, int a_Type, eBlockFace a_Direction); }; typedef std::vector cConnectors; @@ -58,11 +63,17 @@ public: /** Returns true if the piece can be rotated CCW the specific number of 90-degree turns. */ virtual bool CanRotateCCW(int a_NumRotations) const = 0; + /** Returns a copy of the a_Pos after rotating the piece the specified number of CCW rotations. */ + Vector3i RotatePos(const Vector3i & a_Pos, int a_NumCCWRotations) const; + /** Returns a copy of the connector that is rotated and then moved by the specified amounts. */ cConnector RotateMoveConnector(const cConnector & a_Connector, int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const; - /** Returns the hitbox after the specified number of rotations and moved so that a_MyConnector is placed at a_ToConnector*/ - cCuboid RotateHitBoxToConnector(const cConnector & a_MyConnector, const cConnector & a_ToConnector, int a_NumCCWRotations) const; + /** Returns the hitbox after the specified number of rotations and moved so that a_MyConnector is placed at a_ToConnectorPos. */ + cCuboid RotateHitBoxToConnector(const cConnector & a_MyConnector, const Vector3i & a_ToConnectorPos, int a_NumCCWRotations) const; + + /** Returns the hitbox after the specified number of CCW rotations and moved by the specified amounts. */ + cCuboid RotateMoveHitBox(int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const; }; typedef std::vector cPieces; @@ -116,7 +127,7 @@ protected: int m_Depth; }; -typedef std::vector cPlacedPieces; +typedef std::vector cPlacedPieces; @@ -127,12 +138,16 @@ class cPieceGenerator public: cPieceGenerator(cPiecePool & a_PiecePool, int a_Seed); + /** Cleans up all the memory used by the placed pieces. + Call this utility function instead of freeing the items on your own. */ + void FreePieces(cPlacedPieces & a_PlacedPieces); + protected: /** The type used for storing a connection from one piece to another, while building the piece tree. */ struct cConnection { cPiece * m_Piece; // The piece being connected - cPiece::cConnector * m_Connector; // The piece's connector being used + cPiece::cConnector m_Connector; // The piece's connector being used (relative non-rotated coords) int m_NumCCWRotations; // Number of rotations necessary to match the two connectors cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations); @@ -145,7 +160,7 @@ protected: cPlacedPiece * m_Piece; cPiece::cConnector m_Connector; - cFreeConnector(cPlacedPiece & a_Piece, const cPiece::cConnector & a_Connector); + cFreeConnector(cPlacedPiece * a_Piece, const cPiece::cConnector & a_Connector); }; typedef std::vector cFreeConnectors; @@ -157,7 +172,7 @@ protected: /** Selects a starting piece and places it, including the rotations. Also puts the piece's connectors in a_OutConnectors. */ - cPlacedPiece PlaceStartingPiece(int a_BlockX, int a_BlockY, int a_BlockZ, cFreeConnectors & a_OutConnectors); + cPlacedPiece * PlaceStartingPiece(int a_BlockX, int a_BlockY, int a_BlockZ, cFreeConnectors & a_OutConnectors); /** Tries to place a new piece at the specified (placed) connector. Returns true if successful. */ bool TryPlacePieceAtConnector( @@ -168,14 +183,22 @@ protected: /** Checks if the specified piece would fit with the already-placed pieces, using the specified connector and number of CCW rotations. + a_ExistingConnector is in world-coords and is already rotated properly + a_ToPos is the world-coords position on which the new connector should be placed (1 block away from a_ExistingConnector, in its Direction) + a_NewConnector is in the original (non-rotated) coords. Returns true if the piece fits, false if not. */ bool CheckConnection( const cPiece::cConnector & a_ExistingConnector, // The existing connector + const Vector3i & a_ToPos, // The position on which the new connector should be placed const cPiece & a_Piece, // The new piece const cPiece::cConnector & a_NewConnector, // The connector of the new piece int a_NumCCWRotations, // Number of rotations for the new piece to align the connector const cPlacedPieces & a_OutPieces // All the already-placed pieces to check ); + + /** DEBUG: Outputs all the connectors in the pool into stdout. + a_NumProcessed signals the number of connectors from the pool that should be considered processed (not listed). */ + void DebugConnectorPool(const cPieceGenerator::cFreeConnectors & a_ConnectorPool, size_t a_NumProcessed); } ; @@ -190,8 +213,9 @@ class cBFSPieceGenerator : public: cBFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed); - /** Generates a placement for pieces at the specified coords. */ - void PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, cPlacedPieces & a_OutPieces); + /** Generates a placement for pieces at the specified coords. + Caller must free each individual cPlacedPiece in a_OutPieces. */ + void PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MaxDepth, cPlacedPieces & a_OutPieces); }; @@ -204,7 +228,8 @@ class cDFSPieceGenerator : public: cDFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed); - /** Generates a placement for pieces at the specified coords. */ + /** Generates a placement for pieces at the specified coords. + Caller must free each individual cPlacedPiece in a_OutPieces. */ void PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, cPlacedPieces & a_OutPieces); }; -- cgit v1.2.3 From 1fdeabcf78394d197a7ab5e0f9edca07abdedd0e Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 9 Mar 2014 19:30:38 +0100 Subject: cPieceGenerator: New connectors are added to the free pool. --- src/Generating/PieceGenerator.cpp | 32 ++++++++++++++++++++++++++------ src/Generating/PieceGenerator.h | 7 ++++--- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/Generating/PieceGenerator.cpp b/src/Generating/PieceGenerator.cpp index 58ccaf2c2..c8e4ec71b 100644 --- a/src/Generating/PieceGenerator.cpp +++ b/src/Generating/PieceGenerator.cpp @@ -361,7 +361,12 @@ cPlacedPiece * cPieceGenerator::PlaceStartingPiece(int a_BlockX, int a_BlockY, i -bool cPieceGenerator::TryPlacePieceAtConnector(const cPlacedPiece & a_ParentPiece, const cPiece::cConnector & a_Connector, cPlacedPieces & a_OutPieces) +bool cPieceGenerator::TryPlacePieceAtConnector( + const cPlacedPiece & a_ParentPiece, + const cPiece::cConnector & a_Connector, + cPlacedPieces & a_OutPieces, + cPieceGenerator::cFreeConnectors & a_OutConnectors +) { // Translation of direction - direction -> number of CCW rotations needed: // You need DirectionRotationTable[rot1][rot2] CCW turns to connect rot1 to rot2 (they are opposite) @@ -429,10 +434,24 @@ bool cPieceGenerator::TryPlacePieceAtConnector(const cPlacedPiece & a_ParentPiec ); Vector3i NewPos = Conn.m_Piece->RotatePos(Conn.m_Connector.m_Pos, Conn.m_NumCCWRotations); ConnPos -= NewPos; - a_OutPieces.push_back(new cPlacedPiece(&a_ParentPiece, *(Conn.m_Piece), ConnPos, Conn.m_NumCCWRotations)); + cPlacedPiece * PlacedPiece = new cPlacedPiece(&a_ParentPiece, *(Conn.m_Piece), ConnPos, Conn.m_NumCCWRotations); + a_OutPieces.push_back(PlacedPiece); // Add the new piece's connectors to the list of free connectors: - // TODO + cPiece::cConnectors Connectors = Conn.m_Piece->GetConnectors(); + + // DEBUG: + printf("Adding %u connectors to the pool\n", Connectors.size() - 1); + + for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr) + { + if (itr->m_Pos.Equals(Conn.m_Connector.m_Pos)) + { + // This is the connector through which we have been connected to the parent, don't add + continue; + } + a_OutConnectors.push_back(cFreeConnector(PlacedPiece, Conn.m_Piece->RotateMoveConnector(*itr, Conn.m_NumCCWRotations, ConnPos.x, ConnPos.y, ConnPos.z))); + } return true; } @@ -473,11 +492,12 @@ void cPieceGenerator::DebugConnectorPool(const cPieceGenerator::cFreeConnectors size_t idx = 0; for (cPieceGenerator::cFreeConnectors::const_iterator itr = a_ConnectorPool.begin() + a_NumProcessed, end = a_ConnectorPool.end(); itr != end; ++itr, ++idx) { - printf(" %u: {%d, %d, %d}, type %d, direction %s\n", + printf(" %u: {%d, %d, %d}, type %d, direction %s, depth %d\n", idx, itr->m_Connector.m_Pos.x, itr->m_Connector.m_Pos.y, itr->m_Connector.m_Pos.z, itr->m_Connector.m_Type, - BlockFaceToString(itr->m_Connector.m_Direction).c_str() + BlockFaceToString(itr->m_Connector.m_Direction).c_str(), + itr->m_Piece->GetDepth() ); } // for itr - a_ConnectorPool[] } @@ -556,7 +576,7 @@ void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, i cFreeConnector & Conn = ConnectorPool[NumProcessed]; if (Conn.m_Piece->GetDepth() < a_MaxDepth) { - if (TryPlacePieceAtConnector(*Conn.m_Piece, Conn.m_Connector, a_OutPieces)) + if (TryPlacePieceAtConnector(*Conn.m_Piece, Conn.m_Connector, a_OutPieces, ConnectorPool)) { const cPlacedPiece * NewPiece = a_OutPieces.back(); const Vector3i & Coords = NewPiece->GetCoords(); diff --git a/src/Generating/PieceGenerator.h b/src/Generating/PieceGenerator.h index 0e24510ae..310c21fdd 100644 --- a/src/Generating/PieceGenerator.h +++ b/src/Generating/PieceGenerator.h @@ -176,9 +176,10 @@ protected: /** Tries to place a new piece at the specified (placed) connector. Returns true if successful. */ bool TryPlacePieceAtConnector( - const cPlacedPiece & a_ParentPiece, - const cPiece::cConnector & a_Connector, - cPlacedPieces & a_OutPieces + const cPlacedPiece & a_ParentPiece, // The existing piece to a new piece should be placed + const cPiece::cConnector & a_Connector, // The existing connector (world-coords) to which a new piece should be placed + cPlacedPieces & a_OutPieces, // Already placed pieces, to be checked for intersections + cFreeConnectors & a_OutConnectors // List of free connectors to which the new connectors will be placed ); /** Checks if the specified piece would fit with the already-placed pieces, using the specified connector -- cgit v1.2.3 From 8889d3b73347a7cc094a0e233479e96f2bc25a49 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 9 Mar 2014 19:54:27 +0100 Subject: Added cCuboid::Engulf(). --- src/Cuboid.cpp | 34 ++++++++++++++++++++++++++++++++++ src/Cuboid.h | 3 +++ 2 files changed, 37 insertions(+) diff --git a/src/Cuboid.cpp b/src/Cuboid.cpp index 782837b23..dc8df8500 100644 --- a/src/Cuboid.cpp +++ b/src/Cuboid.cpp @@ -197,3 +197,37 @@ bool cCuboid::IsSorted(void) const + +void cCuboid::Engulf(const Vector3i & a_Point) +{ + if (a_Point.x < p1.x) + { + p1.x = a_Point.x; + } + else if (a_Point.x > p2.x) + { + p2.x = a_Point.x; + } + + if (a_Point.y < p1.y) + { + p1.y = a_Point.y; + } + else if (a_Point.y > p2.y) + { + p2.y = a_Point.y; + } + + if (a_Point.z < p1.z) + { + p1.z = a_Point.z; + } + else if (a_Point.z > p2.z) + { + p2.z = a_Point.z; + } +} + + + + diff --git a/src/Cuboid.h b/src/Cuboid.h index 51ccf799b..50a69b853 100644 --- a/src/Cuboid.h +++ b/src/Cuboid.h @@ -86,6 +86,9 @@ public: /** Returns true if the coords are properly sorted (lesser in p1, greater in p2) */ bool IsSorted(void) const; + + /** If needed, expands the cuboid so that it contains the specified point. Assumes sorted. Doesn't contract. */ + void Engulf(const Vector3i & a_Point); } ; // tolua_end -- cgit v1.2.3 From 81bf846e648bf757a67699c57f2a9e66f6850416 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 9 Mar 2014 21:58:12 +0100 Subject: ChunkDef: Replaced enums with static const ints. This makes them easier to use in std::min et al. --- src/ChunkDef.h | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/ChunkDef.h b/src/ChunkDef.h index 7be2fa2df..7876c58e7 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -62,16 +62,12 @@ typedef unsigned char HEIGHTTYPE; class cChunkDef { public: - enum - { - // Chunk dimensions: - Width = 16, - Height = 256, - NumBlocks = Width * Height * Width, - - /// If the data is collected into a single buffer, how large it needs to be: - BlockDataSize = cChunkDef::NumBlocks * 2 + (cChunkDef::NumBlocks / 2), // 2.5 * numblocks - } ; + // Chunk dimensions: + static const int Width = 16; + static const int Height = 256; + static const int NumBlocks = Width * Height * Width; + /// If the data is collected into a single buffer, how large it needs to be: + static const int BlockDataSize = cChunkDef::NumBlocks * 2 + (cChunkDef::NumBlocks / 2); // 2.5 * numblocks /// The type used for any heightmap operations and storage; idx = x + Width * z; Height points to the highest non-air block in the column typedef HEIGHTTYPE HeightMap[Width * Width]; -- cgit v1.2.3 From dacb6cef1d6d2942f01d15186d8a12b30d39a385 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 9 Mar 2014 22:02:08 +0100 Subject: Hardened cCuboid with asserts for its assumptions. --- src/Cuboid.cpp | 6 ++++++ src/Cuboid.h | 8 +++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Cuboid.cpp b/src/Cuboid.cpp index dc8df8500..2400c64f3 100644 --- a/src/Cuboid.cpp +++ b/src/Cuboid.cpp @@ -72,6 +72,9 @@ int cCuboid::GetVolume(void) const bool cCuboid::DoesIntersect(const cCuboid & a_Other) const { + ASSERT(IsSorted()); + ASSERT(a_Other.IsSorted()); + // In order for cuboids to intersect, each of their coord intervals need to intersect return ( DoIntervalsIntersect(p1.x, p2.x, a_Other.p1.x, a_Other.p2.x) && @@ -86,6 +89,9 @@ bool cCuboid::DoesIntersect(const cCuboid & a_Other) const bool cCuboid::IsCompletelyInside(const cCuboid & a_Outer) const { + ASSERT(IsSorted()); + ASSERT(a_Outer.IsSorted()); + return ( (p1.x >= a_Outer.p1.x) && (p2.x <= a_Outer.p2.x) && diff --git a/src/Cuboid.h b/src/Cuboid.h index 50a69b853..b95517f69 100644 --- a/src/Cuboid.h +++ b/src/Cuboid.h @@ -34,7 +34,8 @@ public: Works on unsorted cuboids, too. */ int GetVolume(void) const; - /** Returns true if the cuboids have at least one voxel in common. Both coords are considered inclusive. */ + /** Returns true if the cuboids have at least one voxel in common. Both coords are considered inclusive. + Assumes both cuboids are sorted. */ bool DoesIntersect(const cCuboid & a_Other) const; bool IsInside(const Vector3i & v) const @@ -64,7 +65,8 @@ public: ); } - /** Returns true if this cuboid is completely inside the specifie cuboid (in all 6 coords) */ + /** Returns true if this cuboid is completely inside the specifie cuboid (in all 6 coords). + Assumes both cuboids are sorted. */ bool IsCompletelyInside(const cCuboid & a_Outer) const; /** Moves the cuboid by the specified offsets in each direction */ @@ -72,7 +74,7 @@ public: /** Expands the cuboid by the specified amount in each direction. Works on unsorted cuboids as well. - Note that this function doesn't check for underflows. */ + Note that this function doesn't check for underflows when using negative amounts. */ void Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ); /** Clamps both X coords to the specified range. Works on unsorted cuboids, too. */ -- cgit v1.2.3 From 0e985293b50ec89a163f40222825b3c147135b9a Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 9 Mar 2014 22:04:29 +0100 Subject: A working POCPiece generator. --- src/Generating/ComposableGenerator.cpp | 5 + src/Generating/POCPieceGenerator.cpp | 265 +++++++++++++++++++++++++++++++++ src/Generating/POCPieceGenerator.h | 54 +++++++ src/Generating/PieceGenerator.cpp | 31 +++- src/Generating/PieceGenerator.h | 10 +- 5 files changed, 359 insertions(+), 6 deletions(-) create mode 100644 src/Generating/POCPieceGenerator.cpp create mode 100644 src/Generating/POCPieceGenerator.h diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index e96e9a645..6c00b5905 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -22,6 +22,7 @@ #include "EndGen.h" #include "MineShafts.h" #include "Noise3DGenerator.h" +#include "POCPieceGenerator.h" #include "Ravines.h" @@ -364,6 +365,10 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) { m_FinishGens.push_back(new cStructGenOreNests(Seed)); } + else if (NoCaseCompare(*itr, "POCPieces") == 0) + { + m_FinishGens.push_back(new cPOCPieceGenerator(Seed)); + } else if (NoCaseCompare(*itr, "PreSimulator") == 0) { m_FinishGens.push_back(new cFinishGenPreSimulator); diff --git a/src/Generating/POCPieceGenerator.cpp b/src/Generating/POCPieceGenerator.cpp new file mode 100644 index 000000000..9edfcc64f --- /dev/null +++ b/src/Generating/POCPieceGenerator.cpp @@ -0,0 +1,265 @@ + +// POCPieceGenerator.cpp + +// Implements the cPOCPieceGenerator class representing a Proof-Of_Concept structure generator using the cPieceGenerator technique +// The generator generates a maze of rooms at {0, 100, 0} + +#include "Globals.h" +#include "POCPieceGenerator.h" +#include "ChunkDesc.h" + + + + + +/** POC pieces are simple boxes that have connectors in the middle of their walls. +Each wall has one connector, there are 3 connector types that get assigned semi-randomly. +The piece also knows how to imprint itself in a cChunkDesc, each piece has a different color glass +and each connector is uses a different color wool frame. */ +class cPOCPiece : + public cPiece +{ +public: + cPOCPiece(int a_Size) : + m_Size(a_Size) + { + m_Connectors.push_back(cConnector(m_Size / 2, 1, 0, 0, BLOCK_FACE_ZM)); + m_Connectors.push_back(cConnector(m_Size / 2, 1, m_Size - 1, 1, BLOCK_FACE_ZP)); + m_Connectors.push_back(cConnector(0, 1, m_Size / 2, 2, BLOCK_FACE_XM)); + m_Connectors.push_back(cConnector(m_Size - 1, 1, m_Size / 2, m_Size % 3, BLOCK_FACE_XP)); + } + + + /** Imprints the piece in the specified chunk. Assumes they intersect. */ + void ImprintInChunk(cChunkDesc & a_ChunkDesc, const Vector3i & a_Pos, int a_NumCCWRotations) + { + int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width; + int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width; + Vector3i Min = a_Pos; + Min.Move(-BlockX, 0, -BlockZ); + Vector3i Max = Min; + Max.Move(m_Size - 1, 2, m_Size - 1); + ASSERT(Min.x < cChunkDef::Width); + ASSERT(Min.z < cChunkDef::Width); + ASSERT(Max.x >= 0); + ASSERT(Max.z >= 0); + if (Min.x >= 0) + { + // Draw the XM wall: + a_ChunkDesc.FillRelCuboid(Min.x, Min.x, Min.y, Max.y, Min.z, Max.z, E_BLOCK_STAINED_GLASS, m_Size % 16); + } + if (Min.z >= 0) + { + // Draw the ZM wall: + a_ChunkDesc.FillRelCuboid(Min.x, Max.x, Min.y, Max.y, Min.z, Min.z, E_BLOCK_STAINED_GLASS, m_Size % 16); + } + if (Max.x < cChunkDef::Width) + { + // Draw the XP wall: + a_ChunkDesc.FillRelCuboid(Max.x, Max.x, Min.y, Max.y, Min.z, Max.z, E_BLOCK_STAINED_GLASS, m_Size % 16); + } + if (Max.z < cChunkDef::Width) + { + // Draw the ZP wall: + a_ChunkDesc.FillRelCuboid(Min.x, Max.x, Min.y, Max.y, Max.z, Max.z, E_BLOCK_STAINED_GLASS, m_Size % 16); + } + + // Draw all the connectors: + for (cConnectors::const_iterator itr = m_Connectors.begin(), end = m_Connectors.end(); itr != end; ++itr) + { + cConnector Conn = cPiece::RotateMoveConnector(*itr, a_NumCCWRotations, a_Pos.x, a_Pos.y, a_Pos.z); + Conn.m_Pos.Move(-BlockX, 0, -BlockZ); + if ( + (Conn.m_Pos.x >= 0) && (Conn.m_Pos.x < cChunkDef::Width) && + (Conn.m_Pos.z >= 0) && (Conn.m_Pos.z < cChunkDef::Width) + ) + { + a_ChunkDesc.SetBlockTypeMeta(Conn.m_Pos.x, Conn.m_Pos.y, Conn.m_Pos.z, E_BLOCK_WOOL, itr->m_Type % 16); + } + + /* + // TODO: Frame the connectors + switch (itr->m_Direction) + { + case BLOCK_FACE_XM: + case BLOCK_FACE_XP: + { + // TODO + break; + } + + case BLOCK_FACE_ZM: + case BLOCK_FACE_ZP: + { + // TODO + break; + } + } + */ + } // for itr - m_Connectors[] + } + +protected: + int m_Size; + cConnectors m_Connectors; + + // cPiece overrides: + virtual cConnectors GetConnectors(void) const override + { + return m_Connectors; + } + + virtual Vector3i GetSize(void) const override + { + return Vector3i(m_Size, 3, m_Size); + } + + virtual cCuboid GetHitBox(void) const override + { + return cCuboid(0, 0, 0, m_Size - 1, 2, m_Size - 1); + } + + virtual bool CanRotateCCW(int a_NumRotations) const override + { + return true; + } +}; + + + + + +static void DebugPieces(const cPlacedPieces & a_Pieces) +{ + size_t idx = 0; + for (cPlacedPieces::const_iterator itr = a_Pieces.begin(), end = a_Pieces.end(); itr != end; ++itr, ++idx) + { + const cCuboid & HitBox = (*itr)->GetHitBox(); + printf(" %u: %d rotations, {%d - %d, %d - %d}\n", + idx, (*itr)->GetNumCCWRotations(), + HitBox.p1.x, HitBox.p2.x, HitBox.p1.z, HitBox.p2.z + ); + } // for itr - a_Pieces[] +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cPOCPieceGenerator: + +cPOCPieceGenerator::cPOCPieceGenerator(int a_Seed) : + m_Seed(a_Seed) +{ + // Prepare a vector of available pieces: + m_AvailPieces.push_back(new cPOCPiece(5)); + m_AvailPieces.push_back(new cPOCPiece(7)); + m_AvailPieces.push_back(new cPOCPiece(9)); + + // Generate the structure: + cBFSPieceGenerator Gen(*this, a_Seed); + Gen.PlacePieces(0, 50, 0, 6, m_Pieces); + + // DebugPieces(m_Pieces); + + // Get the smallest cuboid encompassing the entire generated structure: + cCuboid Bounds(0, 50, 0, 0, 50, 0); + for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr) + { + Vector3i MinCoords = (*itr)->GetCoords(); + Bounds.Engulf(MinCoords); + Bounds.Engulf(MinCoords + (*itr)->GetPiece().GetSize()); + } // for itr - m_Pieces[] + m_Bounds = Bounds; +} + + + + + +cPOCPieceGenerator::~cPOCPieceGenerator() +{ + cPieceGenerator::FreePieces(m_Pieces); +} + + + + + +void cPOCPieceGenerator::GenFinish(cChunkDesc & a_ChunkDesc) +{ + int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width; + int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width; + if ( + (BlockX + 16 < m_Bounds.p1.x) || (BlockX > m_Bounds.p2.x) || // X coords out of bounds of the generated structure + (BlockZ + 16 < m_Bounds.p1.z) || (BlockZ > m_Bounds.p2.z) // Z coords out of bounds of the generated structure + ) + { + return; + } + + // Imprint each piece in the chunk: + for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr) + { + const Vector3i & Pos = (*itr)->GetCoords(); + Vector3i Size = (*itr)->GetPiece().GetSize(); + if (((*itr)->GetNumCCWRotations() % 2) == 1) + { + std::swap(Size.x, Size.z); + } + if ( + (Pos.x >= BlockX + 16) || (Pos.x + Size.x - 1 < BlockX) || + (Pos.z >= BlockZ + 16) || (Pos.z + Size.z - 1 < BlockZ) + ) + { + // This piece doesn't intersect the chunk + continue; + } + + ((cPOCPiece &)(*itr)->GetPiece()).ImprintInChunk(a_ChunkDesc, Pos, (*itr)->GetNumCCWRotations()); + } // for itr - m_Pieces[] + a_ChunkDesc.UpdateHeightmap(); +} + + + + + +cPieces cPOCPieceGenerator::GetPiecesWithConnector(int a_ConnectorType) +{ + // Each piece has each connector + return m_AvailPieces; +} + + + + + +cPieces cPOCPieceGenerator::GetStartingPieces(void) +{ + // Any piece can be a starting piece + return m_AvailPieces; +} + + + + + +void cPOCPieceGenerator::PiecePlaced(const cPiece & a_Piece) +{ + UNUSED(a_Piece); +} + + + + + +void cPOCPieceGenerator::Reset(void) +{ + // Nothing needed +} + + + + diff --git a/src/Generating/POCPieceGenerator.h b/src/Generating/POCPieceGenerator.h new file mode 100644 index 000000000..de3114ce0 --- /dev/null +++ b/src/Generating/POCPieceGenerator.h @@ -0,0 +1,54 @@ + +// POCPieceGenerator.h + +// Declares the cPOCPieceGenerator class representing a Proof-Of_Concept structure generator using the cPieceGenerator technique +// The generator generates a maze of rooms at {0, 100, 0} + + + + + +#pragma once + +#include "PieceGenerator.h" +#include "ComposableGenerator.h" + + + + + +class cPOCPieceGenerator : + public cFinishGen, + protected cPiecePool +{ +public: + cPOCPieceGenerator(int a_Seed); + ~cPOCPieceGenerator(); + +protected: + int m_Seed; + + /** The pieces from which the generated structure is built. */ + cPieces m_AvailPieces; + + /** The placed pieces of the generated structure. */ + cPlacedPieces m_Pieces; + + /** Bounds of the complete structure, to save on processing outside chunks. */ + cCuboid m_Bounds; + + + // cFinishGen overrides: + virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; + + // cPiecePool overrides: + virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override; + virtual cPieces GetStartingPieces(void) override; + virtual void PiecePlaced(const cPiece & a_Piece) override; + virtual void Reset(void) override; +} ; + + + + + diff --git a/src/Generating/PieceGenerator.cpp b/src/Generating/PieceGenerator.cpp index c8e4ec71b..e3de5b951 100644 --- a/src/Generating/PieceGenerator.cpp +++ b/src/Generating/PieceGenerator.cpp @@ -11,6 +11,8 @@ +#ifdef SELF_TEST + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Self-test: @@ -132,6 +134,8 @@ protected: } } g_Test; +#endif // SELF_TEST + @@ -287,6 +291,7 @@ cPlacedPiece::cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece { m_Depth = (m_Parent == NULL) ? 0 : (m_Parent->GetDepth() + 1); m_HitBox = a_Piece.RotateMoveHitBox(a_NumCCWRotations, a_Coords.x, a_Coords.y, a_Coords.z); + m_HitBox.Sort(); } @@ -375,10 +380,10 @@ bool cPieceGenerator::TryPlacePieceAtConnector( /* YM, YP, ZM, ZP, XM, XP /* YM */ { 0, 0, 0, 0, 0, 0}, /* YP */ { 0, 0, 0, 0, 0, 0}, - /* ZM */ { 0, 0, 0, 2, 1, 3}, - /* ZP */ { 0, 0, 2, 0, 3, 1}, - /* XM */ { 0, 0, 3, 1, 0, 2}, - /* XP */ { 0, 0, 1, 3, 2, 0}, + /* ZM */ { 0, 0, 2, 0, 1, 3}, + /* ZP */ { 0, 0, 0, 2, 3, 1}, + /* XM */ { 0, 0, 3, 1, 2, 0}, + /* XP */ { 0, 0, 1, 3, 0, 2}, }; // Get a list of available connections: @@ -389,8 +394,10 @@ bool cPieceGenerator::TryPlacePieceAtConnector( Vector3i ConnPos = a_Connector.m_Pos; // The position at which the new connector should be placed - 1 block away from the connector AddFaceDirection(ConnPos.x, ConnPos.y, ConnPos.z, a_Connector.m_Direction); + /* // DEBUG: - printf("Placing piece at pos {%d, %d, %d}, direction %s\n", ConnPos.x, ConnPos.y, ConnPos.z, BlockFaceToString(a_Connector.m_Direction).c_str()); + printf("Placing piece at connector pos {%d, %d, %d}, direction %s\n", ConnPos.x, ConnPos.y, ConnPos.z, BlockFaceToString(a_Connector.m_Direction).c_str()); + //*/ for (cPieces::iterator itrP = AvailablePieces.begin(), endP = AvailablePieces.end(); itrP != endP; ++itrP) { @@ -427,11 +434,15 @@ bool cPieceGenerator::TryPlacePieceAtConnector( cConnection & Conn = Connections[rnd % Connections.size()]; // Place the piece: + /* + // DEBUG printf("Chosen connector at {%d, %d, %d}, direction %s, needs %d rotations\n", Conn.m_Connector.m_Pos.x, Conn.m_Connector.m_Pos.y, Conn.m_Connector.m_Pos.z, BlockFaceToString(Conn.m_Connector.m_Direction).c_str(), Conn.m_NumCCWRotations ); + //*/ + Vector3i NewPos = Conn.m_Piece->RotatePos(Conn.m_Connector.m_Pos, Conn.m_NumCCWRotations); ConnPos -= NewPos; cPlacedPiece * PlacedPiece = new cPlacedPiece(&a_ParentPiece, *(Conn.m_Piece), ConnPos, Conn.m_NumCCWRotations); @@ -440,8 +451,10 @@ bool cPieceGenerator::TryPlacePieceAtConnector( // Add the new piece's connectors to the list of free connectors: cPiece::cConnectors Connectors = Conn.m_Piece->GetConnectors(); + /* // DEBUG: printf("Adding %u connectors to the pool\n", Connectors.size() - 1); + //*/ for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr) { @@ -471,6 +484,7 @@ bool cPieceGenerator::CheckConnection( { // For each placed piece, test the hitbox against the new piece: cCuboid RotatedHitBox = a_Piece.RotateHitBoxToConnector(a_NewConnector, a_ToPos, a_NumCCWRotations); + RotatedHitBox.Sort(); for (cPlacedPieces::const_iterator itr = a_OutPieces.begin(), end = a_OutPieces.end(); itr != end; ++itr) { if ((*itr)->GetHitBox().DoesIntersect(RotatedHitBox)) @@ -485,6 +499,7 @@ bool cPieceGenerator::CheckConnection( +//* // DEBUG: void cPieceGenerator::DebugConnectorPool(const cPieceGenerator::cFreeConnectors & a_ConnectorPool, size_t a_NumProcessed) { @@ -501,6 +516,7 @@ void cPieceGenerator::DebugConnectorPool(const cPieceGenerator::cFreeConnectors ); } // for itr - a_ConnectorPool[] } +//*/ @@ -553,6 +569,7 @@ void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, i // Place the starting piece: a_OutPieces.push_back(PlaceStartingPiece(a_BlockX, a_BlockY, a_BlockZ, ConnectorPool)); + /* // DEBUG: printf("Placed the starting piece at {%d, %d, %d}\n", a_BlockX, a_BlockY, a_BlockZ); cCuboid Hitbox = a_OutPieces[0]->GetHitBox(); @@ -563,6 +580,7 @@ void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, i Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1 ); DebugConnectorPool(ConnectorPool, 0); + //*/ // Place pieces at the available connectors: /* @@ -578,6 +596,8 @@ void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, i { if (TryPlacePieceAtConnector(*Conn.m_Piece, Conn.m_Connector, a_OutPieces, ConnectorPool)) { + /* + // DEBUG: const cPlacedPiece * NewPiece = a_OutPieces.back(); const Vector3i & Coords = NewPiece->GetCoords(); printf("Placed a new piece at {%d, %d, %d}, rotation %d\n", Coords.x, Coords.y, Coords.z, NewPiece->GetNumCCWRotations()); @@ -589,6 +609,7 @@ void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, i Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1 ); DebugConnectorPool(ConnectorPool, NumProcessed + 1); + //*/ } } NumProcessed++; diff --git a/src/Generating/PieceGenerator.h b/src/Generating/PieceGenerator.h index 310c21fdd..9dd5bcfba 100644 --- a/src/Generating/PieceGenerator.h +++ b/src/Generating/PieceGenerator.h @@ -30,6 +30,9 @@ Each uses a slightly different approach to generating: class cPiece { public: + // Force a virtual destructor in all descendants + virtual ~cPiece() {} + struct cConnector { /** Position relative to the piece */ @@ -82,9 +85,14 @@ typedef std::vector cPieces; +/** This class is an interface that provides pieces for the generator. It can keep track of what pieces were +placed and adjust the returned piece vectors. */ class cPiecePool { public: + // Force a virtual destructor in all descendants: + virtual ~cPiecePool() {} + /** Returns a list of pieces that contain the specified connector type. The cPiece pointers returned are managed by the pool and the caller doesn't free them. */ virtual cPieces GetPiecesWithConnector(int a_ConnectorType) = 0; @@ -140,7 +148,7 @@ public: /** Cleans up all the memory used by the placed pieces. Call this utility function instead of freeing the items on your own. */ - void FreePieces(cPlacedPieces & a_PlacedPieces); + static void FreePieces(cPlacedPieces & a_PlacedPieces); protected: /** The type used for storing a connection from one piece to another, while building the piece tree. */ -- cgit v1.2.3 From 6c4807556141f49a3fa5ff63474e6b95e5fd5cbf Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 10 Mar 2014 08:38:40 +0100 Subject: POCPieces: Added height. Now the pieces connect in different heights, too, creating a true 3D maze. --- src/Generating/POCPieceGenerator.cpp | 37 +++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/Generating/POCPieceGenerator.cpp b/src/Generating/POCPieceGenerator.cpp index 9edfcc64f..d7619b8ff 100644 --- a/src/Generating/POCPieceGenerator.cpp +++ b/src/Generating/POCPieceGenerator.cpp @@ -20,13 +20,14 @@ class cPOCPiece : public cPiece { public: - cPOCPiece(int a_Size) : - m_Size(a_Size) + cPOCPiece(int a_SizeXZ, int a_Height) : + m_SizeXZ(a_SizeXZ), + m_Height(a_Height) { - m_Connectors.push_back(cConnector(m_Size / 2, 1, 0, 0, BLOCK_FACE_ZM)); - m_Connectors.push_back(cConnector(m_Size / 2, 1, m_Size - 1, 1, BLOCK_FACE_ZP)); - m_Connectors.push_back(cConnector(0, 1, m_Size / 2, 2, BLOCK_FACE_XM)); - m_Connectors.push_back(cConnector(m_Size - 1, 1, m_Size / 2, m_Size % 3, BLOCK_FACE_XP)); + m_Connectors.push_back(cConnector(m_SizeXZ / 2, a_Height / 2, 0, 0, BLOCK_FACE_ZM)); + m_Connectors.push_back(cConnector(m_SizeXZ / 2, a_Height / 2, m_SizeXZ - 1, 1, BLOCK_FACE_ZP)); + m_Connectors.push_back(cConnector(0, a_Height / 2, m_SizeXZ / 2, 2, BLOCK_FACE_XM)); + m_Connectors.push_back(cConnector(m_SizeXZ - 1, a_Height - 1, m_SizeXZ / 2, m_SizeXZ % 3, BLOCK_FACE_XP)); } @@ -38,7 +39,7 @@ public: Vector3i Min = a_Pos; Min.Move(-BlockX, 0, -BlockZ); Vector3i Max = Min; - Max.Move(m_Size - 1, 2, m_Size - 1); + Max.Move(m_SizeXZ - 1, m_Height - 1, m_SizeXZ - 1); ASSERT(Min.x < cChunkDef::Width); ASSERT(Min.z < cChunkDef::Width); ASSERT(Max.x >= 0); @@ -46,22 +47,22 @@ public: if (Min.x >= 0) { // Draw the XM wall: - a_ChunkDesc.FillRelCuboid(Min.x, Min.x, Min.y, Max.y, Min.z, Max.z, E_BLOCK_STAINED_GLASS, m_Size % 16); + a_ChunkDesc.FillRelCuboid(Min.x, Min.x, Min.y, Max.y, Min.z, Max.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16); } if (Min.z >= 0) { // Draw the ZM wall: - a_ChunkDesc.FillRelCuboid(Min.x, Max.x, Min.y, Max.y, Min.z, Min.z, E_BLOCK_STAINED_GLASS, m_Size % 16); + a_ChunkDesc.FillRelCuboid(Min.x, Max.x, Min.y, Max.y, Min.z, Min.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16); } if (Max.x < cChunkDef::Width) { // Draw the XP wall: - a_ChunkDesc.FillRelCuboid(Max.x, Max.x, Min.y, Max.y, Min.z, Max.z, E_BLOCK_STAINED_GLASS, m_Size % 16); + a_ChunkDesc.FillRelCuboid(Max.x, Max.x, Min.y, Max.y, Min.z, Max.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16); } if (Max.z < cChunkDef::Width) { // Draw the ZP wall: - a_ChunkDesc.FillRelCuboid(Min.x, Max.x, Min.y, Max.y, Max.z, Max.z, E_BLOCK_STAINED_GLASS, m_Size % 16); + a_ChunkDesc.FillRelCuboid(Min.x, Max.x, Min.y, Max.y, Max.z, Max.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16); } // Draw all the connectors: @@ -100,7 +101,8 @@ public: } protected: - int m_Size; + int m_SizeXZ; + int m_Height; cConnectors m_Connectors; // cPiece overrides: @@ -111,12 +113,12 @@ protected: virtual Vector3i GetSize(void) const override { - return Vector3i(m_Size, 3, m_Size); + return Vector3i(m_SizeXZ, m_Height, m_SizeXZ); } virtual cCuboid GetHitBox(void) const override { - return cCuboid(0, 0, 0, m_Size - 1, 2, m_Size - 1); + return cCuboid(0, 0, 0, m_SizeXZ - 1, m_Height - 1, m_SizeXZ - 1); } virtual bool CanRotateCCW(int a_NumRotations) const override @@ -153,9 +155,10 @@ cPOCPieceGenerator::cPOCPieceGenerator(int a_Seed) : m_Seed(a_Seed) { // Prepare a vector of available pieces: - m_AvailPieces.push_back(new cPOCPiece(5)); - m_AvailPieces.push_back(new cPOCPiece(7)); - m_AvailPieces.push_back(new cPOCPiece(9)); + m_AvailPieces.push_back(new cPOCPiece(5, 3)); + m_AvailPieces.push_back(new cPOCPiece(7, 5)); + m_AvailPieces.push_back(new cPOCPiece(9, 5)); + m_AvailPieces.push_back(new cPOCPiece(5, 7)); // Generate the structure: cBFSPieceGenerator Gen(*this, a_Seed); -- cgit v1.2.3 From 26d7ed661225ed092bd79c55e16134aef770ee3b Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 10 Mar 2014 21:16:13 +0100 Subject: Removed debugging output. Kept it commented-out for later revisions, if needed. --- src/Generating/POCPieceGenerator.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Generating/POCPieceGenerator.cpp b/src/Generating/POCPieceGenerator.cpp index d7619b8ff..9ed4b565e 100644 --- a/src/Generating/POCPieceGenerator.cpp +++ b/src/Generating/POCPieceGenerator.cpp @@ -2,7 +2,7 @@ // POCPieceGenerator.cpp // Implements the cPOCPieceGenerator class representing a Proof-Of_Concept structure generator using the cPieceGenerator technique -// The generator generates a maze of rooms at {0, 100, 0} +// The generator generates a maze of rooms at {0, 50, 0} #include "Globals.h" #include "POCPieceGenerator.h" @@ -131,6 +131,7 @@ protected: +/* static void DebugPieces(const cPlacedPieces & a_Pieces) { size_t idx = 0; @@ -143,6 +144,7 @@ static void DebugPieces(const cPlacedPieces & a_Pieces) ); } // for itr - a_Pieces[] } +//*/ -- cgit v1.2.3