w3dappdata.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. /*
  2. ** Command & Conquer Generals(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 : Max2W3d *
  23. * *
  24. * $Archive:: /Commando/Code/Tools/max2w3d/w3dappdata.h $*
  25. * *
  26. * Original Author:: Greg Hjelstrom *
  27. * *
  28. * $Author:: Greg_h $*
  29. * *
  30. * $Modtime:: 8/21/01 9:44a $*
  31. * *
  32. * $Revision:: 8 $*
  33. * *
  34. *---------------------------------------------------------------------------------------------*
  35. * Functions: *
  36. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  37. #ifndef W3DAPPDATA_H
  38. #define W3DAPPDATA_H
  39. #include <Max.h>
  40. /*
  41. ** The W3DUtilityClass uses several app-data chunks to store user-options for INodes
  42. ** in the MAX scene. Below are the IDs for each app-data chunk type:
  43. */
  44. #define W3D_APPDATA_0 0
  45. #define W3D_APPDATA_1 1
  46. #define W3D_APPDATA_2 2
  47. #define W3D_DAZZLE_APPDATA 3
  48. /*
  49. ** Classifying INodes for w3d exporting
  50. **
  51. ** NOTE: Use these utility functions rather than going straight to the AppData
  52. ** structure!
  53. **
  54. ** - There are bits stored in AppData for each node
  55. ** - These bits indicate wether something should be exported as hierarchy,
  56. ** geometry (and if so, what type of geometry: mesh, collision box, bitmap, etc)
  57. **
  58. ** When we say something is "Hierarchy" that means its transform should be put
  59. ** into any hierarchy tree or motion being created. In some places I used
  60. ** the term "Bone" which means the same thing.
  61. **
  62. ** When we say something is "Geometry" that means that the object will become
  63. ** some sort of render object (normal mesh, bitmap, collision mesh, etc)
  64. **
  65. */
  66. /*
  67. ** Either or both of these will return true for a given INode
  68. */
  69. bool Is_Bone(INode * node);
  70. bool Is_Geometry(INode * node);
  71. /*
  72. ** Geometry Type:
  73. ** One of the following will return true if the given INode is
  74. ** to have its geometry exported
  75. */
  76. bool Is_Normal_Mesh(INode * node);
  77. bool Is_Camera_Aligned_Mesh(INode * node);
  78. bool Is_Camera_Oriented_Mesh(INode * node);
  79. bool Is_Collision_AABox(INode * node);
  80. bool Is_Collision_OBBox(INode * node);
  81. bool Is_Skin(INode * node);
  82. bool Is_Shadow(INode * node);
  83. bool Is_Null_Object(INode * node);
  84. bool Is_Dazzle(INode * node);
  85. bool Is_Aggregate(INode * node);
  86. /*
  87. ** Collision Bits, any or all of these may return true for a given INode
  88. */
  89. bool Is_Physical_Collision(INode * node);
  90. bool Is_Projectile_Collision(INode * node);
  91. bool Is_Vis_Collision(INode * node);
  92. bool Is_Camera_Collision(INode * node);
  93. bool Is_Vehicle_Collision(INode * node);
  94. /*
  95. ** Miscellaneous settings
  96. */
  97. bool Is_Hidden(INode * node);
  98. bool Is_Two_Sided(INode * node);
  99. bool Is_ZNormals(INode * node);
  100. bool Is_Vertex_Alpha(INode * node);
  101. bool Is_Shatterable(INode * node);
  102. bool Is_NPatchable(INode * node);
  103. /*
  104. ** Proxy support. If a node has a name which contains a ~ it is considered a
  105. ** proxy for an application defined named object. This overrides all other
  106. ** settings (in the future, we shouldn't do things this way!)
  107. */
  108. inline bool Is_Proxy(INode &node)
  109. {
  110. return (::strchr (node.GetName (), '~') != NULL);
  111. }
  112. /*
  113. ** AJA 9/24/99
  114. ** NOTE: Whenever you add a new W3DAppDataStruct, you must add an accessor function
  115. ** to the bottom of this file. Then the WWScript.dlx project must be modified. That
  116. ** project implements an extension to the MAXScript language in the form of a function
  117. ** called "wwCopyAppData". The implementation of this wwCopyAppData function must be
  118. ** aware of the new W3DAppDataStruct. The modification is pretty straightfoward.
  119. **
  120. ** The wwCopyAppData extension was added to MAXScript so that the data we define
  121. ** below can be preserve when a model is cloned (copy/instance/reference). What
  122. ** happens without using wwCopyAppData is that a new INode is created that contains
  123. ** a copy/instance/reference to the original mesh/bone in the source model. When
  124. ** this new INode is created, it has no app data. When the app data is examined later
  125. ** on, it gets the default values! That means all information concerning Export
  126. ** Geometry/Transform, mesh type, and damage region is lost. wwCopyAppData allows
  127. ** a script to duplicate a model INCLUDING all W3D app data, so that this information
  128. ** is preserved.
  129. */
  130. /*
  131. ** The W3DAppData0Struct contains a bitfield. These #defines are
  132. ** used to interpret the bits.
  133. ** (gth) NOTE: AppData0 is now OBSOLETE!!! Use W3DAppData2Struct now.
  134. */
  135. #define EXPORT_TYPE_MASK 0x000F
  136. #define GEOMETRY_TYPE_MASK 0x01F0
  137. #define COLLISION_TYPE_MASK 0xF000
  138. #define EXPORT_BONE_FLAG 0x0001 // export a bone (transform) for this node
  139. #define EXPORT_GEOMETRY_FLAG 0x0002 // export the geometry for this node
  140. #define EXPORT_HIDDEN_FLAG 0x0004 // mesh should be hidden by default
  141. #define EXPORT_TWO_SIDED_FLAG 0x0008 // mesh should be two sided
  142. #define GEOMETRY_TYPE_CAMERA_ALIGNED 0x0010 // interpret this geometry as a camera-aligned mesh
  143. #define GEOMETRY_TYPE_NORMAL_MESH 0x0020 // this is a normal mesh
  144. #define GEOMETRY_TYPE_OBBOX 0x0030 // this is an oriented box (should have 8 verts, etc)
  145. #define GEOMETRY_TYPE_AABOX 0x0040 // this is an axis aligned box
  146. #define GEOMETRY_TYPE_CAMERA_ORIENTED 0x0050 // interpret this geometry as a camera-oriented mesh
  147. #define GEOMETRY_TYPE_NULL 0x0100 // this is a null (for LOD)
  148. #define EXPORT_CAST_SHADOW_FLAG 0x0200 // this mesh casts a shadow
  149. #define EXPORT_VERTEX_ALPHA_FLAG 0x0400 // convert vertex colors to alpha
  150. #define EXPORT_ZNORMALS_FLAG 0x0800 // force vertex normals to point along +z
  151. #define COLLISION_TYPE_PHYSICAL 0x1000 // runtime engine performs physical collision against this mesh
  152. #define COLLISION_TYPE_PROJECTILE 0x2000 // perform projectile collisions against this mesh
  153. #define COLLISION_TYPE_VIS 0x4000 // perform vis group collisions against this mesh
  154. #define DEFAULT_MESH_EXPORT_FLAGS (EXPORT_BONE_FLAG | EXPORT_GEOMETRY_FLAG | GEOMETRY_TYPE_NORMAL_MESH)
  155. #define DEFAULT_EXPORT_FLAGS 0
  156. /*
  157. ** W3D Utility AppData sub-type 0 (OBSOLETE!)
  158. ** ----------------------------------------------------
  159. ** The utility provides a right-click menu which allows
  160. ** the user to toggle the export flags.
  161. ** (gth) NOTE: AppData0 is now OBSOLETE!!! Use W3DAppData2Struct now.
  162. */
  163. struct W3DAppData0Struct
  164. {
  165. W3DAppData0Struct(void) : ExportFlags(DEFAULT_EXPORT_FLAGS) {}
  166. bool Is_Bone(void) { return (ExportFlags & EXPORT_BONE_FLAG) == EXPORT_BONE_FLAG; }
  167. bool Is_Geometry(void) { return (ExportFlags & EXPORT_GEOMETRY_FLAG) == EXPORT_GEOMETRY_FLAG; }
  168. bool Is_Normal_Mesh(void) { return (ExportFlags & GEOMETRY_TYPE_MASK) == GEOMETRY_TYPE_NORMAL_MESH; }
  169. bool Is_Camera_Aligned_Mesh(void) { return (ExportFlags & GEOMETRY_TYPE_MASK) == GEOMETRY_TYPE_CAMERA_ALIGNED; }
  170. bool Is_Camera_Oriented_Mesh(void) { return (ExportFlags & GEOMETRY_TYPE_MASK) == GEOMETRY_TYPE_CAMERA_ORIENTED; }
  171. bool Is_Collision_AABox(void) { return (ExportFlags & GEOMETRY_TYPE_MASK) == GEOMETRY_TYPE_AABOX; }
  172. bool Is_Collision_OBBox(void) { return (ExportFlags & GEOMETRY_TYPE_MASK) == GEOMETRY_TYPE_OBBOX; }
  173. bool Is_Null(void) { return (ExportFlags & GEOMETRY_TYPE_MASK) == GEOMETRY_TYPE_NULL; }
  174. bool Is_Physical_Collision(void) { return (ExportFlags & COLLISION_TYPE_PHYSICAL) == COLLISION_TYPE_PHYSICAL; }
  175. bool Is_Projectile_Collision(void) { return (ExportFlags & COLLISION_TYPE_PROJECTILE) == COLLISION_TYPE_PROJECTILE; }
  176. bool Is_Vis_Collision(void) { return (ExportFlags & COLLISION_TYPE_VIS) == COLLISION_TYPE_VIS; }
  177. bool Is_Hidden(void) { return (ExportFlags & EXPORT_HIDDEN_FLAG) == EXPORT_HIDDEN_FLAG; }
  178. bool Is_Two_Sided(void) { return (ExportFlags & EXPORT_TWO_SIDED_FLAG) == EXPORT_TWO_SIDED_FLAG; }
  179. bool Is_Vertex_Alpha(void) { return (ExportFlags & EXPORT_VERTEX_ALPHA_FLAG) == EXPORT_VERTEX_ALPHA_FLAG; }
  180. bool Is_ZNormals(void) { return (ExportFlags & EXPORT_ZNORMALS_FLAG) == EXPORT_ZNORMALS_FLAG; }
  181. bool Is_Shadow(void) { return (ExportFlags & EXPORT_CAST_SHADOW_FLAG) == EXPORT_CAST_SHADOW_FLAG; }
  182. unsigned short ExportFlags; // what was I thinking??? (gth)
  183. };
  184. /*
  185. ** W3D Utility AppData sub-type 1
  186. ** ----------------------------------------------------
  187. ** This AppData contains the damage region number for
  188. ** the current object.
  189. */
  190. // Maximum number of damage regions on a model.
  191. #define MAX_DAMAGE_REGIONS ((char)16)
  192. // Value that represents no damage region.
  193. #define NO_DAMAGE_REGION ((char)-1)
  194. struct W3DAppData1Struct
  195. {
  196. W3DAppData1Struct(void) : DamageRegion(NO_DAMAGE_REGION) { }
  197. /*
  198. ** NO_DAMAGE_REGION means the object isn't part of
  199. ** any damage region, 0 through MAX_DAMAGE_REGIONS-1
  200. ** are valid damage regions.
  201. */
  202. char DamageRegion;
  203. };
  204. /*
  205. ** W3D Utility AppData sub-type 2
  206. ** ----------------------------------------------------
  207. ** This is an app-data struct that is meant to contain all
  208. ** of the w3d export options for an object in MAX. It
  209. ** replaces the old AppData sub-type 0. Call the static
  210. ** member functions in the class to get a pointer to
  211. ** the AppData2 struct hanging off any INode and automatically
  212. ** create one for you if there isn't already one...
  213. */
  214. struct W3DAppData2Struct
  215. {
  216. W3DAppData2Struct(void);
  217. W3DAppData2Struct(W3DAppData0Struct & olddata);
  218. void Init_With_Mesh_Defaults(void);
  219. void Init_With_Other_Defaults(void);
  220. void Init_From_AppData0(W3DAppData0Struct & olddata);
  221. void Update_Version(void);
  222. enum GeometryTypeEnum
  223. {
  224. GEO_TYPE_CAMERA_ALIGNED = 0x00000001, // Geometry types are mutually exclusive
  225. GEO_TYPE_NORMAL_MESH = 0x00000002,
  226. GEO_TYPE_OBBOX = 0x00000003,
  227. GEO_TYPE_AABOX = 0x00000004,
  228. GEO_TYPE_CAMERA_ORIENTED = 0x00000005,
  229. GEO_TYPE_NULL = 0x00000006,
  230. GEO_TYPE_DAZZLE = 0x00000007,
  231. GEO_TYPE_AGGREGATE = 0x00000008,
  232. };
  233. /*
  234. ** Read Access
  235. */
  236. bool Is_Bone(void) const { return (ExportFlags & EXPORT_TRANSFORM) == EXPORT_TRANSFORM; }
  237. bool Is_Geometry(void) const { return (ExportFlags & EXPORT_GEOMETRY) == EXPORT_GEOMETRY; }
  238. int Get_Geometry_Type(void) const { return GeometryType; }
  239. bool Is_Normal_Mesh(void) const { return GeometryType == GEO_TYPE_NORMAL_MESH; }
  240. bool Is_Camera_Aligned_Mesh(void) const { return GeometryType == GEO_TYPE_CAMERA_ALIGNED; }
  241. bool Is_Camera_Oriented_Mesh(void) const { return GeometryType == GEO_TYPE_CAMERA_ORIENTED; }
  242. bool Is_Collision_AABox(void) const { return GeometryType == GEO_TYPE_AABOX; }
  243. bool Is_Collision_OBBox(void) const { return GeometryType == GEO_TYPE_OBBOX; }
  244. bool Is_Null(void) const { return GeometryType == GEO_TYPE_NULL; }
  245. bool Is_Dazzle(void) const { return GeometryType == GEO_TYPE_DAZZLE; }
  246. bool Is_Hidden_Enabled(void) const { return (GeometryFlags & GEOMETRY_FLAG_HIDDEN) == GEOMETRY_FLAG_HIDDEN; }
  247. bool Is_Two_Sided_Enabled(void) const { return (GeometryFlags & GEOMETRY_FLAG_TWO_SIDED) == GEOMETRY_FLAG_TWO_SIDED; }
  248. bool Is_Vertex_Alpha_Enabled(void) const { return (GeometryFlags & GEOMETRY_FLAG_VERTEX_ALPHA) == GEOMETRY_FLAG_VERTEX_ALPHA; }
  249. bool Is_ZNormals_Enabled(void) const { return (GeometryFlags & GEOMETRY_FLAG_ZNORMALS) == GEOMETRY_FLAG_ZNORMALS; }
  250. bool Is_Shadow_Enabled(void) const { return (GeometryFlags & GEOMETRY_FLAG_CAST_SHADOW) == GEOMETRY_FLAG_CAST_SHADOW; }
  251. bool Is_Shatterable_Enabled(void) const { return (GeometryFlags & GEOMETRY_FLAG_SHATTERABLE) == GEOMETRY_FLAG_SHATTERABLE; }
  252. bool Is_NPatchable_Enabled(void) const { return (GeometryFlags & GEOMETRY_FLAG_NPATCHABLE) == GEOMETRY_FLAG_NPATCHABLE; }
  253. bool Is_Physical_Collision_Enabled(void) const { return (CollisionFlags & COLLISION_FLAG_PHYSICAL) == COLLISION_FLAG_PHYSICAL; }
  254. bool Is_Projectile_Collision_Enabled(void) const { return (CollisionFlags & COLLISION_FLAG_PROJECTILE) == COLLISION_FLAG_PROJECTILE; }
  255. bool Is_Vis_Collision_Enabled(void) const { return (CollisionFlags & COLLISION_FLAG_VIS) == COLLISION_FLAG_VIS; }
  256. bool Is_Camera_Collision_Enabled(void) const { return (CollisionFlags & COLLISION_FLAG_CAMERA) == COLLISION_FLAG_CAMERA; }
  257. bool Is_Vehicle_Collision_Enabled(void) const { return (CollisionFlags & COLLISION_FLAG_VEHICLE) == COLLISION_FLAG_VEHICLE; }
  258. /*
  259. ** Write Access
  260. */
  261. void Enable_Export_Transform(bool onoff) { if (onoff) { ExportFlags |= EXPORT_TRANSFORM; } else { ExportFlags &= ~EXPORT_TRANSFORM; } }
  262. void Enable_Export_Geometry(bool onoff) { if (onoff) { ExportFlags |= EXPORT_GEOMETRY; } else { ExportFlags &= ~EXPORT_GEOMETRY; } }
  263. void Set_Geometry_Type(GeometryTypeEnum type) { GeometryType = (unsigned int)type; }
  264. void Enable_Hidden(bool onoff) { if (onoff) { GeometryFlags |= GEOMETRY_FLAG_HIDDEN; } else { GeometryFlags &= ~GEOMETRY_FLAG_HIDDEN; } }
  265. void Enable_Two_Sided(bool onoff) { if (onoff) { GeometryFlags |= GEOMETRY_FLAG_TWO_SIDED; } else { GeometryFlags &= ~GEOMETRY_FLAG_TWO_SIDED; } }
  266. void Enable_Shadow(bool onoff) { if (onoff) { GeometryFlags |= GEOMETRY_FLAG_CAST_SHADOW; } else { GeometryFlags &= ~GEOMETRY_FLAG_CAST_SHADOW; } }
  267. void Enable_Vertex_Alpha(bool onoff) { if (onoff) { GeometryFlags |= GEOMETRY_FLAG_VERTEX_ALPHA; } else { GeometryFlags &= ~GEOMETRY_FLAG_VERTEX_ALPHA; } }
  268. void Enable_ZNormals(bool onoff) { if (onoff) { GeometryFlags |= GEOMETRY_FLAG_ZNORMALS; } else { GeometryFlags &= ~GEOMETRY_FLAG_ZNORMALS; } }
  269. void Enable_Shatterable(bool onoff) { if (onoff) { GeometryFlags |= GEOMETRY_FLAG_SHATTERABLE; } else { GeometryFlags &= ~GEOMETRY_FLAG_SHATTERABLE; } }
  270. void Enable_NPatchable(bool onoff) { if (onoff) { GeometryFlags |= GEOMETRY_FLAG_NPATCHABLE; } else { GeometryFlags &= ~GEOMETRY_FLAG_NPATCHABLE; } }
  271. void Enable_Physical_Collision(bool onoff) { if (onoff) { CollisionFlags |= COLLISION_FLAG_PHYSICAL; } else { CollisionFlags &= ~COLLISION_FLAG_PHYSICAL; } }
  272. void Enable_Projectile_Collision(bool onoff) { if (onoff) { CollisionFlags |= COLLISION_FLAG_PROJECTILE; } else { CollisionFlags &= ~COLLISION_FLAG_PROJECTILE; } }
  273. void Enable_Vis_Collision(bool onoff) { if (onoff) { CollisionFlags |= COLLISION_FLAG_VIS; } else { CollisionFlags &= ~COLLISION_FLAG_VIS; } }
  274. void Enable_Camera_Collision(bool onoff) { if (onoff) { CollisionFlags |= COLLISION_FLAG_CAMERA; } else { CollisionFlags &= ~COLLISION_FLAG_CAMERA; } }
  275. void Enable_Vehicle_Collision(bool onoff) { if (onoff) { CollisionFlags |= COLLISION_FLAG_VEHICLE; } else { CollisionFlags &= ~COLLISION_FLAG_VEHICLE; } }
  276. /*
  277. ** Comparison
  278. */
  279. bool operator == (const W3DAppData2Struct & that);
  280. bool operator != (const W3DAppData2Struct & that) { return !(*this == that); }
  281. bool Geometry_Options_Match(const W3DAppData2Struct & that);
  282. /*
  283. ** Get the W3DAppData2Struct for a given INode and create one if
  284. ** there isn't already one.
  285. */
  286. static W3DAppData2Struct * Get_App_Data(INode * node,bool create_if_missing = true);
  287. protected:
  288. void Set_Version(int ver) { ExportFlags &= ~VERSION_MASK; ExportFlags |= (ver<<VERSION_SHIFT); }
  289. int Get_Version(void) { return (ExportFlags & VERSION_MASK)>>VERSION_SHIFT; }
  290. enum ExportFlagsEnum
  291. {
  292. EXPORT_TRANSFORM = 0x00000001, // Export flags bit-field
  293. EXPORT_GEOMETRY = 0x00000002,
  294. VERSION_MASK = 0xFFFF0000, // upper 16bits is version number.
  295. VERSION_SHIFT = 16,
  296. };
  297. enum GeometryFlagsEnum
  298. {
  299. GEOMETRY_FLAG_HIDDEN = 0x00000001, // Geometry Flags bitfield
  300. GEOMETRY_FLAG_TWO_SIDED = 0x00000002,
  301. GEOMETRY_FLAG_CAST_SHADOW = 0x00000004,
  302. GEOMETRY_FLAG_VERTEX_ALPHA = 0x00000008,
  303. GEOMETRY_FLAG_ZNORMALS = 0x00000010,
  304. GEOMETRY_FLAG_SHATTERABLE = 0x00000020,
  305. GEOMETRY_FLAG_NPATCHABLE = 0x00000040,
  306. };
  307. enum CollisionFlagsEnum
  308. {
  309. COLLISION_FLAG_PHYSICAL = 0x00000001,
  310. COLLISION_FLAG_PROJECTILE = 0x00000002,
  311. COLLISION_FLAG_VIS = 0x00000004,
  312. COLLISION_FLAG_CAMERA = 0x00000008,
  313. COLLISION_FLAG_VEHICLE = 0x00000010,
  314. };
  315. unsigned int ExportFlags;
  316. unsigned int GeometryType;
  317. unsigned int GeometryFlags;
  318. unsigned int CollisionFlags;
  319. // future expansion, initialized to zeros
  320. unsigned int UnUsed[4];
  321. };
  322. /*
  323. ** W3D Utility Dazzle App Data
  324. ** ----------------------------------------------------
  325. ** This app-data struct is used to contain parameters
  326. ** specific to dazzle render objects. It currently only
  327. ** contains a type name which is limited to 128 characters
  328. ** and some padding variables for future use.
  329. */
  330. struct W3DDazzleAppDataStruct
  331. {
  332. /*
  333. ** Constructor, zeros everything, then initializes DazzleType to "DEFAULT"
  334. */
  335. W3DDazzleAppDataStruct(void);
  336. /*
  337. ** Get the W3DAppData2Struct for a given INode and create one if
  338. ** there isn't already one.
  339. */
  340. static W3DDazzleAppDataStruct * Get_App_Data(INode * node,bool create_if_missing = true);
  341. /*
  342. ** Members
  343. */
  344. unsigned int UnUsed[4];
  345. char DazzleType[128];
  346. };
  347. #endif