1 /* 2 Copyright (c) 2008-2009 NetAllied Systems GmbH 3 4 This file is part of COLLADAMax. 5 6 Portions of the code are: 7 Copyright (c) 2005-2007 Feeling Software Inc. 8 Copyright (c) 2005-2007 Sony Computer Entertainment America 9 10 Based on the 3dsMax COLLADASW Tools: 11 Copyright (c) 2005-2006 Autodesk Media Entertainment 12 13 Licensed under the MIT Open Source License, 14 for details please see LICENSE file or the website 15 http://www.opensource.org/licenses/mit-license.php 16 */ 17 18 19 #include "COLLADAMaxStableHeaders.h" 20 21 #include "COLLADAMaxOptions.h" 22 23 #include <max.h> 24 #include <maxapi.h> 25 #include <custcont.h> 26 27 #include "resource.h" 28 29 namespace COLLADAMax 30 { 31 32 const String Options::OPTION_NORMALS_NAME = "normals"; 33 const String Options::OPTION_TRIANGULAT_NAME = "triangulate"; 34 const String Options::OPTION_XREFS_NAME = "xrefs"; 35 const String Options::OPTION_TANGENTS_NAME = "tangents"; 36 const String Options::OPTION_ANIMATIONS_NAME = "animations"; 37 const String Options::OPTION_SAMPLEANIMATIONS_NAME = "sampleAnim"; 38 const String Options::OPTION_CREATECLIP_NAME = "createClip"; 39 const String Options::OPTION_BAKEMATRICES_NAME = "bakeMatrices"; 40 const String Options::OPTION_RELATIVEPATHS_NAME = "relativePaths"; 41 const String Options::OPTION_CHECKIFANIMATIONISANIMATED_NAME = "checkIfAnimationIsAnimated"; 42 const String Options::OPTION_ANIMATIONSTART_NAME = "animStart"; 43 const String Options::OPTION_ANIMATIONEND_NAME = "animEnd"; 44 const String Options::OPTION_COPY_IMAGES_NAME = "copyImages"; 45 const String Options::OPTION_EXPORT_USERDEFINED_PROPERTIES_NAME = "exportUserdefinedProperties"; 46 47 48 EnableDlgControl(HWND window,int controlId,BOOL enabled)49 static void EnableDlgControl(HWND window, int controlId, BOOL enabled) 50 { 51 HWND control = GetDlgItem(window, controlId); 52 if (control) 53 EnableWindow(control, enabled); 54 } 55 56 template<class OptionType> writeOption(FILE * file,const String & optionName,OptionType optionValue)57 void writeOption(FILE* file, const String & optionName, OptionType optionValue) 58 { 59 String optionString = optionName + "=%d\r\n"; 60 fprintf_s(file, optionString.c_str(), optionValue); 61 } 62 63 template<class OptionType> readOption(char * token,const String & optionName,char * value,OptionType & optionValue)64 bool readOption(char* token, const String & optionName, char* value, OptionType &optionValue) 65 { 66 bool match = strcmp(token, optionName.c_str()) == 0; 67 if ( match ) 68 optionValue = (OptionType) atoi(value); 69 return match; 70 } 71 72 template<> readOption(char * token,const String & optionName,char * value,bool & optionValue)73 bool readOption<bool>(char* token, const String & optionName, char* value, bool &optionValue) 74 { 75 bool match = strcmp(token, optionName.c_str()) == 0; 76 if ( match ) 77 optionValue = atoi(value) != false; 78 return match; 79 } 80 81 82 const String Options::CONFIGURATION_FILE_NAME = "OpenCOLLADA.ini"; 83 const String Options::CONFIGURATION_HEADER_NAME = "OpenCOLLADA"; 84 Options(Interface * maxInterface)85 Options::Options(Interface* maxInterface) 86 : 87 mMaxInterface(maxInterface), 88 // Set the option values to their default 89 mNormals(true), 90 mTriangulate(true), 91 mIncludeXrefs(false), 92 mTangents(false), 93 mAnimations(true), 94 mSampleAnimation(false), 95 mCreateClip(false), 96 mLayersAsClips(false), 97 mBakeMatrices(false), 98 mRelativePaths(false), 99 mCopyImages(true), 100 mImageDirectory("images"), 101 mCheckIfAnimationIsAnimated(false), 102 importUnits(true), 103 importUpAxis(true), 104 mSelectionOnly(false), 105 106 mAnimationStart(TIME_INITIAL_POSE), 107 mAnimationEnd(TIME_PosInfinity), 108 mXRefOutputDir("C:\\Temp\\xref\\"), 109 mExportUserDefinedProperties(false) 110 { 111 112 // Load the export options from the configuration file 113 // LoadOptions(); 114 } 115 116 // Displays the exporter options dialog to allow the user to change the options. ShowDialog()117 bool Options::ShowDialog() 118 { 119 120 LoadOptions(); 121 // Prompt the user with our dialogbox, and get all the options. 122 bool doExport = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_EXPORT_OPTIONS), mMaxInterface->GetMAXHWnd(), ExportOptionsDlgProcS, (LPARAM)this) != FALSE; 123 124 if (!doExport) 125 return false; 126 127 // Save the export options to the configuration file 128 SaveOptions(); 129 130 return true; 131 } 132 133 134 // options dialog message handler ExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM)135 INT_PTR Options::ExportOptionsDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM) 136 { 137 ISpinnerControl* spin; 138 // int ticksPerFrame = GetTicksPerFrame(); 139 Interval animRange = mMaxInterface->GetAnimRange(); 140 int sceneStart = animRange.Start(); 141 int sceneEnd = animRange.End(); 142 143 switch (message) 144 { 145 case WM_INITDIALOG: { 146 CenterWindow(hWnd, GetParent(hWnd)); 147 148 // grab scene timing details & clip anim start & end if needed 149 if (mAnimationStart < sceneStart) 150 mAnimationStart = sceneStart; 151 152 if (mAnimationStart > sceneEnd) 153 mAnimationStart = sceneEnd; 154 155 if (mAnimationEnd < sceneStart) 156 mAnimationEnd = sceneStart; 157 158 if (mAnimationEnd > sceneEnd) 159 mAnimationEnd = sceneEnd; 160 161 // setup checkboxes 162 CheckDlgButton(hWnd, IDC_GEOM_NORMALS, mNormals); 163 CheckDlgButton(hWnd, IDC_GEOM_TRIANGLES, mTriangulate); 164 CheckDlgButton(hWnd, IDC_GEOM_XREFS, mIncludeXrefs); 165 CheckDlgButton(hWnd, IDC_GEOM_TANGENTS, mTangents); 166 CheckDlgButton(hWnd, IDC_ANIM_ENABLE, mAnimations); 167 CheckDlgButton(hWnd, IDC_ANIM_SAMPLE, mSampleAnimation); 168 CheckDlgButton(hWnd, IDC_ANIM_CLIP, mCreateClip); 169 CheckDlgButton(hWnd, IDC_LAYERS_TO_CLIPS, mLayersAsClips); 170 CheckDlgButton(hWnd, IDC_BAKE_MATRICES, mBakeMatrices); 171 CheckDlgButton(hWnd, IDC_RELATIVE_PATHS, mRelativePaths); 172 CheckDlgButton(hWnd, IDC_COPY_IMAGES, mCopyImages); 173 CheckDlgButton(hWnd, IDC_EXPORT_USER_PROPERTIES, mExportUserDefinedProperties); 174 175 // Animation checkboxes depend on the enable button. 176 EnableDlgControl(hWnd, IDC_ANIM_SAMPLE, mAnimations); 177 EnableDlgControl(hWnd, IDC_ANIM_CLIP, mAnimations); 178 179 #if defined(MAX_RELEASE_R17) && (MAX_RELEASE >= MAX_RELEASE_R17) 180 EnableDlgControl(hWnd, IDC_LAYERS_TO_CLIPS, mAnimations); 181 #else 182 EnableDlgControl(hWnd, IDC_LAYERS_TO_CLIPS, false); 183 #endif 184 185 // setup spinners 186 spin = GetISpinner(GetDlgItem(hWnd, IDC_ANIM_START_SPIN)); 187 spin->LinkToEdit(GetDlgItem(hWnd,IDC_ANIM_START), EDITTYPE_TIME); 188 spin->SetLimits(sceneStart, sceneEnd, true); 189 spin->SetScale(1.0f); 190 spin->SetValue(mAnimationStart, true); 191 spin->Enable(mSampleAnimation && mAnimations); 192 EnableWindow(GetDlgItem(hWnd, IDC_START_LABEL), mSampleAnimation && mAnimations); 193 ReleaseISpinner(spin); 194 195 spin = GetISpinner(GetDlgItem(hWnd, IDC_ANIM_END_SPIN)); 196 spin->LinkToEdit(GetDlgItem(hWnd,IDC_ANIM_END), EDITTYPE_TIME); 197 spin->SetLimits(sceneStart, sceneEnd, true); 198 spin->SetScale(1.0f); 199 spin->SetValue(mAnimationEnd, false); 200 spin->Enable(mSampleAnimation && mAnimations); 201 EnableWindow(GetDlgItem(hWnd, IDC_END_LABEL), mSampleAnimation && mAnimations); 202 ReleaseISpinner(spin); 203 204 return true; 205 } 206 207 case WM_COMMAND: 208 switch (LOWORD(wParam)) { 209 case IDC_ANIM_ENABLE: 210 mAnimations = IsDlgButtonChecked(hWnd, IDC_ANIM_ENABLE) == BST_CHECKED; 211 EnableDlgControl(hWnd, IDC_ANIM_SAMPLE, mAnimations); 212 EnableDlgControl(hWnd, IDC_ANIM_CLIP, mAnimations); 213 #if defined(MAX_RELEASE_R17) && (MAX_RELEASE >= MAX_RELEASE_R17) 214 EnableDlgControl(hWnd, IDC_LAYERS_TO_CLIPS, mAnimations); 215 #else 216 EnableDlgControl(hWnd, IDC_LAYERS_TO_CLIPS, false); 217 #endif 218 219 /*spin = GetISpinner(GetDlgItem(hWnd, IDC_ANIM_START_SPIN)); 220 //spin->LinkToEdit(GetDlgItem(hWnd,IDC_ANIM_START), EDITTYPE_INT); 221 spin->Enable(sampleAnim && animations); 222 EnableWindow(GetDlgItem(hWnd, IDC_START_LABEL), sampleAnim && animations); 223 ReleaseISpinner(spin); 224 225 spin = GetISpinner(GetDlgItem(hWnd, IDC_ANIM_END_SPIN)); 226 //spin->LinkToEdit(GetDlgItem(hWnd,IDC_ANIM_END), EDITTYPE_INT); 227 spin->Enable(sampleAnim && animations); 228 EnableWindow(GetDlgItem(hWnd, IDC_END_LABEL), sampleAnim && animations); 229 ReleaseISpinner(spin); 230 break; */ 231 232 case IDC_ANIM_SAMPLE: 233 mSampleAnimation = IsDlgButtonChecked(hWnd, IDC_ANIM_SAMPLE) == BST_CHECKED; 234 235 spin = GetISpinner(GetDlgItem(hWnd, IDC_ANIM_START_SPIN)); 236 spin->Enable(mSampleAnimation && mAnimations); 237 EnableWindow(GetDlgItem(hWnd, IDC_START_LABEL), mSampleAnimation && mAnimations); 238 ReleaseISpinner(spin); 239 240 spin = GetISpinner(GetDlgItem(hWnd, IDC_ANIM_END_SPIN)); 241 spin->Enable(mSampleAnimation && mAnimations); 242 EnableWindow(GetDlgItem(hWnd, IDC_END_LABEL), mSampleAnimation && mAnimations); 243 ReleaseISpinner(spin); 244 break; 245 246 case IDOK: 247 // hit OK, pick up control values & end dialog 248 mBakeMatrices = IsDlgButtonChecked(hWnd, IDC_BAKE_MATRICES) == BST_CHECKED; 249 mRelativePaths = IsDlgButtonChecked(hWnd, IDC_RELATIVE_PATHS) == BST_CHECKED; 250 mAnimations = IsDlgButtonChecked(hWnd, IDC_ANIM_ENABLE) == BST_CHECKED; 251 mSampleAnimation = IsDlgButtonChecked(hWnd, IDC_ANIM_SAMPLE) == BST_CHECKED; 252 mCreateClip = IsDlgButtonChecked(hWnd, IDC_ANIM_CLIP) == BST_CHECKED; 253 mLayersAsClips = IsDlgButtonChecked(hWnd, IDC_LAYERS_TO_CLIPS) == BST_CHECKED; 254 mNormals = IsDlgButtonChecked(hWnd, IDC_GEOM_NORMALS) == BST_CHECKED; 255 mTriangulate = IsDlgButtonChecked(hWnd, IDC_GEOM_TRIANGLES) == BST_CHECKED; 256 mIncludeXrefs = IsDlgButtonChecked(hWnd, IDC_GEOM_XREFS) == BST_CHECKED; 257 mTangents = IsDlgButtonChecked(hWnd, IDC_GEOM_TANGENTS) == BST_CHECKED; 258 mCopyImages = IsDlgButtonChecked(hWnd, IDC_COPY_IMAGES) == BST_CHECKED; 259 mExportUserDefinedProperties = IsDlgButtonChecked(hWnd, IDC_EXPORT_USER_PROPERTIES) == BST_CHECKED; 260 261 spin = GetISpinner(GetDlgItem(hWnd, IDC_ANIM_START_SPIN)); 262 mAnimationStart = mSampleAnimation ? spin->GetIVal() : sceneStart; 263 ReleaseISpinner(spin); 264 spin = GetISpinner(GetDlgItem(hWnd, IDC_ANIM_END_SPIN)); 265 mAnimationEnd = mSampleAnimation ? spin->GetIVal() : sceneEnd; 266 ReleaseISpinner(spin); 267 268 EndDialog(hWnd, 1); 269 break; 270 271 case IDCANCEL: 272 EndDialog(hWnd, 0); 273 break; 274 } 275 default: 276 return false; 277 } 278 return true; 279 } 280 281 282 283 // options dialog proc ExportOptionsDlgProcS(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)284 INT_PTR CALLBACK Options::ExportOptionsDlgProcS(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 285 { 286 Options* exp; 287 if (message == WM_INITDIALOG) 288 { 289 // record exp instance pointer for subsequent callbacks 290 exp = (Options*) lParam; 291 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)lParam); 292 } 293 else 294 { 295 exp = (Options*)(size_t) GetWindowLongPtr(hWnd, GWLP_USERDATA); 296 } 297 // hand off to message-handler method 298 return exp ? exp->ExportOptionsDlgProc(hWnd, message, wParam, lParam) : false; 299 } 300 301 302 SaveOptions()303 void Options::SaveOptions() 304 { 305 NativeString configurationPath(NativeString(mMaxInterface->GetDir(APP_PLUGCFG_DIR))); 306 URI configurationPathUri(URI::nativePathToUri(configurationPath.toUtf8String())); 307 URI optionsFileUri(configurationPathUri, CONFIGURATION_FILE_NAME); 308 // NativeString filename = configurationPath + "\\" + CONFIGURATION_FILE_NAME; 309 FILE* file; 310 errno_t error = fopen_s(&file, optionsFileUri.toNativePath().c_str(), "wb"); 311 if ( error ) 312 return; 313 314 315 316 // Write down a standard INI header to allow MaxScript edition. 317 String headerString("[" + CONFIGURATION_HEADER_NAME + "]\r\n"); 318 fwrite(headerString.data(), headerString.length(), 1, file); 319 320 // Write down the options, one by one, in the form: 'option=X\n' 321 writeOption(file, OPTION_NORMALS_NAME, mNormals ); 322 323 writeOption(file, OPTION_TRIANGULAT_NAME, mTriangulate ); 324 writeOption(file, OPTION_XREFS_NAME, mIncludeXrefs ); 325 writeOption(file, OPTION_TANGENTS_NAME, mTangents ); 326 writeOption(file, OPTION_ANIMATIONS_NAME, mAnimations ); 327 writeOption(file, OPTION_SAMPLEANIMATIONS_NAME, mSampleAnimation ); 328 writeOption(file, OPTION_CREATECLIP_NAME, mCreateClip ); 329 writeOption(file, OPTION_BAKEMATRICES_NAME, mBakeMatrices ); 330 writeOption(file, OPTION_RELATIVEPATHS_NAME, mRelativePaths ); 331 writeOption(file, OPTION_CHECKIFANIMATIONISANIMATED_NAME, mCheckIfAnimationIsAnimated ); 332 writeOption(file, OPTION_ANIMATIONSTART_NAME, mAnimationStart ); 333 writeOption(file, OPTION_ANIMATIONEND_NAME, mAnimationEnd ); 334 writeOption(file, OPTION_COPY_IMAGES_NAME, mCopyImages ); 335 writeOption(file, OPTION_EXPORT_USERDEFINED_PROPERTIES_NAME, mExportUserDefinedProperties ); 336 337 fclose(file); 338 } 339 340 341 LoadOptions()342 void Options::LoadOptions() 343 { 344 NativeString configurationPath(NativeString(mMaxInterface->GetDir(APP_PLUGCFG_DIR))); 345 URI configurationPathUri(URI::nativePathToUri(configurationPath.toUtf8String())); 346 URI optionsFileUri(configurationPathUri, CONFIGURATION_FILE_NAME); 347 348 FILE* file; 349 errno_t error = fopen_s(&file, optionsFileUri.toNativePath().c_str(), "rb"); 350 if ( error ) 351 return; 352 353 // Read the whole configuration file 354 fseek(file, 0, SEEK_END); 355 int fileLength = ftell(file); 356 fseek(file, 0, SEEK_SET); 357 char* wholeFile = new char[fileLength + 1]; 358 fread(wholeFile, 1, fileLength, file); 359 fclose(file); 360 wholeFile[fileLength] = 0; 361 362 char *context; 363 // Read in the options, one by one, in the form: 'option=X\n' 364 char* token = strtok_s(wholeFile, "\n", &context); 365 while (token ) 366 { 367 // Skip whitespaces 368 while (*token != 0 && (*token == ' ' || *token == '\r' || *token == '\t')) ++token; 369 if (*token != 0) 370 { 371 if (*token == '[') {} // Standard INI header. Just skip the line for now. 372 373 // Read in the Property=Value lines. 374 char* value = strchr(token, '='); 375 if (value ) 376 { 377 *(value++) = 0; 378 while (*value != 0 && (*value == ' ' || *value == '\r' || *value == '\t')) ++value; 379 if (*value != 0) // skip empty lines. 380 { 381 // Look for/read in the COLLADAMax options. 382 readOption<bool>(token, OPTION_NORMALS_NAME, value, mNormals) || 383 readOption<bool>(token, OPTION_TRIANGULAT_NAME, value, mTriangulate) || 384 readOption<bool>(token, OPTION_XREFS_NAME, value, mIncludeXrefs) || 385 readOption<bool>(token, OPTION_TANGENTS_NAME, value, mTangents) || 386 readOption<bool>(token, OPTION_SAMPLEANIMATIONS_NAME, value, mSampleAnimation) || 387 readOption<bool>(token, OPTION_ANIMATIONS_NAME, value, mAnimations) || 388 readOption<bool>(token, OPTION_CREATECLIP_NAME, value, mCreateClip) || 389 readOption<bool>(token, OPTION_BAKEMATRICES_NAME, value, mBakeMatrices) || 390 readOption<bool>(token, OPTION_RELATIVEPATHS_NAME, value, mRelativePaths) || 391 readOption<bool>(token, OPTION_CHECKIFANIMATIONISANIMATED_NAME, value, mCheckIfAnimationIsAnimated) || 392 readOption<int>(token, OPTION_ANIMATIONSTART_NAME, value, mAnimationStart) || 393 readOption<int>(token, OPTION_ANIMATIONEND_NAME, value, mAnimationEnd)|| 394 readOption<bool>(token, OPTION_COPY_IMAGES_NAME, value, mCopyImages)|| 395 readOption<bool>(token, OPTION_EXPORT_USERDEFINED_PROPERTIES_NAME, value, mExportUserDefinedProperties); 396 397 { 398 // Handle unknown option here. 399 } 400 } 401 } 402 } 403 404 token = strtok_s(0, "\n", &context); 405 } 406 delete[] wholeFile; 407 } 408 409 410 411 412 } 413