mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-06 20:24:33 +00:00
Merge 7d65976c31 into 20bf6b7de9
This commit is contained in:
commit
fd730b057d
15 changed files with 3895 additions and 445 deletions
|
|
@ -33,8 +33,6 @@
|
|||
/// @file
|
||||
/// Definitions for the core engine structured types.
|
||||
|
||||
|
||||
template< typename T > class Vector;
|
||||
namespace Torque {
|
||||
class UUID;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ class String;
|
|||
class FileName;
|
||||
class SimObject;
|
||||
class SimObjectType;
|
||||
template<class T> class Vector;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// String scan/print methods
|
||||
|
|
|
|||
|
|
@ -30,9 +30,8 @@
|
|||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
template< class T > class Vector;
|
||||
|
||||
template<typename T, U32 COUNT> struct CustomAllocator;
|
||||
template<typename T, U32 COUNT, typename Allocator> class Vector;
|
||||
|
||||
typedef UTF8 StringChar;
|
||||
|
||||
|
|
@ -147,7 +146,7 @@ public:
|
|||
String collapseEscapes() const;
|
||||
|
||||
/// Split the string into its components separated by the given delimiter.
|
||||
void split( const char* delimiter, Vector< String >& outElements ) const;
|
||||
void split( const char* delimiter, Vector<String, 0, CustomAllocator<String, 0> >& outElements ) const;
|
||||
|
||||
/// Return true if the string starts with the given text.
|
||||
bool startsWith( const char* text ) const;
|
||||
|
|
|
|||
|
|
@ -24,54 +24,16 @@
|
|||
#include "core/util/tVector.h"
|
||||
|
||||
#include "platform/profiler.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
|
||||
#ifdef TORQUE_DEBUG_GUARD
|
||||
|
||||
bool VectorResize(U32 *aSize, U32 *aCount, void **arrayPtr, U32 newCount, U32 elemSize,
|
||||
const char* fileName,
|
||||
const U32 lineNum)
|
||||
bool VectorResize(U32* aSize, U32* aCount, void** arrayPtr, U32 newCount, U32 elemSize,
|
||||
const char* fileName,
|
||||
const U32 lineNum)
|
||||
{
|
||||
PROFILE_SCOPE( VectorResize );
|
||||
|
||||
if (newCount > 0)
|
||||
{
|
||||
U32 blocks = newCount / VectorBlockSize;
|
||||
if (newCount % VectorBlockSize)
|
||||
blocks++;
|
||||
S32 mem_size = blocks * VectorBlockSize * elemSize;
|
||||
|
||||
const char* pUseFileName = fileName != NULL ? fileName : __FILE__;
|
||||
U32 useLineNum = fileName != NULL ? lineNum : __LINE__;
|
||||
|
||||
if (*arrayPtr != NULL)
|
||||
*arrayPtr = dRealloc_r(*arrayPtr, mem_size, pUseFileName, useLineNum);
|
||||
else
|
||||
*arrayPtr = dMalloc_r(mem_size, pUseFileName, useLineNum);
|
||||
|
||||
AssertFatal( *arrayPtr, "VectorResize - Allocation failed." );
|
||||
|
||||
*aCount = newCount;
|
||||
*aSize = blocks * VectorBlockSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (*arrayPtr)
|
||||
{
|
||||
dFree(*arrayPtr);
|
||||
*arrayPtr = 0;
|
||||
}
|
||||
|
||||
*aSize = 0;
|
||||
*aCount = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool VectorResize(U32 *aSize, U32 *aCount, void **arrayPtr, U32 newCount, U32 elemSize)
|
||||
{
|
||||
PROFILE_SCOPE( VectorResize );
|
||||
PROFILE_SCOPE(VectorResize);
|
||||
|
||||
if (newCount > 0)
|
||||
{
|
||||
|
|
@ -79,7 +41,46 @@ bool VectorResize(U32 *aSize, U32 *aCount, void **arrayPtr, U32 newCount, U32 el
|
|||
if (newCount % VectorBlockSize)
|
||||
blocks++;
|
||||
S32 mem_size = blocks * VectorBlockSize * elemSize;
|
||||
*arrayPtr = *arrayPtr ? dRealloc(*arrayPtr,mem_size) :
|
||||
|
||||
const char* pUseFileName = fileName != NULL ? fileName : __FILE__;
|
||||
U32 useLineNum = fileName != NULL ? lineNum : __LINE__;
|
||||
|
||||
if (*arrayPtr != NULL)
|
||||
*arrayPtr = dRealloc_r(*arrayPtr, mem_size, pUseFileName, useLineNum);
|
||||
else
|
||||
*arrayPtr = dMalloc_r(mem_size, pUseFileName, useLineNum);
|
||||
|
||||
AssertFatal(*arrayPtr, "VectorResize - Allocation failed.");
|
||||
|
||||
*aCount = newCount;
|
||||
*aSize = blocks * VectorBlockSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (*arrayPtr)
|
||||
{
|
||||
dFree(*arrayPtr);
|
||||
*arrayPtr = 0;
|
||||
}
|
||||
|
||||
*aSize = 0;
|
||||
*aCount = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool VectorResize(U32* aSize, U32* aCount, void** arrayPtr, U32 newCount, U32 elemSize)
|
||||
{
|
||||
PROFILE_SCOPE(VectorResize);
|
||||
|
||||
if (newCount > 0)
|
||||
{
|
||||
U32 blocks = newCount / VectorBlockSize;
|
||||
if (newCount % VectorBlockSize)
|
||||
blocks++;
|
||||
S32 mem_size = blocks * VectorBlockSize * elemSize;
|
||||
*arrayPtr = *arrayPtr ? dRealloc(*arrayPtr, mem_size) :
|
||||
dMalloc(mem_size);
|
||||
|
||||
*aCount = newCount;
|
||||
|
|
@ -87,7 +88,7 @@ bool VectorResize(U32 *aSize, U32 *aCount, void **arrayPtr, U32 newCount, U32 el
|
|||
return true;
|
||||
}
|
||||
|
||||
if (*arrayPtr)
|
||||
if (*arrayPtr)
|
||||
{
|
||||
dFree(*arrayPtr);
|
||||
*arrayPtr = 0;
|
||||
|
|
@ -99,3 +100,172 @@ bool VectorResize(U32 *aSize, U32 *aCount, void **arrayPtr, U32 newCount, U32 el
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
void test_Vector_dynamic() {
|
||||
Vector<U8> v;
|
||||
AssertFatal(v.size() == 0, "Initial size should be 0");
|
||||
AssertFatal(v.empty(), "Vector should be empty");
|
||||
|
||||
// push_back, push_front, front, back
|
||||
v.push_back(42);
|
||||
AssertFatal(v.size() == 1, "Size after push_back should be 1");
|
||||
AssertFatal(v[0] == 42, "push_back value incorrect");
|
||||
v.push_front(7);
|
||||
AssertFatal(v.size() == 2, "Size after push_front should be 2");
|
||||
AssertFatal(v[0] == 7 && v[1] == 42, "push_front value incorrect");
|
||||
AssertFatal(v.front() == 7, "front() incorrect");
|
||||
AssertFatal(v.back() == 42, "back() incorrect");
|
||||
|
||||
// insert, erase, erase_fast
|
||||
v.insert(1, 99);
|
||||
AssertFatal(v.size() == 3, "Size after insert should be 3");
|
||||
AssertFatal(v[1] == 99, "insert value incorrect");
|
||||
v.erase(1);
|
||||
AssertFatal(v.size() == 2, "Size after erase should be 2");
|
||||
v.push_back(55);
|
||||
v.erase_fast(static_cast < U32>(0));
|
||||
AssertFatal(v.size() == 2, "Size after erase_fast should be 2");
|
||||
|
||||
// find_next, contains, remove
|
||||
AssertFatal(v.find_next(42) != -1, "find_next failed");
|
||||
AssertFatal(v.contains(42), "contains failed");
|
||||
AssertFatal(v.remove(42), "remove failed");
|
||||
AssertFatal(!v.contains(42), "remove did not remove value");
|
||||
|
||||
// pop_front, pop_back
|
||||
v.push_back(88);
|
||||
v.pop_front();
|
||||
AssertFatal(v.size() == 1, "pop_front failed");
|
||||
v.pop_back();
|
||||
AssertFatal(v.size() == 0, "pop_back failed");
|
||||
|
||||
// reserve, capacity, setSize, set, clear, compact, fill, copy, merge, reverse
|
||||
v.reserve(5);
|
||||
AssertFatal(v.capacity() >= 5, "reserve/capacity failed");
|
||||
v.setSize(3);
|
||||
AssertFatal(v.size() == 3, "setSize failed");
|
||||
U8 arr[3] = { 1,2,3 };
|
||||
v.set(arr, 3);
|
||||
for (U32 i = 0; i < 3; ++i) AssertFatal(v[i] == arr[i], "set failed");
|
||||
v.clear();
|
||||
AssertFatal(v.size() == 0, "clear failed");
|
||||
v.setSize(3);
|
||||
v.fill(9);
|
||||
for (U32 i = 0; i < 3; ++i) AssertFatal(v[i] == 9, "fill failed");
|
||||
U8 arr2[3] = { 4,5,6 };
|
||||
v.copy(arr2);
|
||||
for (U32 i = 0; i < 3; ++i) AssertFatal(v[i] == arr2[i], "copy failed");
|
||||
v.reverse();
|
||||
AssertFatal(v[0] == 6 && v[2] == 4, "reverse failed");
|
||||
Vector<U8> v2;
|
||||
v2.set(arr, 3);
|
||||
v.merge(v2);
|
||||
AssertFatal(v.size() == 6, "merge failed");
|
||||
|
||||
// increment, decrement
|
||||
v.increment();
|
||||
AssertFatal(v.size() == 7, "increment failed");
|
||||
v.decrement();
|
||||
AssertFatal(v.size() == 6, "decrement failed");
|
||||
v.increment(2);
|
||||
AssertFatal(v.size() == 8, "increment(n) failed");
|
||||
v.decrement(2);
|
||||
AssertFatal(v.size() == 6, "decrement(n) failed");
|
||||
|
||||
// insert (block), fill(count), fill(count, offset)
|
||||
U8 block[2] = { 10,11 };
|
||||
v.insert(block, 2, 2);
|
||||
AssertFatal(v[2] == 10 && v[3] == 11, "block insert failed");
|
||||
v.fill(7, 2);
|
||||
for (U32 i = 0; i < 2; ++i) AssertFatal(v[i] == 7, "fill(count) failed");
|
||||
v.fill(8, 2, 2);
|
||||
AssertFatal(v[2] == 8 && v[3] == 8, "fill(count,offset) failed");
|
||||
|
||||
// assign, moveFrom, swap, compare, forEach, removeIf, countIf, anyOf, allOf
|
||||
Vector<U8> v3;
|
||||
v3.set(arr, 3);
|
||||
v.assign(&v3, 3, 0, 0);
|
||||
for (U32 i = 0; i < 3; ++i) AssertFatal(v[i] == arr[i], "assign failed");
|
||||
v3.moveFrom(v);
|
||||
AssertFatal(v3.size() == 3 && v.size() == 0, "moveFrom failed");
|
||||
v.set(arr, 3);
|
||||
v.swap(v3);
|
||||
for (U32 i = 0; i < 3; ++i) AssertFatal(v[i] == arr[i], "swap failed");
|
||||
AssertFatal(v.compare(v3), "compare failed");
|
||||
v.forEach([](U8& x) { x = 1; });
|
||||
for (U32 i = 0; i < v.size(); ++i) AssertFatal(v[i] == 1, "forEach failed");
|
||||
v.removeIf([](U8 x) { return x == 1; });
|
||||
AssertFatal(v.size() == 0, "removeIf failed");
|
||||
v.set(arr, 3);
|
||||
U32 countifResult = v.countIf([](U8 x) { return x > 2; });
|
||||
AssertFatal(countifResult, "countIf failed");
|
||||
U8 anyofResult = v.anyOf([](U8 x) { return x == 2; });
|
||||
AssertFatal(anyofResult, "anyOf failed");
|
||||
U8 allofResult = v.allOf([](U8 x) { return x > 0; });
|
||||
AssertFatal(allofResult, "allOf failed");
|
||||
}
|
||||
|
||||
void test_Vector_fixed() {
|
||||
Vector<U8, 10> v;
|
||||
AssertFatal(v.size() == 10, "Fixed vector size should be 10");
|
||||
|
||||
// fill, operator[], front, back, first, last
|
||||
v.fill(5);
|
||||
for (U32 i = 0; i < v.size(); ++i) AssertFatal(v[i] == 5, "fill failed");
|
||||
v[3] = 99;
|
||||
AssertFatal(v[3] == 99, "operator[] failed");
|
||||
AssertFatal(v.front() == 5, "front failed");
|
||||
AssertFatal(v.back() == 5, "back failed");
|
||||
AssertFatal(v.first() == 5, "first failed");
|
||||
AssertFatal(v.last() == 5, "last failed");
|
||||
|
||||
// reverse, swap, erase, erase_fast, contains, remove
|
||||
v.reverse();
|
||||
AssertFatal(v[6] == 99, "reverse failed");
|
||||
Vector<U8, 10> v2;
|
||||
v2.fill(1);
|
||||
v.swap(v2);
|
||||
for (U32 i = 0; i < v.size(); ++i) AssertFatal(v[i] == 1 && v2[i] == 5, "swap failed");
|
||||
v.erase(static_cast <U32>(0));
|
||||
AssertFatal(v.size() == 10, "erase should not change size for fixed vector");
|
||||
v.erase_fast(1);
|
||||
AssertFatal(v.size() == 10, "erase_fast should not change size for fixed vector");
|
||||
AssertFatal(v.contains(1), "contains failed");
|
||||
v.remove(1);
|
||||
AssertFatal(v.contains(1), "remove should not change size for fixed vector");
|
||||
|
||||
// fill(count), fill(count, offset), copy, merge, assign, compare
|
||||
v.fill(2, 5);
|
||||
for (U32 i = 0; i < 5; ++i) AssertFatal(v[i] == 2, "fill(count) failed");
|
||||
v.fill(3, 2, 5);
|
||||
AssertFatal(v[5] == 3 && v[6] == 3, "fill(count,offset) failed");
|
||||
U8 arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
|
||||
v.copy(arr);
|
||||
for (U32 i = 0; i < 10; ++i) AssertFatal(v[i] == arr[i], "copy failed");
|
||||
v2.copy(arr);
|
||||
v.merge(v2);
|
||||
AssertFatal(v.size() == 10, "merge should not change size for fixed vector");
|
||||
v.assign(&v2, 10, 0, 0);
|
||||
for (U32 i = 0; i < 10; ++i) AssertFatal(v[i] == arr[i], "assign failed");
|
||||
AssertFatal(v.compare(v2), "compare failed");
|
||||
|
||||
// forEach, removeIf, countIf, anyOf, allOf
|
||||
v.forEach([](U8& x) { x = 4; });
|
||||
for (U32 i = 0; i < v.size(); ++i) AssertFatal(v[i] == 4, "forEach failed");
|
||||
v.removeIf([](U8 x) { return x == 4; });
|
||||
AssertFatal(v.size() == 10, "removeIf should not change size for fixed vector");
|
||||
v.copy(arr);
|
||||
U32 countifResult = v.countIf([](U8 x) { return x > 5; });
|
||||
AssertFatal(countifResult == 4, "countIf failed");
|
||||
U8 anyofResult = v.anyOf([](U8 x) { return x == 7; });
|
||||
AssertFatal(anyofResult, "anyOf failed");
|
||||
U8 allofResult = v.allOf([](U8 x) { return x < 10; });
|
||||
AssertFatal(allofResult, "allOf failed");
|
||||
}
|
||||
|
||||
DefineEngineFunction(test_Vector, void, (), ,
|
||||
"Test the Vector class with both dynamic and fixed-size vectors.")
|
||||
{
|
||||
test_Vector_dynamic();
|
||||
test_Vector_fixed();
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -27,6 +27,8 @@
|
|||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
|
||||
template<typename T, U32 COUNT> struct CustomAllocator;
|
||||
template<typename T, U32 COUNT, typename Allocator> class Vector;
|
||||
// Not exactly a specialization, just a vector to use when speed is a concern
|
||||
template<class T>
|
||||
class FastVector : public Vector<T>
|
||||
|
|
|
|||
489
Engine/source/core/util/treeObject.cpp
Normal file
489
Engine/source/core/util/treeObject.cpp
Normal file
|
|
@ -0,0 +1,489 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2025 Ratfish Studios, LLC
|
||||
// Portions Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "treeObject.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(TreeObject);
|
||||
|
||||
TreeObject::~TreeObject()
|
||||
{
|
||||
if (mRoot)
|
||||
{
|
||||
delete mRoot;
|
||||
mRoot = NULL;
|
||||
}
|
||||
|
||||
// Clean up any orphaned nodes (safety measure)
|
||||
for (Map<S32, Node*>::Iterator i = mKeyMap.begin(); i != mKeyMap.end(); ++i)
|
||||
{
|
||||
if (i->value && i->value->parent == NULL && i->value != mRoot)
|
||||
{
|
||||
delete i->value;
|
||||
}
|
||||
}
|
||||
mKeyMap.clear();
|
||||
}
|
||||
|
||||
void TreeObject::initPersistFields()
|
||||
{
|
||||
addProtectedField("treeType", TypeString, Offset(mTreeType, TreeObject), &_setType, &defaultProtectedGetFn, "Set type by name.");
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void TreeObject::_internalSetType(const char* typeName)
|
||||
{
|
||||
if (!typeName || !typeName[0]) return;
|
||||
|
||||
ConsoleBaseType* newType = ConsoleBaseType::getTypeByName(typeName);
|
||||
|
||||
if (newType)
|
||||
mTreeType = newType;
|
||||
else
|
||||
Con::errorf("TreeObject: Invalid type '%s'. Use 'TypeS32', 'TypePoint3F', etc.", typeName);
|
||||
}
|
||||
|
||||
bool TreeObject::_setType(void* obj, const char* index, const char* data)
|
||||
{
|
||||
TreeObject* tree = static_cast<TreeObject*>(obj);
|
||||
if (tree != NULL)
|
||||
tree->_internalSetType(data);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TreeObject::setType(const char* typeName)
|
||||
{
|
||||
if (typeName && typeName[0])
|
||||
{
|
||||
ConsoleBaseType* newType = ConsoleBaseType::getTypeByName(typeName);
|
||||
if (newType)
|
||||
mTreeType = newType;
|
||||
else
|
||||
Con::errorf("TreeObject::setTreeType - Unknown console type '%s'! use listConsoleTypes for options", typeName);
|
||||
}
|
||||
}
|
||||
|
||||
S32 TreeObject::addNode(S32 parentKey, const char* scriptData, S32 forcedKey)
|
||||
{
|
||||
if (mTreeType == NULL)
|
||||
{
|
||||
Con::errorf("TreeObject::addNode - treeType not set. Cannot allocate node data.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
S32 finalKey = (forcedKey == -1) ? mNextFreeKey++ : forcedKey;
|
||||
|
||||
if (forcedKey != -1)
|
||||
{
|
||||
if (findNode(finalKey))
|
||||
{
|
||||
Con::errorf("TreeObject::addNode - Key collision! Key %d already exists.", finalKey);
|
||||
return -1;
|
||||
}
|
||||
if (finalKey >= mNextFreeKey)
|
||||
mNextFreeKey = finalKey + 1;
|
||||
}
|
||||
|
||||
void* newData = dMalloc(mTreeType->getTypeSize());
|
||||
dMemset(newData, 0, mTreeType->getTypeSize());
|
||||
|
||||
if (scriptData && scriptData[0])
|
||||
{
|
||||
const char* scriptArgv[] = { scriptData };
|
||||
mTreeType->setData(newData, 1, scriptArgv, NULL, 0);
|
||||
}
|
||||
|
||||
Node* newNode = new Node(finalKey, mTreeType);
|
||||
newNode->data = newData;
|
||||
|
||||
Node* parent = findNode(parentKey);
|
||||
if (parent)
|
||||
{
|
||||
parent->push_back(newNode);
|
||||
newNode->parent = parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mRoot == NULL)
|
||||
{
|
||||
mRoot = newNode;
|
||||
newNode->parent = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
mRoot->push_back(newNode);
|
||||
newNode->parent = mRoot;
|
||||
}
|
||||
}
|
||||
|
||||
mKeyMap.insert(finalKey, newNode);
|
||||
|
||||
return finalKey;
|
||||
}
|
||||
|
||||
void TreeObject::deleteNode(S32 key)
|
||||
{
|
||||
Node* node = findNode(key);
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
if (node == mRoot)
|
||||
{
|
||||
mRoot = NULL;
|
||||
}
|
||||
|
||||
_deleteNode(node, true);
|
||||
}
|
||||
|
||||
void TreeObject::_deleteNode(Node* node, bool unlinkFromMap)
|
||||
{
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
// Collect all keys in subtree for map cleanup
|
||||
Vector<S32> keysToRemove;
|
||||
if (unlinkFromMap)
|
||||
{
|
||||
node->forEachInSubtree([&keysToRemove](TreeNode<void*>* n) {
|
||||
Node* scriptNode = static_cast<Node*>(n);
|
||||
keysToRemove.push_back(scriptNode->key);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Remove from parent's children array
|
||||
node->nullParent();
|
||||
|
||||
// If deleting the root node, clear mRoot
|
||||
if (node == mRoot)
|
||||
mRoot = NULL;
|
||||
|
||||
// Delete the node (destructor handles children recursively)
|
||||
delete node;
|
||||
|
||||
// Clean up map entries
|
||||
if (unlinkFromMap)
|
||||
{
|
||||
for (U32 i = 0; i < keysToRemove.size(); i++)
|
||||
{
|
||||
mKeyMap.erase(keysToRemove[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TreeObject::Node* TreeObject::findNode(S32 key)
|
||||
{
|
||||
Map<S32, Node*>::Iterator iter = mKeyMap.find(key);
|
||||
return (iter != mKeyMap.end()) ? iter->value : NULL;
|
||||
}
|
||||
|
||||
S32 TreeObject::getParent(S32 key)
|
||||
{
|
||||
Node* n = findNode(key);
|
||||
if (n == NULL || n->parent == NULL)
|
||||
return -1;
|
||||
return static_cast<Node*>(n->getParent())->key;
|
||||
}
|
||||
|
||||
bool TreeObject::toParent(S32 key, S32 newParentKey)
|
||||
{
|
||||
Node* targetNode = findNode(key);
|
||||
Node* newParentNode = findNode(newParentKey);
|
||||
|
||||
if (!targetNode || !newParentNode || key == newParentKey)
|
||||
return false;
|
||||
|
||||
// Check for circular reference (prevent making ancestor a child)
|
||||
Node* checkNode = newParentNode;
|
||||
while (checkNode != NULL)
|
||||
{
|
||||
if (checkNode->key == key)
|
||||
return false;
|
||||
checkNode = static_cast<Node*>(checkNode->parent);
|
||||
}
|
||||
|
||||
// Remove from old parent and add to new parent
|
||||
targetNode->nullParent();
|
||||
targetNode->parent = newParentNode;
|
||||
newParentNode->push_back(targetNode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Vector<S32> TreeObject::getChildren(S32 key)
|
||||
{
|
||||
Vector<S32> keys;
|
||||
Node* n = findNode(key);
|
||||
if (n)
|
||||
{
|
||||
Vector<TreeNode<void*>*> children = n->getChildren();
|
||||
keys.reserve(children.size());
|
||||
for (U32 i = 0; i < children.size(); i++)
|
||||
keys.push_back(static_cast<Node*>(children[i])->key);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
Vector<S32> TreeObject::getSiblings(S32 key)
|
||||
{
|
||||
Vector<S32> keys;
|
||||
Node* n = findNode(key);
|
||||
if (n)
|
||||
{
|
||||
Vector<TreeNode<void*>*> siblings = n->getSiblings();
|
||||
keys.reserve(siblings.size());
|
||||
for (U32 i = 0; i < siblings.size(); i++)
|
||||
keys.push_back(static_cast<Node*>(siblings[i])->key);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
const char* TreeObject::nodesToString(const Vector<S32>& keys)
|
||||
{
|
||||
if (keys.empty())
|
||||
return "";
|
||||
|
||||
static const U32 bufSize = 1024;
|
||||
char* returnBuffer = Con::getReturnBuffer(bufSize);
|
||||
returnBuffer[0] = '\0';
|
||||
|
||||
bool first = true;
|
||||
for (S32 i = 0; i < keys.size(); i++)
|
||||
{
|
||||
char keyBuf[16];
|
||||
dSprintf(keyBuf, sizeof(keyBuf), "%d", keys[i]);
|
||||
|
||||
if (!first)
|
||||
dStrcat(returnBuffer, " ", bufSize);
|
||||
|
||||
dStrcat(returnBuffer, keyBuf, bufSize);
|
||||
first = false;
|
||||
}
|
||||
|
||||
return returnBuffer;
|
||||
}
|
||||
|
||||
const char* TreeObject::toString()
|
||||
{
|
||||
if (!mRoot || !mTreeType) return "";
|
||||
|
||||
const U32 bufSize = 16384;
|
||||
char* heapBuffer = (char*)dMalloc(bufSize);
|
||||
dMemset(heapBuffer, 0, bufSize);
|
||||
|
||||
dSprintf(heapBuffer, bufSize, "%s\n", mTreeType->getTypeName());
|
||||
U32 bufferPos = dStrlen(heapBuffer);
|
||||
|
||||
_toStringRecursive(mRoot, heapBuffer, bufferPos, bufSize);
|
||||
heapBuffer[bufferPos] = '\0';
|
||||
|
||||
char* returnBuffer = Con::getReturnBuffer(bufSize);
|
||||
dStrcpy(returnBuffer, heapBuffer, bufSize);
|
||||
dFree(heapBuffer);
|
||||
|
||||
return returnBuffer;
|
||||
}
|
||||
|
||||
void TreeObject::_toStringRecursive(Node* node, char* buffer, U32& bufferPos, U32 bufSize)
|
||||
{
|
||||
if (!node || bufferPos >= (bufSize - 1)) return;
|
||||
|
||||
char localDataStr[512] = "";
|
||||
if (node->data && node->type) {
|
||||
const char* tempStr = node->type->getData(node->data, NULL, 0);
|
||||
if (tempStr) {
|
||||
dStrncpy(localDataStr, tempStr, sizeof(localDataStr) - 1);
|
||||
localDataStr[sizeof(localDataStr) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
S32 pKey = (node->parent) ? static_cast<Node*>(node->parent)->key : -1;
|
||||
|
||||
char line[1024];
|
||||
dSprintf(line, sizeof(line), "%d %d \"%s\"\n", node->key, pKey, localDataStr);
|
||||
U32 lineLen = dStrlen(line);
|
||||
|
||||
if (bufferPos + lineLen < bufSize) {
|
||||
dStrcpy(buffer + bufferPos, line, bufSize - bufferPos);
|
||||
bufferPos += lineLen;
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < node->size(); i++) {
|
||||
Node* child = static_cast<Node*>((*node)[i]);
|
||||
_toStringRecursive(child, buffer, bufferPos, bufSize);
|
||||
}
|
||||
}
|
||||
|
||||
void TreeObject::fromString(const char* data)
|
||||
{
|
||||
if (!data || !*data)
|
||||
return;
|
||||
|
||||
|
||||
if (mRoot) {
|
||||
_deleteNode(mRoot, true);
|
||||
mRoot = NULL;
|
||||
}
|
||||
|
||||
mKeyMap.clear();
|
||||
mNextFreeKey = 0;
|
||||
|
||||
const char* pipe = dStrchr(data, '\n');
|
||||
if (pipe)
|
||||
{
|
||||
char typeName[256];
|
||||
U32 typeLen = pipe - data;
|
||||
if (typeLen > 1)
|
||||
{
|
||||
dStrncpy(typeName, data, typeLen);
|
||||
typeName[typeLen] = '\0';
|
||||
setType(typeName);
|
||||
}
|
||||
_fromStringRecursive(pipe + 1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
void TreeObject::_fromStringRecursive(const char* str, S32 ignored)
|
||||
{
|
||||
if (!str || !*str) return;
|
||||
const char* p = str;
|
||||
|
||||
while (*p) {
|
||||
while (*p && (*p == '\n' || *p == '\r' || *p == ' ')) p++;
|
||||
if (!*p) break;
|
||||
|
||||
S32 key = 0;
|
||||
S32 parentID = -1;
|
||||
char dataBuf[1024] = "";
|
||||
|
||||
if (dSscanf(p, "%d %d \"%[^\"]\"", &key, &parentID, dataBuf) < 3) {
|
||||
const char* nextLine = dStrchr(p, '\n');
|
||||
if (!nextLine) break;
|
||||
p = nextLine + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
addNode(parentID, dataBuf, key);
|
||||
const char* nextLine = dStrchr(p, '\n');
|
||||
if (!nextLine) break;
|
||||
p = nextLine + 1;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================
|
||||
DefineEngineMethod(TreeObject, setTreeType, void, (const char* typeName), ,
|
||||
"@brief Sets the data type for the tree at runtime.\n"
|
||||
"@param typeName The name of the type (e.g., 'Point3F', 'TransformF').")
|
||||
{
|
||||
object->setType(typeName);
|
||||
}
|
||||
|
||||
DefineEngineMethod(TreeObject, addNode, S32, (S32 parentKey, const char* data, S32 forcedKey), (-1),
|
||||
"@brief Adds a node to the hierarchy.\n"
|
||||
"@param parentKey The ID of the parent (-1 for root).\n"
|
||||
"@param data The data string (TransformF/Point3F).\n"
|
||||
"@param forcedKey Optional S32 ID. If -1, one is generated.\n"
|
||||
"@return The S32 key assigned to the node.")
|
||||
{
|
||||
return object->addNode(parentKey, data, forcedKey);
|
||||
}
|
||||
|
||||
DefineEngineMethod(TreeObject, deleteNode, void, (S32 key), ,
|
||||
"Removes a node and its entire subtree from the armature using its S32 key.")
|
||||
{
|
||||
object->deleteNode(key);
|
||||
}
|
||||
|
||||
DefineEngineMethod(TreeObject, getNode, const char*, (S32 key), ,
|
||||
"@brief Retrieves the data string stored in a specific node.\n"
|
||||
"@param key The unique ID of the node.\n"
|
||||
"@return The data string, or an empty string if the node/data is not found.")
|
||||
{
|
||||
TreeObject::Node* node = object->findNode(key);
|
||||
if (node && node->data && node->type)
|
||||
{
|
||||
const char* dataVal = node->type->getData(node->data, NULL, 0);
|
||||
return dataVal ? dataVal : "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
DefineEngineMethod(TreeObject, toParent, bool, (S32 key, S32 newParentKey), ,
|
||||
"@brief Shifts a node to a new parent in the hierarchy.\n"
|
||||
"@param key The ID of the node to move.\n"
|
||||
"@param newParentKey The ID of the new parent, or -1 for root.\n"
|
||||
"@return True on success.")
|
||||
{
|
||||
return object->toParent(key, newParentKey);
|
||||
}
|
||||
|
||||
DefineEngineMethod(TreeObject, getParent, S32, (S32 key), , "Returns parent key.")
|
||||
{
|
||||
return object->getParent(key);
|
||||
}
|
||||
|
||||
DefineEngineMethod(TreeObject, getChildren, const char*, (S32 key), , "Returns space-separated child keys.")
|
||||
{
|
||||
return object->nodesToString(object->getChildren(key));
|
||||
}
|
||||
|
||||
DefineEngineMethod(TreeObject, getNumChildren, S32, (S32 key), ,
|
||||
"@brief Returns the number of children attached to the node identified by key.\n"
|
||||
"@param key The S32 identifier of the node.")
|
||||
{
|
||||
return object->getNumChildren(key);
|
||||
}
|
||||
|
||||
DefineEngineMethod(TreeObject, getSiblings, const char*, (S32 key), , "Returns space-separated sibling keys.")
|
||||
{
|
||||
return object->nodesToString(object->getSiblings(key));
|
||||
}
|
||||
|
||||
DefineEngineMethod(TreeObject, getNumSiblings, S32, (S32 key), ,
|
||||
"@brief Returns the number of siblings for the node identified by key.\n"
|
||||
"@param key The S32 identifier of the node.")
|
||||
{
|
||||
return object->getNumSiblings(key);
|
||||
}
|
||||
|
||||
DefineEngineMethod(TreeObject, toString, const char*, (), ,
|
||||
"Serializes the tree to a single string with a type header.")
|
||||
{
|
||||
return object->toString();
|
||||
}
|
||||
|
||||
DefineEngineMethod(TreeObject, fromString, void, (const char* data), ,
|
||||
"Rebuilds the tree from a serialized string.")
|
||||
{
|
||||
object->fromString(data);
|
||||
}
|
||||
|
||||
|
||||
//==============================================================
|
||||
DefineEngineFunction(listConsoleTypes, void, (), , "Lists all registered ConsoleBaseTypes.")
|
||||
{
|
||||
for (ConsoleBaseType* type = ConsoleBaseType::getListHead(); type != NULL; type = type->getListNext())
|
||||
{
|
||||
Con::printf("%s", type->getTypeName());
|
||||
}
|
||||
}
|
||||
1219
Engine/source/core/util/treeObject.h
Normal file
1219
Engine/source/core/util/treeObject.h
Normal file
File diff suppressed because it is too large
Load diff
347
Engine/source/core/util/vectorObject.cpp
Normal file
347
Engine/source/core/util/vectorObject.cpp
Normal file
|
|
@ -0,0 +1,347 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "vectorObject.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(VectorObject);
|
||||
|
||||
void VectorObject::initPersistFields()
|
||||
{
|
||||
addProtectedField("varType", TypeString, Offset(mVarType, VectorObject), &_setType, &defaultProtectedGetFn, "Set type by name.");
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void VectorObject::_internalSetType(const char* typeName)
|
||||
{
|
||||
if (!typeName || !typeName[0]) return;
|
||||
|
||||
ConsoleBaseType* newType = ConsoleBaseType::getTypeByName(typeName);
|
||||
|
||||
if (newType)
|
||||
mVarType = newType;
|
||||
else
|
||||
Con::errorf("VectorObject: Invalid type '%s'. Use 'TypeS32', 'TypePoint3F', etc.", typeName);
|
||||
}
|
||||
|
||||
bool VectorObject::_setType(void* obj, const char* index, const char* data)
|
||||
{
|
||||
VectorObject* tree = static_cast<VectorObject*>(obj);
|
||||
if (tree != NULL)
|
||||
tree->_internalSetType(data);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void VectorObject::setType(const char* typeName)
|
||||
{
|
||||
if (typeName && typeName[0])
|
||||
{
|
||||
ConsoleBaseType* newType = ConsoleBaseType::getTypeByName(typeName);
|
||||
if (newType)
|
||||
mVarType = newType;
|
||||
else
|
||||
Con::errorf("VectorObject::setType - Unknown console type '%s'! use listConsoleTypes for options", typeName);
|
||||
}
|
||||
}
|
||||
|
||||
void* VectorObject::get(U32 index)
|
||||
{
|
||||
if (index >= mData.size())
|
||||
{
|
||||
Con::errorf("VectorObject::get - Index %d out of bounds (size: %d)", index, mData.size());
|
||||
return NULL;
|
||||
}
|
||||
return mData[index];
|
||||
}
|
||||
|
||||
void VectorObject::set(U32 index, void* data)
|
||||
{
|
||||
if (index >= mData.size())
|
||||
{
|
||||
Con::errorf("VectorObject::set - Index %d out of bounds (size: %d)", index, mData.size());
|
||||
return;
|
||||
}
|
||||
mData.set(data, index );
|
||||
}
|
||||
|
||||
void VectorObject::push_back(void* data)
|
||||
{
|
||||
mData.push_back(data);
|
||||
}
|
||||
|
||||
void VectorObject::insert(U32 index, void* data)
|
||||
{
|
||||
if (index > mData.size())
|
||||
{
|
||||
Con::errorf("VectorObject::insert - Index %d out of bounds (size: %d)", index, mData.size());
|
||||
return;
|
||||
}
|
||||
mData.insert(index, data);
|
||||
}
|
||||
|
||||
void VectorObject::erase(U32 index)
|
||||
{
|
||||
if (index >= mData.size())
|
||||
{
|
||||
Con::errorf("VectorObject::erase - Index %d out of bounds (size: %d)", index, mData.size());
|
||||
return;
|
||||
}
|
||||
mData.erase(index);
|
||||
}
|
||||
|
||||
void VectorObject::clear()
|
||||
{
|
||||
mData.clear();
|
||||
}
|
||||
|
||||
void VectorObject::fromString(char* dataString)
|
||||
{
|
||||
clear();
|
||||
|
||||
if (!mVarType || !dataString || !dataString[0])
|
||||
return;
|
||||
|
||||
String dataStr(dataString);
|
||||
Vector<String> tokens;
|
||||
dataStr.split(" \t\n\r", tokens);
|
||||
const U32 typeSize = 128;
|
||||
for (U32 i = 0; i < tokens.size(); ++i)
|
||||
{
|
||||
const char* tokenStr = tokens[i].c_str();
|
||||
|
||||
void* nativeVar = mVarType->getNativeVariable();
|
||||
Con::setData(mVarType->getTypeID(), nativeVar, 0, 1, &tokenStr);
|
||||
|
||||
void* persistentData = dMalloc(typeSize);
|
||||
dMemcpy(persistentData, nativeVar, typeSize);
|
||||
|
||||
mData.push_back(persistentData);
|
||||
}
|
||||
}
|
||||
|
||||
char* VectorObject::toString()
|
||||
{
|
||||
if (!mVarType || mData.empty())
|
||||
return "";
|
||||
|
||||
char* returnBuffer = Con::getReturnBuffer(16384);
|
||||
returnBuffer[0] = '\0';
|
||||
|
||||
for (U32 i = 0; i < mData.size(); ++i)
|
||||
{
|
||||
const char* valString = Con::getData(mVarType->getTypeID(), mData[i], 0);
|
||||
|
||||
if (!valString) continue;
|
||||
|
||||
if (i > 0)
|
||||
dStrcat(returnBuffer, " ", 16384);
|
||||
|
||||
dStrcat(returnBuffer, valString, 16384);
|
||||
}
|
||||
|
||||
return returnBuffer;
|
||||
}
|
||||
|
||||
//--- ENGINE METHODS ---//
|
||||
DefineEngineMethod(VectorObject, setType, void, (const char* typeName), ,
|
||||
"@brief Sets the data type for the vector at runtime.\n"
|
||||
"@param typeName The name of the type (e.g., 'Point3F', 'TransformF').")
|
||||
{
|
||||
object->setType(typeName);
|
||||
}
|
||||
|
||||
DefineEngineMethod(VectorObject, getType, const char*, (), ,
|
||||
"@brief Returns the name of the currently assigned ConsoleBaseType.\n"
|
||||
"@return The type name as a string.")
|
||||
{
|
||||
ConsoleBaseType* type = object->getVarType();
|
||||
return type ? type->getTypeName() : "";
|
||||
}
|
||||
|
||||
DefineEngineMethod(VectorObject, size, S32, (), ,
|
||||
"@brief Returns the number of elements in the vector.\n"
|
||||
"@return The number of elements.")
|
||||
{
|
||||
return object->size();
|
||||
}
|
||||
|
||||
DefineEngineMethod(VectorObject, clear, void, (), ,
|
||||
"@brief Clears all elements from the vector.")
|
||||
{
|
||||
object->clear();
|
||||
}
|
||||
|
||||
DefineEngineMethod(VectorObject, push_back, void, (const char* data), ,
|
||||
"@brief Appends an element to the end of the vector.\n"
|
||||
"@param data The data string (TransformF/Point3F/etc).")
|
||||
{
|
||||
if (!object->getVarType())
|
||||
{
|
||||
Con::errorf("VectorObject::push_back - No variable type set!");
|
||||
return;
|
||||
}
|
||||
const char* dataStr = data;
|
||||
void* nativeVar = object->getVarType()->getNativeVariable();
|
||||
Con::setData(object->getVarType()->getTypeID(), nativeVar, 0, 1, &dataStr);
|
||||
const U32 typeSize = 128;
|
||||
void* persistentData = dMalloc(typeSize);
|
||||
dMemcpy(persistentData, nativeVar, typeSize);
|
||||
object->push_back(persistentData);
|
||||
}
|
||||
|
||||
DefineEngineMethod(VectorObject, get, const char*, (S32 index), ,
|
||||
"@brief Retrieves an element from the vector.\n"
|
||||
"@param index The index of the element to retrieve.\n"
|
||||
"@return The data string (TransformF/Point3F/etc).")
|
||||
{
|
||||
if (!object->getVarType())
|
||||
{
|
||||
Con::errorf("VectorObject::get - No variable type set!");
|
||||
return "";
|
||||
}
|
||||
void* data = object->get(index);
|
||||
if (!data)
|
||||
return "";
|
||||
return Con::getData(object->getVarType()->getTypeID(), data, 0);
|
||||
}
|
||||
|
||||
DefineEngineMethod(VectorObject, set, void, (S32 index, const char* data), ,
|
||||
"@brief Sets an element in the vector.\n"
|
||||
"@param index The index of the element to set.\n"
|
||||
"@param data The data string (TransformF/Point3F/etc).")
|
||||
{
|
||||
if (!object->getVarType())
|
||||
{
|
||||
Con::errorf("VectorObject::set - No variable type set!");
|
||||
return;
|
||||
}
|
||||
const char* dataStr = data;
|
||||
void* nativeVar = object->getVarType()->getNativeVariable();
|
||||
Con::setData(object->getVarType()->getTypeID(), nativeVar, 0, 1, &dataStr);
|
||||
const U32 typeSize = 128;
|
||||
void* persistentData = dMalloc(typeSize);
|
||||
dMemcpy(persistentData, nativeVar, typeSize);
|
||||
object->set(index, persistentData);
|
||||
}
|
||||
|
||||
DefineEngineMethod(VectorObject, insert, void, (S32 index, const char* data), ,
|
||||
"@brief Inserts an element into the vector at the specified index.\n"
|
||||
"@param index The index at which to insert the element.\n"
|
||||
"@param data The data string (TransformF/Point3F/etc).")
|
||||
{
|
||||
if (!object->getVarType())
|
||||
{
|
||||
Con::errorf("VectorObject::insert - No variable type set!");
|
||||
return;
|
||||
}
|
||||
const char* dataStr = data;
|
||||
void* nativeVar = object->getVarType()->getNativeVariable();
|
||||
Con::setData(object->getVarType()->getTypeID(), nativeVar, 0, 1, &dataStr);
|
||||
const U32 typeSize = 128;
|
||||
void* persistentData = dMalloc(typeSize);
|
||||
dMemcpy(persistentData, nativeVar, typeSize);
|
||||
object->insert(index, persistentData);
|
||||
}
|
||||
|
||||
DefineEngineMethod(VectorObject, erase, void, (S32 index), ,
|
||||
"@brief Removes an element from the vector at the specified index.\n"
|
||||
"@param index The index of the element to remove.")
|
||||
{
|
||||
object->erase(index);
|
||||
}
|
||||
|
||||
DefineEngineMethod(VectorObject, fromString, void, (const char* data), ,
|
||||
"@brief Populates the vector from a space-separated string of data.\n"
|
||||
"@param data The space-separated data string.")
|
||||
{
|
||||
char* dataCopy = dStrdup(data);
|
||||
object->fromString(dataCopy);
|
||||
dFree(dataCopy);
|
||||
}
|
||||
|
||||
DefineEngineMethod(VectorObject, toString, const char*, (), ,
|
||||
"@brief Converts the vector's contents to a space-separated string.\n"
|
||||
"@return The space-separated data string.")
|
||||
{
|
||||
return object->toString();
|
||||
}
|
||||
|
||||
ConsoleType(TypeVector, TypeVector, VectorObject*, NULL)
|
||||
ImplementConsoleTypeCasters(TypeVector, VectorObject*);
|
||||
|
||||
ConsoleGetType(TypeVector)
|
||||
{
|
||||
VectorObject* vObj = *((VectorObject**)dptr);
|
||||
if (!vObj) return "";
|
||||
|
||||
// Returns "TypeName Element1 Element2 ..."
|
||||
const char* typeName = vObj->getVarType() ? vObj->getVarType()->getTypeName() : "TypeVoid";
|
||||
|
||||
static const U32 bufSize = 16384;
|
||||
char* returnBuffer = Con::getReturnBuffer(bufSize);
|
||||
dSprintf(returnBuffer, bufSize, "%s %s", typeName, vObj->toString());
|
||||
|
||||
return returnBuffer;
|
||||
}
|
||||
|
||||
ConsoleSetType(TypeVector)
|
||||
{
|
||||
if (argc < 1) return;
|
||||
|
||||
VectorObject** vObjPtr = (VectorObject**)dptr;
|
||||
VectorObject* vObj = *vObjPtr;
|
||||
|
||||
if (vObj)
|
||||
{
|
||||
// Tokenize the input: The first entry is the TYPE
|
||||
String dataStr(argv[0]);
|
||||
Vector<String> tokens;
|
||||
dataStr.split(" \t\n\r", tokens);
|
||||
|
||||
if (tokens.size() > 0)
|
||||
{
|
||||
// 1. Set the VarType from the first token (e.g., "TypePoint3F")
|
||||
vObj->setType(tokens[0].c_str());
|
||||
|
||||
// 2. Process the rest as elements
|
||||
if (tokens.size() > 1)
|
||||
{
|
||||
// Re-concatenate the remaining tokens into a data string
|
||||
String remainingData = "";
|
||||
for (U32 i = 1; i < tokens.size(); ++i)
|
||||
{
|
||||
remainingData += tokens[i];
|
||||
if (i < tokens.size() - 1) remainingData += " ";
|
||||
}
|
||||
vObj->fromString(const_cast<char*>(remainingData.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the field is currently null, attempt to resolve argv as an object name
|
||||
if (!Sim::findObject(argv[0], *vObjPtr))
|
||||
Con::warnf("TypeVector::setData - Could not resolve VectorObject: %s", argv[0]);
|
||||
}
|
||||
}
|
||||
63
Engine/source/core/util/vectorObject.h
Normal file
63
Engine/source/core/util/vectorObject.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _TVECTOROBJECT_H_
|
||||
#define _TVECTOROBJECT_H_
|
||||
|
||||
#include "console/simObject.h"
|
||||
|
||||
class VectorObject : public SimObject {
|
||||
typedef SimObject Parent;
|
||||
|
||||
protected:
|
||||
ConsoleBaseType* mVarType;
|
||||
Vector<void*> mData;
|
||||
public:
|
||||
VectorObject(): mVarType(NULL) {};
|
||||
DECLARE_CONOBJECT(VectorObject);
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
void _internalSetType(const char* typeName);
|
||||
static bool _setType(void* obj, const char* index, const char* data);
|
||||
void setType(const char* typeName);
|
||||
ConsoleBaseType* getVarType() { return mVarType; };
|
||||
|
||||
U32 size() const { return mData.size(); };
|
||||
void* get(U32 index);
|
||||
void set(U32 index, void* data);
|
||||
void push_back(void* data);
|
||||
void insert(U32 index, void* data);
|
||||
void erase(U32 index);
|
||||
void clear();
|
||||
void fromString(char* data);
|
||||
char* toString();
|
||||
};
|
||||
|
||||
DefineConsoleType(TypeVector, VectorObject*);
|
||||
|
||||
template<typename T>
|
||||
static inline S32 VecType() {
|
||||
return TYPEID<VectorObject*>();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -34,7 +34,8 @@ class ObjectProxy;
|
|||
class ObjectProxyList;
|
||||
class SceneLightingInterface;
|
||||
|
||||
template <class T> class Vector;
|
||||
template<typename T, U32 COUNT> struct CustomAllocator;
|
||||
template<typename T, U32 COUNT, typename Allocator> class Vector;
|
||||
typedef Vector<SceneLightingInterface*> SceneLightingInterfaces;
|
||||
|
||||
// List of available "systems" that the lighting kit can use
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ enum DriveType
|
|||
|
||||
// Some forward declares for later.
|
||||
class Point2I;
|
||||
template<class T> class Vector;
|
||||
|
||||
template<typename Signature> class Signal;
|
||||
struct InputEventInfo;
|
||||
|
||||
|
|
@ -245,10 +245,10 @@ namespace Platform
|
|||
bool isFullPath(const char *path);
|
||||
StringTableEntry makeRelativePathName(const char *path, const char *to);
|
||||
|
||||
String stripExtension( String fileName, Vector< String >& validExtensions );
|
||||
String stripExtension( String fileName, Vector<String, 0, CustomAllocator<String, 0> >& validExtensions );
|
||||
|
||||
bool dumpPath(const char *in_pBasePath, Vector<FileInfo>& out_rFileVector, S32 recurseDepth = -1);
|
||||
bool dumpDirectories( const char *path, Vector<StringTableEntry> &directoryVector, S32 depth = 0, bool noBasePath = false );
|
||||
bool dumpPath(const char *in_pBasePath, Vector<FileInfo, 0, CustomAllocator<FileInfo, 0> >& out_rFileVector, S32 recurseDepth = -1);
|
||||
bool dumpDirectories( const char *path, Vector<StringTableEntry, 0, CustomAllocator<StringTableEntry, 0> >&directoryVector, S32 depth = 0, bool noBasePath = false );
|
||||
bool hasSubDirectory( const char *pPath );
|
||||
bool getFileTimes(const char *filePath, FileTime *createTime, FileTime *modifyTime);
|
||||
bool isFile(const char *pFilePath);
|
||||
|
|
@ -285,8 +285,8 @@ namespace Platform
|
|||
extern struct VolumeInformation *PVolumeInformation;
|
||||
|
||||
// Volume functions.
|
||||
void getVolumeNamesList( Vector<const char*>& out_rNameVector, bool bOnlyFixedDrives = false );
|
||||
void getVolumeInformationList( Vector<VolumeInformation>& out_rVolumeInfoVector, bool bOnlyFixedDrives = false );
|
||||
void getVolumeNamesList(Vector<StringTableEntry, 0, CustomAllocator<StringTableEntry, 0> >& out_rNameVector, bool bOnlyFixedDrives = false );
|
||||
void getVolumeInformationList(Vector<VolumeInformation, 0, CustomAllocator<VolumeInformation, 0> >& out_rVolumeInfoVector, bool bOnlyFixedDrives = false );
|
||||
|
||||
struct SystemInfo_struct
|
||||
{
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ public:
|
|||
///
|
||||
/// @todo Rethink this so we don't have a private public.
|
||||
virtual bool create( const char *name, dsize_t size, U32 charset = TGE_ANSI_CHARSET ) = 0;
|
||||
static void enumeratePlatformFonts( Vector<StringTableEntry>& fonts, UTF16* fontFamily = NULL );
|
||||
static void enumeratePlatformFonts( Vector<StringTableEntry,0, CustomAllocator<StringTableEntry, 0>>& fonts, UTF16* fontFamily = NULL );
|
||||
};
|
||||
|
||||
extern PlatformFont *createPlatformFont(const char *name, dsize_t size, U32 charset = TGE_ANSI_CHARSET);
|
||||
|
|
|
|||
|
|
@ -336,13 +336,14 @@ void SceneObject::onRemove()
|
|||
{
|
||||
smSceneObjectRemove.trigger(this);
|
||||
|
||||
if (getParent() != NULL) attachToParent(NULL);
|
||||
unmount();
|
||||
plUnlink();
|
||||
|
||||
if (mContainer)
|
||||
mContainer->removeObject(this);
|
||||
|
||||
Parent::onRemove();
|
||||
// PATHSHAPE
|
||||
if ( getParent() != NULL) attachToParent( NULL);
|
||||
// PATHSHAPE END
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -395,7 +396,7 @@ void SceneObject::inspectPostApply()
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
void SceneObject::setGlobalBounds()
|
||||
{
|
||||
{
|
||||
mGlobalBounds = true;
|
||||
mObjBox.minExtents.set( -1e10, -1e10, -1e10 );
|
||||
mObjBox.maxExtents.set( 1e10, 1e10, 1e10 );
|
||||
|
|
@ -434,6 +435,7 @@ void SceneObject::setTransform( const MatrixF& mat )
|
|||
mSceneManager->notifyObjectDirty( this );
|
||||
|
||||
setRenderTransform( mat );
|
||||
setMountTransforms();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -1351,6 +1353,19 @@ void SceneObject::getRenderMountTransform( F32 delta, S32 index, const MatrixF &
|
|||
outMat->mul( mRenderObjToWorld, mountTransform );
|
||||
}
|
||||
|
||||
void SceneObject::setMountTransforms()
|
||||
{
|
||||
// Update all objects mounted to us
|
||||
for (SceneObject* mounted = mMount.list; mounted; mounted = mounted->mMount.link)
|
||||
{
|
||||
// Compute mounted object's new world transform
|
||||
MatrixF worldXfm;
|
||||
getMountTransform(mounted->mMount.node, mounted->mMount.xfm, &worldXfm);
|
||||
mounted->setTransform(worldXfm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// Console API.
|
||||
//=============================================================================
|
||||
|
|
@ -1666,7 +1681,8 @@ void SceneObject::moveRender(const Point3F &delta)
|
|||
void SceneObject::PerformUpdatesForChildren(MatrixF mat){
|
||||
for (U32 i=0; i < getNumChildren(); i++) {
|
||||
SceneObject *o = getChild(i);
|
||||
o->updateChildTransform(); //update the position of the child object
|
||||
if (!o->isMounted())
|
||||
o->updateChildTransform(); //update the position of the child object
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -674,6 +674,7 @@ class SceneObject : public NetObject, public ProcessObject
|
|||
|
||||
void resolveMountPID();
|
||||
|
||||
void setMountTransforms();
|
||||
/// @}
|
||||
|
||||
/// @name Sound
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue