SkinCopy.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : G *
  23. * *
  24. * $Archive:: /Commando/Code/Tools/max2w3d/SkinCopy.cpp $*
  25. * *
  26. * $Author:: Andre_a $*
  27. * *
  28. * $Modtime:: 11/03/99 11:51a $*
  29. * *
  30. * $Revision:: 3 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * find_skin_binding -- Find the "WWSkin Binding" modifier on this object. *
  35. * find_skin_wsm -- Finds the node for the WWSkin WSM used by this object. *
  36. * get_skin_wsm_obj -- Gets the SkinWSMObjectClass from a WWSkin WSM node. *
  37. * duplicate_wsm -- Duplicates a WWSkin WSM *
  38. * find_equivalent_node -- Searches a hierarchy for an object equivalent to the given one. *
  39. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  40. /*
  41. -- Copy the skin info for this object into the target object.
  42. -- If we haven't copied the WSM yet, it will be copied.
  43. new_wsm = wwCopySkinInfo source_root target_root new_wsm
  44. */
  45. #include <MaxScrpt.h> // Main MAXScript header
  46. #include <MaxObj.h> // MAX* Wrapper objects
  47. #include <definsfn.h> // def_* functions to create static function headers
  48. #include <Max.h>
  49. #include <modstack.h>
  50. #include "skin.h"
  51. #include "util.h"
  52. #include "w3d_file.h"
  53. /*
  54. ** Forward declarations
  55. */
  56. Value *find_skin_node_in_tree (INode *root);
  57. SkinModifierClass *find_skin_binding (INode *skinned_obj);
  58. INode *find_skin_wsm (INode *skinned_obj);
  59. SkinWSMObjectClass *get_skin_wsm_obj (INode *wsm_node);
  60. INode *duplicate_wsm (INode *skinned_obj, INode *tree_root);
  61. INode *find_equivalent_node (INode *source, INode *tree, bool name_is_valid = false);
  62. Value *copy_skin_info (INode *source, INode *target, INode *wsm);
  63. IDerivedObject *setup_wsm_derived_obj (INode *node);
  64. ModContext *find_skin_mod_context (INode *node);
  65. /*
  66. ** Let MAXScript know we're implementing a new built-in function.
  67. */
  68. def_visible_primitive(find_skin_node, "wwFindSkinNode");
  69. def_visible_primitive(copy_skin_info, "wwCopySkinInfo");
  70. def_visible_primitive(dupe_skin_wsm, "wwDuplicateSkinWSM");
  71. /*
  72. **
  73. ** MAXScript Function:
  74. ** wwFindSkinNode - Usage: wwFindSkinNode tree_root_node
  75. **
  76. ** Searches the given hierarchy tree for the node containing
  77. ** the WWSkin WSM. Returns the node if found, otherwise it
  78. ** returns undefined.
  79. **
  80. ** Used by the SceneSetup MAXScript.
  81. */
  82. Value *find_skin_node_cf (Value **arg_list, int count)
  83. {
  84. // Verify the number and type of the arguments.
  85. check_arg_count("wwFindSkinNode", 1, count);
  86. type_check(arg_list[0], MAXNode, "Tree Root INode");
  87. // Get the INode that was passed in.
  88. INode *tree_root = arg_list[0]->to_node();
  89. // Search the tree for the WWSkin WSM, and return
  90. // the node which references it.
  91. return find_skin_node_in_tree(tree_root);
  92. }
  93. /*
  94. **
  95. ** MAXScript Function:
  96. ** wwCopySkinInfo - Usage: wwCopySkinInfo from_node to_node wsm_node to_tree_root
  97. **
  98. ** Copies the skin info for the given node to the target node.
  99. ** If wsm_node is "undefined" then we will create a new WWSkin WSM
  100. ** with the same values as the one being used by from_node.
  101. ** If from_node doesn't have a WWSkin binding, the return value
  102. ** is "undefined". If the function succeeds, it returns the
  103. ** wsm_node (the new WSM if it was created, otherwise the old wsm_node).
  104. **
  105. ** Used by the SceneSetup MAXScript.
  106. */
  107. Value * copy_skin_info_cf (Value **arg_list, int count)
  108. {
  109. // Verify the number and type of the arguments.
  110. check_arg_count("wwCopySkinInfo", 4, count);
  111. type_check(arg_list[0], MAXNode, "Source INode");
  112. type_check(arg_list[1], MAXNode, "Target INode");
  113. type_check(arg_list[3], MAXNode, "Target Tree Root INode");
  114. // Get the INode pointers that were passed in.
  115. INode *src_node = arg_list[0]->to_node();
  116. INode *dest_node = arg_list[1]->to_node();
  117. INode *wsm_node = NULL;
  118. INode *tree_root = arg_list[3]->to_node();
  119. if (arg_list[2] == &undefined)
  120. {
  121. // Duplicate the WSM used by src_node.
  122. wsm_node = duplicate_wsm(find_skin_wsm(src_node), tree_root);
  123. if (wsm_node == NULL)
  124. return &undefined;
  125. }
  126. else
  127. wsm_node = arg_list[2]->to_node();
  128. return copy_skin_info(src_node, dest_node, wsm_node);
  129. }
  130. /*
  131. **
  132. ** MAXScript Function:
  133. ** wwDuplicateSkinWSM - Usage: wwDuplicateSkinWSM wwskin_wsm_node tree_root
  134. **
  135. ** Duplicates the given WWSkin WSM. tree_root is the root node of a hierarchy
  136. ** containing bones similar to the ones used by the given WSM. The hierarchy
  137. ** will be searched for equivalent bones (ie. names the same except their
  138. ** extension), and those bones will be used by the newly duplicated WSM.
  139. **
  140. ** Used by the SceneSetup MAXScript.
  141. */
  142. Value * dupe_skin_wsm_cf (Value **arg_list, int count)
  143. {
  144. // Verify the number and type of the arguments.
  145. check_arg_count("wwDuplicateSkinWSM", 2, count);
  146. type_check(arg_list[0], MAXNode, "WWSkin Object INode");
  147. type_check(arg_list[1], MAXNode, "Target Tree Root INode");
  148. // Get the INode pointers that were passed in.
  149. INode *wsm_node = arg_list[0]->to_node();
  150. INode *root_node = arg_list[1]->to_node();
  151. // Return the duplicated WWSkin WSM.
  152. INode *dupe = duplicate_wsm(wsm_node, root_node);
  153. if (!dupe)
  154. return &undefined;
  155. else
  156. {
  157. // Return the WSM.
  158. one_typed_value_local(Value* wsm_node);
  159. vl.wsm_node = MAXNode::intern(dupe);
  160. return_value(vl.wsm_node);
  161. }
  162. }
  163. Value *find_skin_node_in_tree (INode *root)
  164. {
  165. if (root == NULL)
  166. return &undefined;
  167. // Is this the node we're looking for?
  168. if (get_skin_wsm_obj(root))
  169. {
  170. one_typed_value_local(Value* wsm_node);
  171. vl.wsm_node = MAXNode::intern(root);
  172. return_value(vl.wsm_node);
  173. }
  174. // Search the children of this node.
  175. for (int i = 0; i < root->NumChildren(); i++)
  176. {
  177. Value *retval = find_skin_node_in_tree(root->GetChildNode(i));
  178. if (retval != &undefined)
  179. return retval;
  180. }
  181. // Didn't find it anywhere!
  182. return &undefined;
  183. }
  184. /***********************************************************************************************
  185. * find_skin_binding -- Find the "WWSkin Binding" modifier on this object. *
  186. * *
  187. * INPUT: The skinned object. *
  188. * *
  189. * OUTPUT: The skin modifier, or NULL if one doesn't exist. *
  190. * *
  191. * WARNINGS: *
  192. * *
  193. * HISTORY: *
  194. * 10/19/1999 AJA : Created. *
  195. *=============================================================================================*/
  196. SkinModifierClass *find_skin_binding (INode *skinned_obj)
  197. {
  198. // WWSkin Binding ties us to a space warp, so search the node's
  199. // WSM Derived Object for the WWSkin Binding modifier.
  200. IDerivedObject *dobj = skinned_obj->GetWSMDerivedObject();
  201. if (dobj == NULL)
  202. return NULL; // not bound to a space warp
  203. // Search for the WWSkin Binding modifier on this derived object.
  204. for (int i = 0; i < dobj->NumModifiers(); i++)
  205. {
  206. Modifier *mod = dobj->GetModifier(i);
  207. if (mod->ClassID() != SKIN_MOD_CLASS_ID)
  208. continue;
  209. // We found the skin modifier.
  210. return (SkinModifierClass*)mod;
  211. }
  212. // Skin modifier not found.
  213. return NULL;
  214. }
  215. /***********************************************************************************************
  216. * find_skin_wsm -- Finds the node for the WWSkin WSM used by this object. *
  217. * *
  218. * INPUT: The node of an object with a WWSkin Binding. *
  219. * *
  220. * OUTPUT: The node of the WWSkin WSM referenced by the given object. *
  221. * *
  222. * WARNINGS: *
  223. * *
  224. * HISTORY: *
  225. * 10/18/1999 AJA : Created. *
  226. *=============================================================================================*/
  227. INode *find_skin_wsm (INode *skinned_obj)
  228. {
  229. // Find the skin modifier on this object.
  230. SkinModifierClass *skin_mod = find_skin_binding(skinned_obj);
  231. if (skin_mod == NULL)
  232. return NULL;
  233. // Using the skin modifer, find the WSM's INode.
  234. INode *wsm = (INode*)( skin_mod->GetReference(SkinModifierClass::NODE_REF) );
  235. if (wsm == NULL)
  236. {
  237. char buf[256];
  238. sprintf(buf, "%s has a WWSkin Binding, but I can't find its WWSkin WSM!",
  239. skinned_obj->GetName());
  240. throw RuntimeError(buf);
  241. }
  242. return wsm;
  243. }
  244. /***********************************************************************************************
  245. * get_skin_wsm_obj -- Gets the SkinWSMObjectClass from a WWSkin WSM node. *
  246. * *
  247. * INPUT: The node for the WWSkin WSM's representation in the scene. *
  248. * *
  249. * OUTPUT: The SkinWSMObjectClass. *
  250. * *
  251. * WARNINGS: *
  252. * *
  253. * HISTORY: *
  254. * 10/18/1999 AJA : Created. *
  255. *=============================================================================================*/
  256. SkinWSMObjectClass *get_skin_wsm_obj (INode *wsm_node)
  257. {
  258. // We need a valid node.
  259. if (!wsm_node)
  260. return NULL;
  261. // The node must reference an object.
  262. Object *obj = wsm_node->GetObjectRef();
  263. if (!obj)
  264. return NULL;
  265. // That BASE object must be a SkinWSMObject
  266. while (obj)
  267. {
  268. // If this is a derived object, burrow deeper,
  269. // otherwise we're at the base object.
  270. if (obj->SuperClassID() == GEN_DERIVOB_CLASS_ID)
  271. obj = ((IDerivedObject*)obj)->GetObjRef();
  272. else
  273. break;
  274. }
  275. if (obj->ClassID() != SKIN_OBJ_CLASS_ID)
  276. return NULL;
  277. // Return it.
  278. return (SkinWSMObjectClass*)obj;
  279. }
  280. /***********************************************************************************************
  281. * duplicate_wsm -- Duplicates a WWSkin WSM *
  282. * *
  283. * INPUT: wsm_node - INode of the WWSkin WSM object. *
  284. * tree - The root of a tree containing equivalents of the bones in the WWSkin used *
  285. * by skinned_obj. The bone names must be the same (after being processed by *
  286. * Set_W3D_Name() *
  287. * *
  288. * OUTPUT: The node of the newly duplicated WWSkin WSM. *
  289. * *
  290. * WARNINGS: *
  291. * *
  292. * HISTORY: *
  293. * 10/18/1999 AJA : Created. *
  294. * 11/3/1999 AJA : Changed first argument from skinned_obj to wsm_node. *
  295. *=============================================================================================*/
  296. INode *duplicate_wsm (INode *wsm_node, INode *tree)
  297. {
  298. SkinWSMObjectClass *wsm_obj = get_skin_wsm_obj(wsm_node);
  299. if (!wsm_node || !wsm_obj)
  300. return NULL;
  301. /*
  302. ** Duplicate the WSM.
  303. */
  304. SkinWSMObjectClass *new_wsm_obj =
  305. (SkinWSMObjectClass*)CreateInstance(WSM_OBJECT_CLASS_ID, SKIN_OBJ_CLASS_ID);
  306. if (!new_wsm_obj)
  307. return NULL;
  308. // Create a new node in the scene that points to the new WSM object.
  309. INode *new_wsm_node = MAXScript_interface->CreateObjectNode(new_wsm_obj);
  310. if (!new_wsm_node)
  311. return NULL;
  312. // Copy the bones from one to the other.
  313. for (int i = 0; i < wsm_obj->Num_Bones(); i++)
  314. {
  315. INode *src_bone = wsm_obj->Get_Bone(i);
  316. INode *dst_bone = find_equivalent_node(src_bone, tree);
  317. if (!src_bone || !dst_bone)
  318. return NULL;
  319. new_wsm_obj->Add_Bone(dst_bone);
  320. }
  321. // Return a pointer to the new WSM node.
  322. return new_wsm_node;
  323. }
  324. /***********************************************************************************************
  325. * find_equivalent_node -- Searches a hierarchy for an object equivalent to the given one. *
  326. * *
  327. * INPUT: source - The node to search for an equivalent of. *
  328. * tree - The hierarchy to search in. *
  329. * *
  330. * OUTPUT: The equivalent node, or NULL if none was found. *
  331. * *
  332. * WARNINGS: *
  333. * *
  334. * HISTORY: *
  335. * 10/19/1999 AJA : Created. *
  336. *=============================================================================================*/
  337. INode *find_equivalent_node (INode *source, INode *tree, bool name_is_valid)
  338. {
  339. // We need a valid source and tree.
  340. if (!source || !tree)
  341. return NULL;
  342. // The name of the source object. We'll only evaluate this once as an easy optimization.
  343. static char src_name[W3D_NAME_LEN];
  344. if (!name_is_valid)
  345. Set_W3D_Name(src_name, source->GetName());
  346. // The name of the current object we're examining.
  347. char chk_name[W3D_NAME_LEN];
  348. Set_W3D_Name(chk_name, tree->GetName());
  349. // Is this the node we're looking for?
  350. if (strcmp(src_name, chk_name) == 0)
  351. return tree; // Yup, sure is.
  352. // Nope. Check its children.
  353. for (int i = 0; i < tree->NumberOfChildren(); i++)
  354. {
  355. INode *retval = find_equivalent_node(source, tree->GetChildNode(i), true);
  356. if (retval != NULL)
  357. return retval; // we found the node in our children
  358. }
  359. // No equivalent node was found.
  360. return NULL;
  361. }
  362. Value *copy_skin_info (INode *source, INode *target, INode *wsm)
  363. {
  364. // Get the "WWSkin Binding" modifier on the source object.
  365. SkinModifierClass *source_modifier = find_skin_binding(source);
  366. if (source_modifier == NULL)
  367. return &undefined;
  368. // Get the WSMDerivedObject we can add our skin binding modifier to.
  369. IDerivedObject *dobj = setup_wsm_derived_obj(target);
  370. // Create a new skin modifier and copy the source modifier's settings to it.
  371. SkinModifierClass *new_modifier = new SkinModifierClass(wsm, get_skin_wsm_obj(wsm));
  372. if (new_modifier == NULL)
  373. throw RuntimeError("Out of memory - Unable to allocate a new SkinModifierClass object!");
  374. new_modifier->SubObjSelLevel = source_modifier->SubObjSelLevel;
  375. // Dupe the mod context, especially the local mod data hanging off of it.
  376. ModContext *source_context = find_skin_mod_context(source);
  377. ModContext *new_context = new ModContext(source_context->tm, source_context->box,
  378. source_context->localData);
  379. if (new_context == NULL)
  380. throw RuntimeError("Out of memory - Unable to allocate a new ModContext object!");
  381. // Add a new "WWSkin Binding" modifier to the target object to associate
  382. // the object with the skin WSM. All of the settings should be correct,
  383. // and the target object becomes a "skinned object".
  384. dobj->AddModifier(new_modifier, new_context);
  385. // Return the WSM.
  386. one_typed_value_local(Value* wsm_node);
  387. vl.wsm_node = MAXNode::intern(wsm);
  388. return_value(vl.wsm_node);
  389. }
  390. IDerivedObject *setup_wsm_derived_obj (INode *node)
  391. {
  392. // Check if the target object is already bound to a space warp.
  393. IDerivedObject *dobj = node->GetWSMDerivedObject();
  394. if (dobj != NULL)
  395. {
  396. // It's bound to a space warp. Check if WWSkin is one of the
  397. // space warp bindings. If so, remove it (we don't want to
  398. // be bound to an old skin).
  399. for (int i = 0; i < dobj->NumModifiers(); i++)
  400. {
  401. Modifier *mod = dobj->GetModifier(i);
  402. if (mod->ClassID() != SKIN_MOD_CLASS_ID)
  403. continue;
  404. // We found the skin modifier, remove it.
  405. dobj->DeleteModifier(i);
  406. break;
  407. }
  408. }
  409. else
  410. {
  411. // This object isn't bound to a space warp. Create a
  412. // WSMDerivedObject for the node to play with.
  413. dobj = CreateWSDerivedObject(node->GetObjectRef());
  414. if (dobj == NULL)
  415. {
  416. char msg[128];
  417. sprintf(msg, "Error setting up the WSMDerivedObject for %s", node->GetName());
  418. throw RuntimeError(msg);
  419. }
  420. node->SetObjectRef(dobj);
  421. }
  422. return dobj;
  423. }
  424. ModContext *find_skin_mod_context (INode *node)
  425. {
  426. // We need a valid node
  427. if (node == NULL)
  428. return NULL;
  429. // The node needs to be bound to a space warp (ie. must have
  430. // a WSMDerivedObject).
  431. IDerivedObject *dobj = node->GetWSMDerivedObject();
  432. if (dobj == NULL)
  433. return NULL;
  434. // It's bound to a space warp. Find the WWSkin modifier.
  435. for (int i = 0; i < dobj->NumModifiers(); i++)
  436. {
  437. Modifier *mod = dobj->GetModifier(i);
  438. if (mod->ClassID() != SKIN_MOD_CLASS_ID)
  439. continue;
  440. // We found the skin modifier, return its mod context.
  441. return dobj->GetModContext(i);
  442. }
  443. // We didn't find a WWSkin binding.
  444. return NULL;
  445. }