| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526 |
- /*
- ** Command & Conquer Generals(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
- ***********************************************************************************************
- * *
- * Project Name : G *
- * *
- * $Archive:: /Commando/Code/Tools/max2w3d/SkinCopy.cpp $*
- * *
- * $Author:: Andre_a $*
- * *
- * $Modtime:: 11/03/99 11:51a $*
- * *
- * $Revision:: 3 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * find_skin_binding -- Find the "WWSkin Binding" modifier on this object. *
- * find_skin_wsm -- Finds the node for the WWSkin WSM used by this object. *
- * get_skin_wsm_obj -- Gets the SkinWSMObjectClass from a WWSkin WSM node. *
- * duplicate_wsm -- Duplicates a WWSkin WSM *
- * find_equivalent_node -- Searches a hierarchy for an object equivalent to the given one. *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- /*
- -- Copy the skin info for this object into the target object.
- -- If we haven't copied the WSM yet, it will be copied.
- new_wsm = wwCopySkinInfo source_root target_root new_wsm
- */
- #include <MaxScrpt.h> // Main MAXScript header
- #include <MaxObj.h> // MAX* Wrapper objects
- #include <definsfn.h> // def_* functions to create static function headers
- #include <Max.h>
- #include <modstack.h>
- #include "skin.h"
- #include "util.h"
- #include "w3d_file.h"
- /*
- ** Forward declarations
- */
- Value *find_skin_node_in_tree (INode *root);
- SkinModifierClass *find_skin_binding (INode *skinned_obj);
- INode *find_skin_wsm (INode *skinned_obj);
- SkinWSMObjectClass *get_skin_wsm_obj (INode *wsm_node);
- INode *duplicate_wsm (INode *skinned_obj, INode *tree_root);
- INode *find_equivalent_node (INode *source, INode *tree, bool name_is_valid = false);
- Value *copy_skin_info (INode *source, INode *target, INode *wsm);
- IDerivedObject *setup_wsm_derived_obj (INode *node);
- ModContext *find_skin_mod_context (INode *node);
- /*
- ** Let MAXScript know we're implementing a new built-in function.
- */
- def_visible_primitive(find_skin_node, "wwFindSkinNode");
- def_visible_primitive(copy_skin_info, "wwCopySkinInfo");
- def_visible_primitive(dupe_skin_wsm, "wwDuplicateSkinWSM");
- /*
- **
- ** MAXScript Function:
- ** wwFindSkinNode - Usage: wwFindSkinNode tree_root_node
- **
- ** Searches the given hierarchy tree for the node containing
- ** the WWSkin WSM. Returns the node if found, otherwise it
- ** returns undefined.
- **
- ** Used by the SceneSetup MAXScript.
- */
- Value *find_skin_node_cf (Value **arg_list, int count)
- {
- // Verify the number and type of the arguments.
- check_arg_count("wwFindSkinNode", 1, count);
- type_check(arg_list[0], MAXNode, "Tree Root INode");
- // Get the INode that was passed in.
- INode *tree_root = arg_list[0]->to_node();
- // Search the tree for the WWSkin WSM, and return
- // the node which references it.
- return find_skin_node_in_tree(tree_root);
- }
- /*
- **
- ** MAXScript Function:
- ** wwCopySkinInfo - Usage: wwCopySkinInfo from_node to_node wsm_node to_tree_root
- **
- ** Copies the skin info for the given node to the target node.
- ** If wsm_node is "undefined" then we will create a new WWSkin WSM
- ** with the same values as the one being used by from_node.
- ** If from_node doesn't have a WWSkin binding, the return value
- ** is "undefined". If the function succeeds, it returns the
- ** wsm_node (the new WSM if it was created, otherwise the old wsm_node).
- **
- ** Used by the SceneSetup MAXScript.
- */
- Value * copy_skin_info_cf (Value **arg_list, int count)
- {
- // Verify the number and type of the arguments.
- check_arg_count("wwCopySkinInfo", 4, count);
- type_check(arg_list[0], MAXNode, "Source INode");
- type_check(arg_list[1], MAXNode, "Target INode");
- type_check(arg_list[3], MAXNode, "Target Tree Root INode");
- // Get the INode pointers that were passed in.
- INode *src_node = arg_list[0]->to_node();
- INode *dest_node = arg_list[1]->to_node();
- INode *wsm_node = NULL;
- INode *tree_root = arg_list[3]->to_node();
- if (arg_list[2] == &undefined)
- {
- // Duplicate the WSM used by src_node.
- wsm_node = duplicate_wsm(find_skin_wsm(src_node), tree_root);
- if (wsm_node == NULL)
- return &undefined;
- }
- else
- wsm_node = arg_list[2]->to_node();
- return copy_skin_info(src_node, dest_node, wsm_node);
- }
- /*
- **
- ** MAXScript Function:
- ** wwDuplicateSkinWSM - Usage: wwDuplicateSkinWSM wwskin_wsm_node tree_root
- **
- ** Duplicates the given WWSkin WSM. tree_root is the root node of a hierarchy
- ** containing bones similar to the ones used by the given WSM. The hierarchy
- ** will be searched for equivalent bones (ie. names the same except their
- ** extension), and those bones will be used by the newly duplicated WSM.
- **
- ** Used by the SceneSetup MAXScript.
- */
- Value * dupe_skin_wsm_cf (Value **arg_list, int count)
- {
- // Verify the number and type of the arguments.
- check_arg_count("wwDuplicateSkinWSM", 2, count);
- type_check(arg_list[0], MAXNode, "WWSkin Object INode");
- type_check(arg_list[1], MAXNode, "Target Tree Root INode");
- // Get the INode pointers that were passed in.
- INode *wsm_node = arg_list[0]->to_node();
- INode *root_node = arg_list[1]->to_node();
- // Return the duplicated WWSkin WSM.
- INode *dupe = duplicate_wsm(wsm_node, root_node);
- if (!dupe)
- return &undefined;
- else
- {
- // Return the WSM.
- one_typed_value_local(Value* wsm_node);
- vl.wsm_node = MAXNode::intern(dupe);
- return_value(vl.wsm_node);
- }
- }
- Value *find_skin_node_in_tree (INode *root)
- {
- if (root == NULL)
- return &undefined;
- // Is this the node we're looking for?
- if (get_skin_wsm_obj(root))
- {
- one_typed_value_local(Value* wsm_node);
- vl.wsm_node = MAXNode::intern(root);
- return_value(vl.wsm_node);
- }
- // Search the children of this node.
- for (int i = 0; i < root->NumChildren(); i++)
- {
- Value *retval = find_skin_node_in_tree(root->GetChildNode(i));
- if (retval != &undefined)
- return retval;
- }
- // Didn't find it anywhere!
- return &undefined;
- }
- /***********************************************************************************************
- * find_skin_binding -- Find the "WWSkin Binding" modifier on this object. *
- * *
- * INPUT: The skinned object. *
- * *
- * OUTPUT: The skin modifier, or NULL if one doesn't exist. *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/19/1999 AJA : Created. *
- *=============================================================================================*/
- SkinModifierClass *find_skin_binding (INode *skinned_obj)
- {
- // WWSkin Binding ties us to a space warp, so search the node's
- // WSM Derived Object for the WWSkin Binding modifier.
- IDerivedObject *dobj = skinned_obj->GetWSMDerivedObject();
- if (dobj == NULL)
- return NULL; // not bound to a space warp
- // Search for the WWSkin Binding modifier on this derived object.
- for (int i = 0; i < dobj->NumModifiers(); i++)
- {
- Modifier *mod = dobj->GetModifier(i);
- if (mod->ClassID() != SKIN_MOD_CLASS_ID)
- continue;
- // We found the skin modifier.
- return (SkinModifierClass*)mod;
- }
- // Skin modifier not found.
- return NULL;
- }
- /***********************************************************************************************
- * find_skin_wsm -- Finds the node for the WWSkin WSM used by this object. *
- * *
- * INPUT: The node of an object with a WWSkin Binding. *
- * *
- * OUTPUT: The node of the WWSkin WSM referenced by the given object. *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/18/1999 AJA : Created. *
- *=============================================================================================*/
- INode *find_skin_wsm (INode *skinned_obj)
- {
- // Find the skin modifier on this object.
- SkinModifierClass *skin_mod = find_skin_binding(skinned_obj);
- if (skin_mod == NULL)
- return NULL;
- // Using the skin modifer, find the WSM's INode.
- INode *wsm = (INode*)( skin_mod->GetReference(SkinModifierClass::NODE_REF) );
- if (wsm == NULL)
- {
- char buf[256];
- sprintf(buf, "%s has a WWSkin Binding, but I can't find its WWSkin WSM!",
- skinned_obj->GetName());
- throw RuntimeError(buf);
- }
- return wsm;
- }
- /***********************************************************************************************
- * get_skin_wsm_obj -- Gets the SkinWSMObjectClass from a WWSkin WSM node. *
- * *
- * INPUT: The node for the WWSkin WSM's representation in the scene. *
- * *
- * OUTPUT: The SkinWSMObjectClass. *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/18/1999 AJA : Created. *
- *=============================================================================================*/
- SkinWSMObjectClass *get_skin_wsm_obj (INode *wsm_node)
- {
- // We need a valid node.
- if (!wsm_node)
- return NULL;
- // The node must reference an object.
- Object *obj = wsm_node->GetObjectRef();
- if (!obj)
- return NULL;
- // That BASE object must be a SkinWSMObject
- while (obj)
- {
- // If this is a derived object, burrow deeper,
- // otherwise we're at the base object.
- if (obj->SuperClassID() == GEN_DERIVOB_CLASS_ID)
- obj = ((IDerivedObject*)obj)->GetObjRef();
- else
- break;
- }
- if (obj->ClassID() != SKIN_OBJ_CLASS_ID)
- return NULL;
- // Return it.
- return (SkinWSMObjectClass*)obj;
- }
- /***********************************************************************************************
- * duplicate_wsm -- Duplicates a WWSkin WSM *
- * *
- * INPUT: wsm_node - INode of the WWSkin WSM object. *
- * tree - The root of a tree containing equivalents of the bones in the WWSkin used *
- * by skinned_obj. The bone names must be the same (after being processed by *
- * Set_W3D_Name() *
- * *
- * OUTPUT: The node of the newly duplicated WWSkin WSM. *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/18/1999 AJA : Created. *
- * 11/3/1999 AJA : Changed first argument from skinned_obj to wsm_node. *
- *=============================================================================================*/
- INode *duplicate_wsm (INode *wsm_node, INode *tree)
- {
- SkinWSMObjectClass *wsm_obj = get_skin_wsm_obj(wsm_node);
- if (!wsm_node || !wsm_obj)
- return NULL;
- /*
- ** Duplicate the WSM.
- */
- SkinWSMObjectClass *new_wsm_obj =
- (SkinWSMObjectClass*)CreateInstance(WSM_OBJECT_CLASS_ID, SKIN_OBJ_CLASS_ID);
- if (!new_wsm_obj)
- return NULL;
- // Create a new node in the scene that points to the new WSM object.
- INode *new_wsm_node = MAXScript_interface->CreateObjectNode(new_wsm_obj);
- if (!new_wsm_node)
- return NULL;
- // Copy the bones from one to the other.
- for (int i = 0; i < wsm_obj->Num_Bones(); i++)
- {
- INode *src_bone = wsm_obj->Get_Bone(i);
- INode *dst_bone = find_equivalent_node(src_bone, tree);
- if (!src_bone || !dst_bone)
- return NULL;
- new_wsm_obj->Add_Bone(dst_bone);
- }
- // Return a pointer to the new WSM node.
- return new_wsm_node;
- }
- /***********************************************************************************************
- * find_equivalent_node -- Searches a hierarchy for an object equivalent to the given one. *
- * *
- * INPUT: source - The node to search for an equivalent of. *
- * tree - The hierarchy to search in. *
- * *
- * OUTPUT: The equivalent node, or NULL if none was found. *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/19/1999 AJA : Created. *
- *=============================================================================================*/
- INode *find_equivalent_node (INode *source, INode *tree, bool name_is_valid)
- {
- // We need a valid source and tree.
- if (!source || !tree)
- return NULL;
- // The name of the source object. We'll only evaluate this once as an easy optimization.
- static char src_name[W3D_NAME_LEN];
- if (!name_is_valid)
- Set_W3D_Name(src_name, source->GetName());
- // The name of the current object we're examining.
- char chk_name[W3D_NAME_LEN];
- Set_W3D_Name(chk_name, tree->GetName());
- // Is this the node we're looking for?
- if (strcmp(src_name, chk_name) == 0)
- return tree; // Yup, sure is.
- // Nope. Check its children.
- for (int i = 0; i < tree->NumberOfChildren(); i++)
- {
- INode *retval = find_equivalent_node(source, tree->GetChildNode(i), true);
- if (retval != NULL)
- return retval; // we found the node in our children
- }
- // No equivalent node was found.
- return NULL;
- }
- Value *copy_skin_info (INode *source, INode *target, INode *wsm)
- {
- // Get the "WWSkin Binding" modifier on the source object.
- SkinModifierClass *source_modifier = find_skin_binding(source);
- if (source_modifier == NULL)
- return &undefined;
- // Get the WSMDerivedObject we can add our skin binding modifier to.
- IDerivedObject *dobj = setup_wsm_derived_obj(target);
- // Create a new skin modifier and copy the source modifier's settings to it.
- SkinModifierClass *new_modifier = new SkinModifierClass(wsm, get_skin_wsm_obj(wsm));
- if (new_modifier == NULL)
- throw RuntimeError("Out of memory - Unable to allocate a new SkinModifierClass object!");
- new_modifier->SubObjSelLevel = source_modifier->SubObjSelLevel;
- // Dupe the mod context, especially the local mod data hanging off of it.
- ModContext *source_context = find_skin_mod_context(source);
- ModContext *new_context = new ModContext(source_context->tm, source_context->box,
- source_context->localData);
- if (new_context == NULL)
- throw RuntimeError("Out of memory - Unable to allocate a new ModContext object!");
- // Add a new "WWSkin Binding" modifier to the target object to associate
- // the object with the skin WSM. All of the settings should be correct,
- // and the target object becomes a "skinned object".
- dobj->AddModifier(new_modifier, new_context);
- // Return the WSM.
- one_typed_value_local(Value* wsm_node);
- vl.wsm_node = MAXNode::intern(wsm);
- return_value(vl.wsm_node);
- }
- IDerivedObject *setup_wsm_derived_obj (INode *node)
- {
- // Check if the target object is already bound to a space warp.
- IDerivedObject *dobj = node->GetWSMDerivedObject();
- if (dobj != NULL)
- {
- // It's bound to a space warp. Check if WWSkin is one of the
- // space warp bindings. If so, remove it (we don't want to
- // be bound to an old skin).
- for (int i = 0; i < dobj->NumModifiers(); i++)
- {
- Modifier *mod = dobj->GetModifier(i);
- if (mod->ClassID() != SKIN_MOD_CLASS_ID)
- continue;
- // We found the skin modifier, remove it.
- dobj->DeleteModifier(i);
- break;
- }
- }
- else
- {
- // This object isn't bound to a space warp. Create a
- // WSMDerivedObject for the node to play with.
- dobj = CreateWSDerivedObject(node->GetObjectRef());
- if (dobj == NULL)
- {
- char msg[128];
- sprintf(msg, "Error setting up the WSMDerivedObject for %s", node->GetName());
- throw RuntimeError(msg);
- }
- node->SetObjectRef(dobj);
- }
- return dobj;
- }
- ModContext *find_skin_mod_context (INode *node)
- {
- // We need a valid node
- if (node == NULL)
- return NULL;
- // The node needs to be bound to a space warp (ie. must have
- // a WSMDerivedObject).
- IDerivedObject *dobj = node->GetWSMDerivedObject();
- if (dobj == NULL)
- return NULL;
- // It's bound to a space warp. Find the WWSkin modifier.
- for (int i = 0; i < dobj->NumModifiers(); i++)
- {
- Modifier *mod = dobj->GetModifier(i);
- if (mod->ClassID() != SKIN_MOD_CLASS_ID)
- continue;
- // We found the skin modifier, return its mod context.
- return dobj->GetModContext(i);
- }
- // We didn't find a WWSkin binding.
- return NULL;
- }
|