From a46779fad6562e4deade6102945c7a740131efca Mon Sep 17 00:00:00 2001 From: James Urquhart Date: Sat, 3 Sep 2016 10:41:25 +0100 Subject: [PATCH] Defer re-init'ing the shape when TSShapeConstructor is loading a shape --- Engine/source/ts/tsShape.cpp | 80 ++++++++++++++------------ Engine/source/ts/tsShape.h | 12 +++- Engine/source/ts/tsShapeConstruct.cpp | 27 ++++++++- Engine/source/ts/tsShapeConstruct.h | 13 ++++- Engine/source/ts/tsShapeEdit.cpp | 82 +++++++++++++++++---------- 5 files changed, 143 insertions(+), 71 deletions(-) diff --git a/Engine/source/ts/tsShape.cpp b/Engine/source/ts/tsShape.cpp index ff55766c2..6f0bc94a0 100644 --- a/Engine/source/ts/tsShape.cpp +++ b/Engine/source/ts/tsShape.cpp @@ -71,6 +71,7 @@ TSShape::TSShape() mShapeDataSize = 0; mUseDetailFromScreenError = false; + mNeedReinit = false; mDetailLevelLookup.setSize( 1 ); mDetailLevelLookup[0].set( -1, 0 ); @@ -413,43 +414,51 @@ void TSShape::getObjectDetails(S32 objIndex, Vector& objDetails) void TSShape::init() { - S32 numSubShapes = subShapeFirstNode.size(); - AssertFatal(numSubShapes==subShapeFirstObject.size(),"TSShape::init"); + initObjects(); + initVertexFeatures(); + initMaterialList(); + mNeedReinit = false; +} - S32 i,j; +void TSShape::initObjects() +{ + S32 numSubShapes = subShapeFirstNode.size(); + AssertFatal(numSubShapes == subShapeFirstObject.size(), "TSShape::initObjects"); + + S32 i, j; // set up parent/child relationships on nodes and objects - for (i=0; i=0) + if (parentIndex >= 0) { if (nodes[parentIndex].firstChild<0) - nodes[parentIndex].firstChild=i; + nodes[parentIndex].firstChild = i; else { S32 child = nodes[parentIndex].firstChild; - while (nodes[child].nextSibling>=0) + while (nodes[child].nextSibling >= 0) child = nodes[child].nextSibling; nodes[child].nextSibling = i; } } } - for (i=0; i=0) + if (nodeIndex >= 0) { if (nodes[nodeIndex].firstObject<0) nodes[nodeIndex].firstObject = i; else { S32 objectIndex = nodes[nodeIndex].firstObject; - while (objects[objectIndex].nextSibling>=0) + while (objects[objectIndex].nextSibling >= 0) objectIndex = objects[objectIndex].nextSibling; objects[objectIndex].nextSibling = i; } @@ -457,7 +466,7 @@ void TSShape::init() } mFlags = 0; - for (i=0; i=0; i--) + for (i = mSmallestVisibleDL - 1; i >= 0; i--) { if (igetNumPolys() : 0; } } @@ -555,11 +564,11 @@ void TSShape::init() { ConvexHullAccelerator* accel = detailCollisionAccelerators[dca]; if (accel != NULL) { - delete [] accel->vertexList; - delete [] accel->normalList; + delete[] accel->vertexList; + delete[] accel->normalList; for (S32 j = 0; j < accel->numVerts; j++) - delete [] accel->emitStrings[j]; - delete [] accel->emitStrings; + delete[] accel->emitStrings[j]; + delete[] accel->emitStrings; delete accel; } } @@ -580,7 +589,7 @@ void TSShape::init() { Con::warnf("Mesh %i has a bad parentMeshObject (%i)", iter - meshes.begin(), mesh->parentMesh); } - + if (mesh->parentMesh >= 0 && mesh->parentMesh < meshes.size()) { mesh->parentMeshObject = meshes[mesh->parentMesh]; @@ -592,9 +601,6 @@ void TSShape::init() mesh->mVertexFormat = &mVertexFormat; } - - initVertexFeatures(); - initMaterialList(); } void TSShape::initVertexBuffers() diff --git a/Engine/source/ts/tsShape.h b/Engine/source/ts/tsShape.h index 09a5a84f1..e72dd8617 100644 --- a/Engine/source/ts/tsShape.h +++ b/Engine/source/ts/tsShape.h @@ -413,6 +413,7 @@ class TSShape GFXPrimitiveBufferHandle mShapeVertexIndices; bool mSequencesConstructed; + bool mNeedReinit; // shape class has few methods -- @@ -427,7 +428,10 @@ class TSShape bool preloadMaterialList(const Torque::Path &path); ///< called to preload and validate the materials in the mat list void setupBillboardDetails( const String &cachePath ); - + + /// Inits object list (no geometry buffers) + void initObjects(); + /// Initializes the main vertex buffer void initVertexBuffers(); @@ -557,8 +561,6 @@ class TSShape const GFXVertexFormat* getVertexFormat() const { return &mVertexFormat; } - bool needsBufferUpdate(); - /// @} /// @name Alpha Transitions @@ -685,6 +687,10 @@ class TSShape bool setSequenceBlend(const String& seqName, bool blend, const String& blendRefSeqName, S32 blendRefFrame); bool setSequenceGroundSpeed(const String& seqName, const Point3F& trans, const Point3F& rot); + + void makeEditable(); + bool needsReinit(); + bool needsBufferUpdate(); /// @} }; diff --git a/Engine/source/ts/tsShapeConstruct.cpp b/Engine/source/ts/tsShapeConstruct.cpp index da93d9691..dd2a67644 100644 --- a/Engine/source/ts/tsShapeConstruct.cpp +++ b/Engine/source/ts/tsShapeConstruct.cpp @@ -86,6 +86,11 @@ void TSShapeConstructor::_onTSShapeLoaded( Resource< TSShape >& resource ) TSShapeConstructor* ctor = findShapeConstructor( resource.getPath().getFullPath() ); if( ctor ) ctor->_onLoad( resource ); + + if (ctor && ctor->mShape && ctor->mShape->needsReinit()) + { + ctor->mShape->init(); + } } void TSShapeConstructor::_onTSShapeUnloaded( const Torque::Path& path, TSShape* shape ) @@ -128,7 +133,7 @@ static void SplitSequencePathAndName( String& srcPath, String& srcName ) IMPLEMENT_CONOBJECT(TSShapeConstructor); TSShapeConstructor::TSShapeConstructor() - : mShapePath("") + : mShapePath(""), mLoadingShape(false) { mShape = NULL; } @@ -374,9 +379,15 @@ bool TSShapeConstructor::onAdd() // If an instance of this shape has already been loaded, call onLoad now Resource shape = ResourceManager::get().find( mShapePath ); + if ( shape ) _onLoad( shape ); + if (mShape && mShape->needsReinit()) + { + mShape->init(); + } + return true; } @@ -394,6 +405,7 @@ void TSShapeConstructor::_onLoad(TSShape* shape) mShape = shape; mChangeSet.clear(); + mLoadingShape = true; // Add sequences defined using field syntax for ( S32 i = 0; i < mSequences.size(); i++ ) @@ -411,6 +423,7 @@ void TSShapeConstructor::_onLoad(TSShape* shape) // Call script function onLoad_callback(); + mLoadingShape = false; } //----------------------------------------------------------------------------- @@ -3279,3 +3292,15 @@ bool TSShapeConstructor::ChangeSet::addCmd_removeImposter( const TSShapeConstruc return true; } + +void TSShapeConstructor::onActionPerformed() +{ + // Reinit shape if we modify stuff in the shape editor, otherwise delay + if (!mLoadingShape) + { + if (mShape && mShape->needsReinit()) + { + mShape->init(); + } + } +} diff --git a/Engine/source/ts/tsShapeConstruct.h b/Engine/source/ts/tsShapeConstruct.h index 640c80c91..24dffe0da 100644 --- a/Engine/source/ts/tsShapeConstruct.h +++ b/Engine/source/ts/tsShapeConstruct.h @@ -246,6 +246,7 @@ public: TSShape* mShape; // Edited shape; NULL while not loaded; not a Resource as we don't want it to prevent from unloading. ColladaUtils::ImportOptions mOptions; + bool mLoadingShape; public: @@ -261,6 +262,7 @@ public: bool onAdd(); void onScriptChanged(const Torque::Path& path); + void onActionPerformed(); bool writeField(StringTableEntry fieldname, const char *value); void writeChangeSet(); @@ -383,8 +385,16 @@ typedef domUpAxisType TSShapeConstructorUpAxis; typedef ColladaUtils::ImportOptions::eLodType TSShapeConstructorLodType; DefineEnumType( TSShapeConstructorUpAxis ); -DefineEnumType( TSShapeConstructorLodType ); +DefineEnumType(TSShapeConstructorLodType); +class TSShapeConstructorMethodActionCallback +{ + TSShapeConstructor* mObject; + +public: + TSShapeConstructorMethodActionCallback(TSShapeConstructor *object) : mObject(object) { ; } + ~TSShapeConstructorMethodActionCallback() { mObject->onActionPerformed(); } +}; /* This macro simplifies the definition of a TSShapeConstructor API method. It wraps the actual EngineMethod definition and automatically calls the real @@ -403,6 +413,7 @@ DefineEnumType( TSShapeConstructorLodType ); Con::errorf( "TSShapeConstructor::" #name " - shape not loaded" ); \ return defRet; \ } \ + TSShapeConstructorMethodActionCallback actionCallback(object); \ return object->name rawArgs ; \ } \ /* Define the real TSShapeConstructor method */ \ diff --git a/Engine/source/ts/tsShapeEdit.cpp b/Engine/source/ts/tsShapeEdit.cpp index 32a9792a2..94379de4d 100644 --- a/Engine/source/ts/tsShapeEdit.cpp +++ b/Engine/source/ts/tsShapeEdit.cpp @@ -435,6 +435,9 @@ bool TSShape::addNode(const String& name, const String& parentName, const Point3 } } + // Need to make everything editable since node indexes etc will change + makeEditable(); + // Insert node at the end of the subshape S32 subShapeIndex = (parentIndex >= 0) ? getSubShapeForNode(parentIndex) : 0; S32 nodeIndex = subShapeNumNodes[subShapeIndex]; @@ -493,8 +496,7 @@ bool TSShape::addNode(const String& name, const String& parentName, const Point3 } } - // Re-initialise the shape - init(); + initObjects(); return true; } @@ -548,6 +550,9 @@ bool TSShape::removeNode(const String& name) ((nodeParentIndex >= 0) ? getName(nodes[nodeParentIndex].nameIndex).c_str() : "null")); } + // Need to make everything editable since node indexes etc will change + makeEditable(); + // Update animation sequences for (S32 iSeq = 0; iSeq < sequences.size(); iSeq++) { @@ -626,8 +631,7 @@ bool TSShape::removeNode(const String& name) // Remove the sequence name if it is no longer in use removeName(name); - // Re-initialise the shape - init(); + initObjects(); return true; } @@ -855,6 +859,9 @@ bool TSShape::removeObject(const String& name) return false; } + // Need to make everything editable since node indexes etc will change + makeEditable(); + // Destroy all meshes in the object TSShape::Object& obj = objects[objIndex]; while ( obj.numMeshes ) @@ -893,14 +900,7 @@ bool TSShape::removeObject(const String& name) // Update smallest visible detail updateSmallestVisibleDL(); - // Ensure shape is dirty - if (meshes[0]) - { - meshes[0]->makeEditable(); - } - - // Re-initialise the shape - init(); + initObjects(); return true; } @@ -961,6 +961,9 @@ bool TSShape::addMesh(TSMesh* mesh, const String& meshName) // Ensure mesh is in editable state mesh->makeEditable(); + // Need to make everything editable since node indexes etc will change + makeEditable(); + // Determine the object name and detail size from the mesh name S32 detailSize = 999; String objName(String::GetTrailingNumber(meshName, detailSize)); @@ -1049,8 +1052,7 @@ bool TSShape::addMesh(TSMesh* mesh, const String& meshName) } } - // Re-initialise the shape - init(); + initObjects(); return true; } @@ -1140,6 +1142,9 @@ bool TSShape::setMeshSize(const String& meshName, S32 size) return false; } + // Need to make everything editable since node indexes etc will change + makeEditable(); + // Remove the mesh from the object, but don't destroy it TSShape::Object& obj = objects[objIndex]; TSMesh* mesh = meshes[obj.startMeshIndex + meshIndex]; @@ -1151,8 +1156,7 @@ bool TSShape::setMeshSize(const String& meshName, S32 size) // Update smallest visible detail updateSmallestVisibleDL(); - // Re-initialise the shape - init(); + initObjects(); return true; } @@ -1167,6 +1171,9 @@ bool TSShape::removeMesh(const String& meshName) return false; } + // Need to make everything editable since node indexes etc will change + makeEditable(); + // Destroy and remove the mesh TSShape::Object& obj = objects[objIndex]; destructInPlace(meshes[obj.startMeshIndex + meshIndex]); @@ -1179,8 +1186,7 @@ bool TSShape::removeMesh(const String& meshName) // Update smallest visible detail updateSmallestVisibleDL(); - // Re-initialise the shape - init(); + initObjects(); return true; } @@ -1294,8 +1300,8 @@ S32 TSShape::setDetailSize(S32 oldSize, S32 newSize) // Update smallest visible detail updateSmallestVisibleDL(); - // Re-initialise the shape - init(); + // Nothing major, just reint object lists + initObjects(); return newIndex; } @@ -1310,6 +1316,9 @@ bool TSShape::removeDetail( S32 size ) return false; } + // Need to make everything editable since node indexes etc will change + makeEditable(); + // Destroy and remove each mesh in the detail level for ( S32 objIndex = objects.size()-1; objIndex >= 0; objIndex-- ) { @@ -1339,17 +1348,10 @@ bool TSShape::removeDetail( S32 size ) billboardDetails.erase( dl ); } - // Ensure shape is dirty - if (meshes[0]) - { - meshes[0]->makeEditable(); - } - // Update smallest visible detail updateSmallestVisibleDL(); - // Re-initialise the shape - init(); + initObjects(); return true; } @@ -2115,7 +2117,7 @@ bool TSShape::setSequenceGroundSpeed(const String& seqName, const Point3F& trans // Fixup ground frame indices seq.numGroundFrames += frameAdjust; - for (S32 i = seqIndex+1; i < sequences.size(); i++) + for (S32 i = seqIndex + 1; i < sequences.size(); i++) sequences[i].firstGroundFrame += frameAdjust; // Generate the ground-frames @@ -2140,3 +2142,25 @@ bool TSShape::setSequenceGroundSpeed(const String& seqName, const Point3F& trans return true; } + +void TSShape::makeEditable() +{ + mNeedReinit = true; + if (mShapeVertexData.base == NULL) + return; + + for (U32 i = 0; i < meshes.size(); i++) + { + if (meshes[i]) + { + meshes[i]->makeEditable(); + } + } + + mShapeVertexData.set(NULL, 0); +} + +bool TSShape::needsReinit() +{ + return mVertexSize == 0 || mShapeVertexData.base == NULL || mNeedReinit; +}