1 #include "ModelWindow.h"
2 #include <LDLib/LDrawModelViewer.h>
3 #include <TCFoundation/TCMacros.h>
4 #include "LDVExtensionsSetup.h"
5 #include "LDViewWindow.h"
6 #include "JpegOptionsDialog.h"
7 #include "ExportOptionsDialog.h"
8 #include <TCFoundation/TCAutoreleasePool.h>
9 #include <TCFoundation/TCUserDefaults.h>
10 #include <TCFoundation/TCStringArray.h>
11 #include <TCFoundation/mystring.h>
12 #include <TCFoundation/TCImage.h>
13 #include <TCFoundation/TCAlertManager.h>
14 #include <TCFoundation/TCProgressAlert.h>
15 #include <TCFoundation/TCLocalStrings.h>
16 #include <LDLoader/LDLError.h>
17 #include <LDLoader/LDLModel.h>
18 #include <LDLib/LDLibraryUpdater.h>
19 #include <LDLib/LDHtmlInventory.h>
20 #include "Resource.h"
21 #include <Commctrl.h>
22 #include <LDLib/LDUserDefaultsKeys.h>
23 #include <CUI/CUIWindowResizer.h>
24 #include <CUI/CUIScaler.h>
25 #include <TRE/TREMainModel.h>
26 #include <TRE/TREGLExtensions.h>
27 #include <windowsx.h>
28
29 #if !defined(USE_CPP11) && !defined(_NO_BOOST)
30 #include <boost/bind.hpp>
31 #endif // !_NO_BOOST
32
33 #if defined(_MSC_VER) && _MSC_VER >= 1400 && defined(_DEBUG)
34 #define new DEBUG_CLIENTBLOCK
35 #endif // _DEBUG
36
37 #define DISTANCE_MULT 1.325f
38
39 #define POLL_INTERVAL 500
40 #define POLL_TIMER 1
41
42 #define FSAA_UPDATE_TIMER 2
43
44 #define PNG_IMAGE_TYPE_INDEX 1
45 #define BMP_IMAGE_TYPE_INDEX 2
46 #define JPG_IMAGE_TYPE_INDEX 3
47 #define SVG_IMAGE_TYPE_INDEX 4
48 #define EPS_IMAGE_TYPE_INDEX 5
49 #define PDF_IMAGE_TYPE_INDEX 6
50
51 #define MAX_SNAPSHOT_WIDTH 10000
52 #define MAX_SNAPSHOT_HEIGHT 10000
53
54 #ifndef ListView_SetCheckState
55 #define ListView_SetCheckState(hwndLV, i, fCheck) \
56 ListView_SetItemState(hwndLV, i, \
57 INDEXTOSTATEIMAGEMASK((fCheck)+1), LVIS_STATEIMAGEMASK)
58 #endif
59
60 void debugOut(char *fmt, ...);
61
ControlInfo(void)62 ControlInfo::ControlInfo(void)
63 {
64 #ifdef _LEAK_DEBUG
65 strcpy(className, "ControlInfo");
66 #endif
67 }
68
ErrorInfo(void)69 ErrorInfo::ErrorInfo(void)
70 :m_typeName(NULL)
71 {
72 #ifdef _LEAK_DEBUG
73 strcpy(className, "ErrorInfo");
74 #endif
75 }
76
~ErrorInfo(void)77 ErrorInfo::~ErrorInfo(void)
78 {
79 }
80
dealloc(void)81 void ErrorInfo::dealloc(void)
82 {
83 delete m_typeName;
84 TCObject::dealloc();
85 }
86
setTypeName(CUCSTR typeName)87 void ErrorInfo::setTypeName(CUCSTR typeName)
88 {
89 if (typeName != m_typeName)
90 {
91 delete[] m_typeName;
92 m_typeName = copyString(typeName);
93 }
94 }
95
ModelWindow(CUIWindow * parentWindow,int x,int y,int width,int height)96 ModelWindow::ModelWindow(
97 CUIWindow* parentWindow,
98 int x,
99 int y,
100 int width,
101 int height):
102 CUIOGLWindow(parentWindow, x, y, width, height),
103 modelViewer(new LDrawModelViewer(width, height)),
104 snapshotTaker(NULL),
105 numFramesSinceReference(0),
106 firstFPSPass(true),
107 //rotationSpeed(0.0f),
108 //lButtonDown(false),
109 //rButtonDown(false),
110 //mButtonDown(false),
111 hPrefsWindow(NULL),
112 captureCount(0),
113 redrawCount(0),
114 hProgressWindow(NULL),
115 lastProgressUpdate(0),
116 loading(false),
117 //needsRecompile(false),
118 hErrorWindow(NULL),
119 errors(new LDLErrorArray),
120 errorTreePopulated(false),
121 errorInfos(NULL),
122 prefs(new LDViewPreferences(parentWindow->getHInstance(), modelViewer)),
123 applyingPrefs(false),
124 offscreenActive(false),
125 hPBuffer(NULL),
126 hPBufferDC(NULL),
127 hPBufferGLRC(NULL),
128 hBitmapRenderDC(NULL),
129 hBitmapRenderGLRC(NULL),
130 hRenderBitmap(NULL),
131 hPrintDialog(NULL),
132 hStatusBar(NULL),
133 hProgressBar(NULL),
134 windowShown(false),
135 hCurrentDC(NULL),
136 hCurrentGLRC(NULL),
137 errorWindowResizer(NULL),
138 saveWindowResizer(NULL),
139 savingFromCommandLine(false),
140 skipErrorUpdates(false),
141 releasingMouse(false),
142 saveStepSuffix(NULL),
143 userLoad(false),
144 errorCount(0),
145 warningCount(0)
146 #if defined(USE_CPP11) || !defined(_NO_BOOST)
147 ,remoteListener(true)
148 ,remoteMessageID(0)
149 #endif // !_NO_BOOST
150 {
151 UCSTR programPath = LDViewPreferences::getLDViewPath();
152 HRSRC hStudLogoResource = FindResource(NULL,
153 MAKEINTRESOURCE(IDR_STUDLOGO_PNG), RT_PNGDATA_1X);
154 HRSRC hFontResource = FindResource(NULL, MAKEINTRESOURCE(IDR_SANS_FONT),
155 RT_RCDATA);
156
157 loadSettings();
158 if (hStudLogoResource)
159 {
160 HGLOBAL hStudLogo = LoadResource(NULL, hStudLogoResource);
161
162 if (hStudLogo)
163 {
164 TCByte *data = (TCByte *)LockResource(hStudLogo);
165
166 if (data)
167 {
168 DWORD length = SizeofResource(NULL, hStudLogoResource);
169
170 if (length)
171 {
172 TREMainModel::setStudTextureData(data, length);
173 }
174 }
175 }
176 }
177 if (hFontResource)
178 {
179 HGLOBAL hFont = LoadResource(NULL, hFontResource);
180
181 if (hFont)
182 {
183 TCByte *data = (TCByte *)LockResource(hFont);
184
185 if (data)
186 {
187 DWORD length = SizeofResource(NULL, hFontResource);
188
189 if (length)
190 {
191 modelViewer->setFontData(data, length);
192 }
193 }
194 }
195 }
196 TCImage *fontImage2x = TCImage::createFromResource(NULL, IDR_SANS_FONT, 4,
197 true, 2.0);
198 if (fontImage2x != NULL)
199 {
200 modelViewer->setFont2x(fontImage2x);
201 fontImage2x->release();
202 }
203 windowStyle = windowStyle & ~WS_VISIBLE;
204 inputHandler = modelViewer->getInputHandler();
205 TCAlertManager::registerHandler(LDLError::alertClass(), this,
206 (TCAlertCallback)&ModelWindow::ldlErrorCallback);
207 TCAlertManager::registerHandler(TCProgressAlert::alertClass(), this,
208 (TCAlertCallback)&ModelWindow::progressAlertCallback);
209 TCAlertManager::registerHandler(LDrawModelViewer::alertClass(), this,
210 (TCAlertCallback)&ModelWindow::modelViewerAlertCallback);
211 TCAlertManager::registerHandler(LDrawModelViewer::redrawAlertClass(), this,
212 (TCAlertCallback)&ModelWindow::redrawAlertCallback);
213 TCAlertManager::registerHandler(LDrawModelViewer::loadAlertClass(), this,
214 (TCAlertCallback)&ModelWindow::loadAlertCallback);
215 TCAlertManager::registerHandler(LDInputHandler::captureAlertClass(), this,
216 (TCAlertCallback)&ModelWindow::captureAlertCallback);
217 TCAlertManager::registerHandler(LDInputHandler::releaseAlertClass(), this,
218 (TCAlertCallback)&ModelWindow::releaseAlertCallback);
219 TCAlertManager::registerHandler(LDSnapshotTaker::alertClass(), this,
220 (TCAlertCallback)&ModelWindow::snapshotTakerAlertCallback);
221 if (programPath != NULL)
222 {
223 TCUserDefaults::setStringForKey(programPath, INSTALL_PATH_KEY, false);
224 TCUserDefaults::setStringForKey(programPath, INSTALL_PATH_4_1_KEY, false);
225 delete[] programPath;
226 }
227 #if defined(USE_CPP11) || !defined(_NO_BOOST)
228 if (remoteListener)
229 {
230 launchRemoteListener();
231 }
232 #endif // !_NO_BOOST
233 }
234
~ModelWindow(void)235 ModelWindow::~ModelWindow(void)
236 {
237 }
238
dealloc(void)239 void ModelWindow::dealloc(void)
240 {
241 #if defined(USE_CPP11) || !defined(_NO_BOOST)
242 if (remoteListener)
243 {
244 shutDownRemoteListener();
245 }
246 #endif // !_NO_BOOST
247 TCAlertManager::unregisterHandler(this);
248 TCObject::release(errorInfos);
249 TCObject::release(snapshotTaker);
250 errorInfos = NULL;
251 if (prefs)
252 {
253 prefs->release();
254 prefs = NULL;
255 }
256 if (errors)
257 {
258 errors->release();
259 errors = NULL;
260 }
261 if (modelViewer)
262 {
263 modelViewer->release();
264 modelViewer = NULL;
265 }
266 if (errorWindowResizer)
267 {
268 errorWindowResizer->release();
269 }
270 delete saveStepSuffix;
271 stopPolling();
272 CUIOGLWindow::dealloc();
273 }
274
275 #if defined(USE_CPP11) || !defined(_NO_BOOST)
276
277 #define PIPE_BUFSIZE 4096
278 #define PIPE_FILENAME _UC("\\\\.\\pipe\\LDViewRemoteControl")
279
shutDownRemoteListener(void)280 void ModelWindow::shutDownRemoteListener(void)
281 {
282 #ifdef USE_CPP11
283 std::unique_lock<std::mutex> lock(mutex);
284 #else
285 boost::mutex::scoped_lock lock(mutex);
286 #endif
287 exiting = true;
288 lock.unlock();
289 // Connect to the pipe to pull the ConnectNamedPipe
290 HANDLE hPipe = CreateFile(
291 PIPE_FILENAME,
292 GENERIC_WRITE,
293 0,
294 NULL,
295 OPEN_EXISTING,
296 0,
297 NULL);
298 if (hPipe != INVALID_HANDLE_VALUE)
299 {
300 CloseHandle(hPipe);
301 }
302 #ifdef USE_CPP11
303 if (listenerThread != NULL)
304 {
305 if (listenerFuture.wait_for(std::chrono::seconds(1)) == std::future_status::ready)
306 {
307 listenerThread->join();
308 }
309 else
310 {
311 // If it hasn't shut down after 1 second, abandon it.
312 listenerThread->detach();
313 }
314 }
315 #else
316 if (!listenerThread->timed_join(boost::posix_time::seconds(1)))
317 {
318 // If it hasn't shut down after 1 second, abandon it.
319 listenerThread->detach();
320 }
321 #endif
322 delete listenerThread;
323 }
324
launchRemoteListener(void)325 void ModelWindow::launchRemoteListener(void)
326 {
327 remoteCommandMap["highlight_line"] = RCHighlightLine;
328 remoteCommandMap["highlight_lines"] = RCHighlightLine;
329 remoteCommandMap["get_version"] = RCGetVersion;
330 ucstringtoutf8(ldviewVersion,
331 LDViewWindow::getProductVersion());
332 exiting = false;
333 remoteMessageID = RegisterWindowMessage(_UC("LDViewRemoteControl"));
334 try
335 {
336 #ifdef USE_CPP11
337 listenerFuture = listenerPromise.get_future();
338 listenerThread = new std::thread(&ModelWindow::listenerProc, this);
339 #else
340 listenerThread = new boost::thread(
341 boost::bind(&ModelWindow::listenerProc, this));
342 #endif
343 }
344 catch (...)
345 {
346 debugPrintf("error spawning listener thread");
347 }
348 }
349
listenerProc(void)350 void ModelWindow::listenerProc(void)
351 {
352 listenerProcInner();
353 #ifdef USE_CPP11
354 listenerPromise.set_value(true);
355 #endif
356 }
357
listenerProcInner(void)358 void ModelWindow::listenerProcInner(void)
359 {
360 while (true)
361 {
362 #ifdef USE_CPP11
363 std::unique_lock<std::mutex> lock(mutex);
364 #else
365 boost::mutex::scoped_lock lock(mutex);
366 #endif
367 if (exiting)
368 {
369 return;
370 }
371 lock.unlock();
372 HANDLE hPipe = CreateNamedPipe(
373 PIPE_FILENAME,
374 PIPE_ACCESS_DUPLEX,
375 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
376 PIPE_UNLIMITED_INSTANCES,
377 PIPE_BUFSIZE,
378 PIPE_BUFSIZE,
379 NMPWAIT_USE_DEFAULT_WAIT,
380 NULL);
381 if (hPipe == INVALID_HANDLE_VALUE)
382 {
383 debugPrintf("Error creating listener pipe.\n");
384 return;
385 }
386 if (!ConnectNamedPipe(hPipe, NULL))
387 {
388 if (GetLastError() != ERROR_PIPE_CONNECTED)
389 {
390 debugPrintf("Error connecting listener pipe to client.\n");
391 CloseHandle(hPipe);
392 return;
393 }
394 }
395 lock.lock();
396 if (exiting)
397 {
398 CloseHandle(hPipe);
399 return;
400 }
401 #ifdef USE_CPP11
402 std::thread remoteThread(&ModelWindow::remoteProc, this, hPipe);
403 #else
404 boost::thread remoteThread(boost::bind(&ModelWindow::remoteProc, this,
405 hPipe));
406 #endif
407 remoteThread.detach();
408 }
409 }
410
sendResponseMessage(HANDLE hPipe,const char * message)411 void ModelWindow::sendResponseMessage(HANDLE hPipe, const char *message)
412 {
413 DWORD numWritten;
414 DWORD messageLength = (DWORD)strlen(message);
415
416 // Note null terminator on message is optional.
417 if (WriteFile(hPipe, &messageLength, sizeof(messageLength), &numWritten,
418 NULL) && numWritten == sizeof(messageLength))
419 {
420 WriteFile(hPipe, message, messageLength, &numWritten, NULL);
421 }
422 }
423
sendVersionResponse(HANDLE hPipe)424 void ModelWindow::sendVersionResponse(HANDLE hPipe)
425 {
426 sendResponseMessage(hPipe, ldviewVersion.c_str());
427 }
428
remoteProc(HANDLE hPipe)429 void ModelWindow::remoteProc(HANDLE hPipe)
430 {
431 while (true)
432 {
433 DWORD messageSize;
434 DWORD readSize;
435 char *message;
436
437 if (ReadFile(hPipe, &messageSize, sizeof(messageSize), &readSize, NULL))
438 {
439 if (readSize != sizeof(messageSize))
440 {
441 debugPrintf("Remote message size failure.\n");
442 break;
443 }
444 }
445 else
446 {
447 break;
448 }
449 if (messageSize > 1000000)
450 {
451 // Don't even try to handle unreasonable messages.
452 break;
453 }
454 message = new char[messageSize + 1];
455 if (ReadFile(hPipe, message, messageSize, &readSize, NULL))
456 {
457 std::string command;
458 std::string data;
459
460 message[messageSize] = 0;
461 switch (parseRemoteMessage(message, command, data))
462 {
463 case RCGetVersion:
464 sendVersionResponse(hPipe);
465 delete message;
466 break;
467 default:
468 // Note: message is deleted by UI thread.
469 PostMessage(hWindow, remoteMessageID, 0, (LPARAM)message);
470 break;
471 }
472 }
473 else
474 {
475 delete message;
476 break;
477 }
478 }
479 CloseHandle(hPipe);
480 }
481
highlightLines(const std::string & paths)482 void ModelWindow::highlightLines(const std::string &paths)
483 {
484 modelViewer->setHighlightPaths(paths);
485 }
486
parseRemoteMessage(const char * message,std::string & command,std::string & data)487 ModelWindow::RemoteCommands ModelWindow::parseRemoteMessage(
488 const char *message,
489 std::string &command,
490 std::string &data)
491 {
492 const char *colonSpot = strchr(message, ':');
493 if (colonSpot != NULL)
494 {
495 command = message;
496 command.resize(colonSpot - message);
497 convertStringToLower(&command[0]);
498 data = &colonSpot[1];
499 return remoteCommandMap[command];
500 }
501 return RCUnknown;
502 }
503
processRemoteMessage(char * message)504 void ModelWindow::processRemoteMessage(char *message)
505 {
506 std::string command;
507 std::string data;
508
509 switch (parseRemoteMessage(message, command, data))
510 {
511 case RCHighlightLine:
512 highlightLines(data);
513 break;
514 default:
515 printf("Unrecognized remote command: %s(%s)\n", command.c_str(),
516 data.c_str());
517 break;
518 }
519 delete message;
520 }
521
522 #endif // !_NO_BOOST
523
ldlErrorCallback(LDLError * error)524 void ModelWindow::ldlErrorCallback(LDLError *error)
525 {
526 if (error && userLoad)
527 {
528 if (!errorCallback(error))
529 {
530 error->cancelLoad();
531 }
532 }
533 }
534
loadAlertCallback(TCAlert * alert)535 void ModelWindow::loadAlertCallback(TCAlert *alert)
536 {
537 if (strcmp(alert->getMessage(), "ModelLoadCanceled") == 0)
538 {
539 parentWindow->setTitle(_UC("LDView"));
540 stopPolling();
541 }
542 TCAlertManager::sendAlert(alertClass(), this, alert->getMessageUC());
543 }
544
redrawAlertCallback(TCAlert * alert)545 void ModelWindow::redrawAlertCallback(TCAlert *alert)
546 {
547 if (alert->getSender() == modelViewer)
548 {
549 redrawRequested = true;
550 forceRedraw();
551 }
552 }
553
captureAlertCallback(TCAlert * alert)554 void ModelWindow::captureAlertCallback(TCAlert *alert)
555 {
556 if (alert->getSender() == inputHandler)
557 {
558 captureMouse();
559 }
560 }
561
releaseAlertCallback(TCAlert * alert)562 void ModelWindow::releaseAlertCallback(TCAlert *alert)
563 {
564 if (alert->getSender() == inputHandler)
565 {
566 releaseMouse();
567 }
568 }
569
snapshotTakerAlertCallback(TCAlert * alert)570 void ModelWindow::snapshotTakerAlertCallback(TCAlert *alert)
571 {
572 if (alert->getSender() == snapshotTaker)
573 {
574 if (strcmp(alert->getMessage(), "MakeCurrent") == 0)
575 {
576 makeCurrent();
577 }
578 }
579 }
580
modelViewerAlertCallback(TCAlert * alert)581 void ModelWindow::modelViewerAlertCallback(TCAlert *alert)
582 {
583 if (alert)
584 {
585 stopAnimation();
586 MessageBox(hWindow, alert->getMessageUC(), _UC("LDView"),
587 MB_OK | MB_ICONWARNING);
588 }
589 }
590
progressAlertCallback(TCProgressAlert * alert)591 void ModelWindow::progressAlertCallback(TCProgressAlert *alert)
592 {
593 if (alert)
594 {
595 #if defined(USE_CPP11) || !defined(_NO_BOOST)
596 if (strcmp(alert->getSource(), LD_LIBRARY_UPDATER) != 0)
597 #endif //_NO_BOOST
598 {
599 bool showErrors = true;
600
601 if (strcmp(alert->getSource(), "LDSnapshotTaker") == 0)
602 {
603 showErrors = false;
604 }
605 if (!progressCallback(alert->getMessageUC(), alert->getProgress(),
606 strcmp(alert->getSource(), "TCImageFormat") == 0, showErrors))
607 {
608 alert->abort();
609 }
610 // printf("Progress message from %s:\n%s (%f)\n", alert->getSource(),
611 // alert->getMessage(), alert->getProgress());
612 }
613 }
614 }
615
loadSettings(void)616 void ModelWindow::loadSettings(void)
617 {
618 pollSetting = TCUserDefaults::longForKey(POLL_KEY, 0, false);
619 viewMode = (LDInputHandler::ViewMode)TCUserDefaults::longForKey(
620 VIEW_MODE_KEY, 0, false);
621 loadPrintSettings();
622 loadSaveSettings();
623 }
624
loadPrintSettings(void)625 void ModelWindow::loadPrintSettings(void)
626 {
627 printLeftMargin = TCUserDefaults::longForKey(LEFT_MARGIN_KEY, 500, false) /
628 1000.0f;
629 printRightMargin = TCUserDefaults::longForKey(RIGHT_MARGIN_KEY, 500,
630 false) / 1000.0f;
631 printTopMargin = TCUserDefaults::longForKey(TOP_MARGIN_KEY, 500, false) /
632 1000.0f;
633 printBottomMargin = TCUserDefaults::longForKey(BOTTOM_MARGIN_KEY, 500,
634 false) / 1000.0f;
635 printOrientation = TCUserDefaults::longForKey(ORIENTATION_KEY,
636 DMORIENT_PORTRAIT, false);
637 printPaperSize = TCUserDefaults::longForKey(PAPER_SIZE_KEY, DMPAPER_LETTER,
638 false);
639 usePrinterDPI = TCUserDefaults::longForKey(USE_PRINTER_DPI_KEY, 1) != 0;
640 printDPI = TCUserDefaults::longForKey(PRINT_DPI_KEY, 300);
641 printBackground = TCUserDefaults::longForKey(PRINT_BACKGROUND_KEY, 0, false)
642 != 0;
643 }
644
loadSaveSettings(void)645 void ModelWindow::loadSaveSettings(void)
646 {
647 saveActualSize = TCUserDefaults::longForKey(SAVE_ACTUAL_SIZE_KEY, 1, false)
648 != 0;
649 saveWidth = TCUserDefaults::longForKey(SAVE_WIDTH_KEY, 1024, false);
650 saveHeight = TCUserDefaults::longForKey(SAVE_HEIGHT_KEY, 768, false);
651 saveZoomToFit = TCUserDefaults::longForKey(SAVE_ZOOM_TO_FIT_KEY, 1, false)
652 != 0;
653 saveSeries = TCUserDefaults::longForKey(SAVE_SERIES_KEY, 1, false) != 0;
654 saveDigits = TCUserDefaults::longForKey(SAVE_DIGITS_KEY, 1, false);
655 ignorePBuffer = TCUserDefaults::longForKey(IGNORE_PBUFFER_KEY, 0, false)
656 != 0;
657 ignoreFBO = TCUserDefaults::longForKey(IGNORE_FRAMEBUFFER_OBJECT_KEY, 0,
658 false) != 0;
659 ignorePixelFormat = TCUserDefaults::longForKey(IGNORE_PIXEL_FORMAT_KEY, 0,
660 false) != 0;
661 saveImageType = TCUserDefaults::longForKey(SAVE_IMAGE_TYPE_KEY, 1, false);
662 saveExportType = TCUserDefaults::longForKey(SAVE_EXPORT_TYPE_KEY,
663 LDrawModelViewer::ETPov, false);
664 saveAlpha = TCUserDefaults::longForKey(SAVE_ALPHA_KEY, 0, false) != 0;
665 autoCrop = TCUserDefaults::boolForKey(AUTO_CROP_KEY, false, false);
666 saveAllSteps = TCUserDefaults::boolForKey(SAVE_STEPS_KEY, false, false);
667 delete[] saveStepSuffix;
668 saveStepSuffix = TCUserDefaults::stringForKeyUC(SAVE_STEPS_SUFFIX_KEY,
669 ls(_UC("DefaultStepSuffix")), false);
670 saveStepsSameScale = TCUserDefaults::boolForKey(SAVE_STEPS_SAME_SCALE_KEY,
671 true, false);
672 }
673
674 // Note: static function
roundUp(int value,int nearest)675 int ModelWindow::roundUp(int value, int nearest)
676 {
677 return (value + nearest - 1) / nearest * nearest;
678 }
679
setFilename(const char * value)680 void ModelWindow::setFilename(const char* value)
681 {
682 modelViewer->setFilename(value);
683 checkForPart();
684 }
685
getFilename(void)686 char* ModelWindow::getFilename(void)
687 {
688 return modelViewer->getFilename();
689 }
690
update(void)691 void ModelWindow::update(void)
692 {
693 doPaint();
694 }
695
finalSetup(void)696 void ModelWindow::finalSetup(void)
697 {
698 }
699
getFileTime(FILETIME * fileTime)700 bool ModelWindow::getFileTime(FILETIME* fileTime)
701 {
702 return getFileInfo(fileTime, NULL, NULL);
703 }
704
getFileInfo(FILETIME * fileTime,DWORD * fileSizeHigh,DWORD * fileSizeLow)705 bool ModelWindow::getFileInfo(FILETIME* fileTime, DWORD* fileSizeHigh, DWORD* fileSizeLow)
706 {
707 const char *filename;
708
709 if (modelViewer && (filename = modelViewer->getFilename()) != NULL)
710 {
711 WIN32_FIND_DATA findBuf;
712 HANDLE findHandle;
713 ucstring ucFilename;
714
715 utf8toucstring(ucFilename, filename);
716 findHandle = FindFirstFile(ucFilename.c_str(), &findBuf);
717 if (findHandle != INVALID_HANDLE_VALUE)
718 {
719 if (fileTime != NULL)
720 {
721 *fileTime = findBuf.ftLastWriteTime;
722 }
723 if (fileSizeHigh != NULL && fileSizeLow != NULL)
724 {
725 *fileSizeHigh = findBuf.nFileSizeHigh;
726 *fileSizeLow = findBuf.nFileSizeLow;
727 }
728 FindClose(findHandle);
729 return true;
730 }
731 }
732 return false;
733 }
734
checkFileForUpdates(void)735 void ModelWindow::checkFileForUpdates(void)
736 {
737 if (pollTimerRunning)
738 {
739 FILETIME newWriteTime;
740 DWORD newFileSizeHigh, newFileSizeLow;
741
742 stopPolling();
743 if (getFileInfo(&newWriteTime, &newFileSizeHigh, &newFileSizeLow))
744 {
745 if (lastWriteTime.dwLowDateTime != newWriteTime.dwLowDateTime ||
746 lastWriteTime.dwHighDateTime != newWriteTime.dwHighDateTime)
747 {
748 if (newFileSizeHigh != lastFileSizeHigh || newFileSizeLow != lastFileSizeLow)
749 {
750 // A full half second must pass without any changes to the file
751 // size before we consider the file update to be complete.
752 startPolling();
753 lastFileSizeHigh = newFileSizeHigh;
754 lastFileSizeLow = newFileSizeLow;
755 return;
756 }
757 lastFileSizeHigh = lastFileSizeLow = 0;
758 bool update = true;
759
760 lastWriteTime = newWriteTime;
761 if (pollSetting == POLL_PROMPT)
762 {
763 if (captureCount)
764 {
765 while (captureCount)
766 {
767 releaseMouse();
768 }
769 inputHandler->cancelMouseDrag();
770 }
771 stopAnimation();
772 if (MessageBox(hWindow, ls(_UC("PollReloadCheck")),
773 ls(_UC("PollFileUpdate")),
774 MB_OKCANCEL | MB_APPLMODAL | MB_ICONQUESTION) !=
775 IDOK)
776 {
777 update = false;
778 }
779 }
780 if (update)
781 {
782 reload();
783 }
784 }
785 }
786 startPolling();
787 }
788 }
789
openGlWillEnd(void)790 void ModelWindow::openGlWillEnd(void)
791 {
792 if (modelViewer)
793 {
794 modelViewer->openGlWillEnd();
795 }
796 }
797
updateFSAA()798 void ModelWindow::updateFSAA()
799 {
800 applyingPrefs = true;
801 uncompile();
802 closeWindow();
803 if (!((LDViewWindow*)parentWindow)->getFullScreen())
804 {
805 x -= 2;
806 y -= 2;
807 width += 4;
808 height += 4;
809 }
810 initWindow();
811 if (modelViewer)
812 {
813 modelViewer->uncompile();
814 }
815 showWindow(SW_SHOW);
816 applyingPrefs = false;
817 killTimer(FSAA_UPDATE_TIMER);
818 forceRedraw();
819 if (hStatusBar)
820 {
821 // For some unknown reason, the status bar only updates its text on the
822 // fly while the model is rotating if it is created after the model
823 // window. Since we just destroyed and recreated the model window, we
824 // need to destroy and recreate the status window.
825 ((LDViewWindow*)parentWindow)->switchStatusBar();
826 ((LDViewWindow*)parentWindow)->switchStatusBar();
827 }
828 }
829
doTimer(UINT_PTR timerID)830 LRESULT ModelWindow::doTimer(UINT_PTR timerID)
831 {
832 switch (timerID)
833 {
834 case POLL_TIMER:
835 checkFileForUpdates();
836 break;
837 case FSAA_UPDATE_TIMER:
838 updateFSAA();
839 break;
840 }
841 return 0;
842 }
843
captureMouse(void)844 void ModelWindow::captureMouse(void)
845 {
846 SetCapture(hWindow);
847 }
848
releaseMouse(void)849 void ModelWindow::releaseMouse(void)
850 {
851 releasingMouse = true;
852 ReleaseCapture();
853 releasingMouse = false;
854 }
855
856 // NOTE: Static method.
altPressed(void)857 bool ModelWindow::altPressed(void)
858 {
859 return (GetKeyState(VK_MENU) & 0x8000) != 0;
860 }
861
862 // Note: static method.
convertKeyModifiers(TCULong osModifiers)863 TCULong ModelWindow::convertKeyModifiers(TCULong osModifiers)
864 {
865 TCULong retValue = 0;
866
867 if (osModifiers & MK_SHIFT)
868 {
869 retValue |= LDInputHandler::MKShift;
870 }
871 if (osModifiers & MK_CONTROL)
872 {
873 retValue |= LDInputHandler::MKControl;
874 }
875 return retValue;
876 }
877
878 // Note: static method.
getCurrentKeyModifiers(void)879 TCULong ModelWindow::getCurrentKeyModifiers(void)
880 {
881 TCULong retValue = 0;
882
883 if (GetKeyState(VK_SHIFT) & 0x8000)
884 {
885 retValue |= LDInputHandler::MKShift;
886 }
887 if (GetKeyState(VK_CONTROL) & 0x8000)
888 {
889 retValue |= LDInputHandler::MKControl;
890 }
891 return retValue;
892 }
893
894 // Note: static method.
convertKeyCode(TCULong osKeyCode)895 LDInputHandler::KeyCode ModelWindow::convertKeyCode(TCULong osKeyCode)
896 {
897 if (isalpha(osKeyCode))
898 {
899 return (LDInputHandler::KeyCode)(toupper(osKeyCode) - 'A' +
900 LDInputHandler::KCA);
901 }
902 else
903 {
904 switch (osKeyCode)
905 {
906 case VK_RETURN:
907 return LDInputHandler::KCReturn;
908 case VK_SHIFT:
909 return LDInputHandler::KCShift;
910 case VK_CONTROL:
911 return LDInputHandler::KCControl;
912 case VK_MENU:
913 return LDInputHandler::KCAlt;
914 case VK_SPACE:
915 return LDInputHandler::KCSpace;
916 case VK_PRIOR:
917 return LDInputHandler::KCPageUp;
918 case VK_NEXT:
919 return LDInputHandler::KCPageDown;
920 case VK_END:
921 return LDInputHandler::KCEnd;
922 case VK_HOME:
923 return LDInputHandler::KCHome;
924 case VK_ESCAPE:
925 return LDInputHandler::KCEscape;
926 case VK_LEFT:
927 return LDInputHandler::KCLeft;
928 case VK_UP:
929 return LDInputHandler::KCUp;
930 case VK_RIGHT:
931 return LDInputHandler::KCRight;
932 case VK_DOWN:
933 return LDInputHandler::KCDown;
934 case VK_INSERT:
935 return LDInputHandler::KCInsert;
936 case VK_DELETE:
937 return LDInputHandler::KCDelete;
938 default:
939 return LDInputHandler::KCUnknown;
940 }
941 }
942 }
943
doLButtonDown(WPARAM keyFlags,int xPos,int yPos)944 LRESULT ModelWindow::doLButtonDown(WPARAM keyFlags, int xPos, int yPos)
945 {
946 if (inputHandler->mouseDown(convertKeyModifiers((TCULong)keyFlags),
947 LDInputHandler::MBLeft, unscalePixels(xPos), unscalePixels(yPos)))
948 {
949 return 0;
950 }
951 return 1;
952 }
953
doLButtonUp(WPARAM keyFlags,int xPos,int yPos)954 LRESULT ModelWindow::doLButtonUp(WPARAM keyFlags, int xPos, int yPos)
955 {
956 if (inputHandler->mouseUp((TCULong)keyFlags, LDInputHandler::MBLeft,
957 unscalePixels(xPos), unscalePixels(yPos)))
958 {
959 return 0;
960 }
961 return 1;
962 }
963
doRButtonDown(WPARAM keyFlags,int xPos,int yPos)964 LRESULT ModelWindow::doRButtonDown(WPARAM keyFlags, int xPos, int yPos)
965 {
966 if (inputHandler->mouseDown(convertKeyModifiers((TCULong)keyFlags),
967 LDInputHandler::MBRight, unscalePixels(xPos), unscalePixels(yPos)))
968 {
969 return 0;
970 }
971 return 1;
972 }
973
doRButtonUp(WPARAM keyFlags,int xPos,int yPos)974 LRESULT ModelWindow::doRButtonUp(WPARAM keyFlags, int xPos, int yPos)
975 {
976 if (inputHandler->mouseUp((TCULong)keyFlags, LDInputHandler::MBRight,
977 unscalePixels(xPos), unscalePixels(yPos)))
978 {
979 return 0;
980 }
981 return 1;
982 }
983
doMButtonDown(WPARAM keyFlags,int xPos,int yPos)984 LRESULT ModelWindow::doMButtonDown(WPARAM keyFlags, int xPos, int yPos)
985 {
986 if (inputHandler->mouseDown(convertKeyModifiers((TCULong)keyFlags),
987 LDInputHandler::MBMiddle, unscalePixels(xPos), unscalePixels(yPos)))
988 {
989 return 0;
990 }
991 return 1;
992 }
993
doMButtonUp(WPARAM keyFlags,int xPos,int yPos)994 LRESULT ModelWindow::doMButtonUp(WPARAM keyFlags, int xPos, int yPos)
995 {
996 if (inputHandler->mouseUp((TCULong)keyFlags, LDInputHandler::MBMiddle,
997 unscalePixels(xPos), unscalePixels(yPos)))
998 {
999 return 0;
1000 }
1001 return 1;
1002 }
1003
doCaptureChanged(HWND)1004 LRESULT ModelWindow::doCaptureChanged(HWND /*hNewWnd*/)
1005 {
1006 if (!releasingMouse && inputHandler->mouseCaptureChanged())
1007 {
1008 return 0;
1009 }
1010 return 1;
1011 }
1012
doMouseMove(WPARAM keyFlags,int xPos,int yPos)1013 LRESULT ModelWindow::doMouseMove(WPARAM keyFlags, int xPos, int yPos)
1014 {
1015 if (inputHandler->mouseMove(convertKeyModifiers((TCULong)keyFlags),
1016 unscalePixels(xPos), unscalePixels(yPos)))
1017 {
1018 return 0;
1019 }
1020 return 1;
1021 }
1022
mouseWheel(short keyFlags,short zDelta)1023 void ModelWindow::mouseWheel(short keyFlags, short zDelta)
1024 {
1025 inputHandler->mouseWheel(convertKeyModifiers(keyFlags),
1026 (TCFloat)zDelta);
1027 }
1028
doEraseBackground(RECT *)1029 LRESULT ModelWindow::doEraseBackground(RECT* /*updateRect*/)
1030 {
1031 created = TRUE;
1032 return 1;
1033 }
1034
doSize(WPARAM sizeType,int newWidth,int newHeight)1035 LRESULT ModelWindow::doSize(WPARAM sizeType, int newWidth, int newHeight)
1036 {
1037 RECT rect;
1038 POINT point;
1039 LRESULT retValue;
1040
1041 GetWindowRect(hWindow, &rect);
1042 point.x = rect.left;
1043 point.y = rect.top;
1044 ScreenToClient(hParentWindow, &point);
1045 if (hPBufferGLRC)
1046 {
1047 wglMakeCurrent(hdc, hglrc);
1048 }
1049 retValue = CUIOGLWindow::doSize(sizeType, newWidth, newHeight);
1050 if (modelViewer && !hPBufferGLRC)
1051 {
1052 updateModelViewerSize();
1053 }
1054 if (hPBufferGLRC)
1055 {
1056 makeCurrent();
1057 }
1058 return retValue;
1059 }
1060
sizeView(void)1061 void ModelWindow::sizeView(void)
1062 {
1063 }
1064
perspectiveView(void)1065 void ModelWindow::perspectiveView(void)
1066 {
1067 modelViewer->perspectiveView();
1068 }
1069
forceRedraw(int count)1070 void ModelWindow::forceRedraw(int count)
1071 {
1072 if (hWindow)
1073 {
1074 InvalidateRect(hWindow, NULL, FALSE);
1075 }
1076 redrawCount += count;
1077 }
1078
setZoomSpeed(TCFloat value)1079 void ModelWindow::setZoomSpeed(TCFloat value)
1080 {
1081 modelViewer->setZoomSpeed(value);
1082 }
1083
getZoomSpeed(void)1084 TCFloat ModelWindow::getZoomSpeed(void)
1085 {
1086 return modelViewer->getZoomSpeed();
1087 }
1088
resetView(LDVAngle viewAngle)1089 void ModelWindow::resetView(LDVAngle viewAngle)
1090 {
1091 modelViewer->resetView(viewAngle);
1092 modelViewer->setXRotate(0.0f);
1093 modelViewer->setYRotate(0.0f);
1094 stopAnimation();
1095 fps = 0.0f;
1096 forceRedraw();
1097 }
1098
saveDefaultView(void)1099 void ModelWindow::saveDefaultView(void)
1100 {
1101 prefs->saveDefaultView();
1102 }
1103
resetDefaultView(void)1104 void ModelWindow::resetDefaultView(void)
1105 {
1106 prefs->resetDefaultView();
1107 }
1108
reload(void)1109 void ModelWindow::reload(void)
1110 {
1111 clearErrors();
1112 modelViewer->setNeedsReload();
1113 forceRedraw();
1114 }
1115
recompile(void)1116 void ModelWindow::recompile(void)
1117 {
1118 modelViewer->recompile();
1119 }
1120
uncompile(void)1121 void ModelWindow::uncompile(void)
1122 {
1123 if (modelViewer)
1124 {
1125 modelViewer->uncompile();
1126 }
1127 }
1128
doErrorOK(void)1129 BOOL ModelWindow::doErrorOK(void)
1130 {
1131 doDialogClose(hErrorWindow);
1132 return TRUE;
1133 }
1134
doProgressCancel(void)1135 void ModelWindow::doProgressCancel(void)
1136 {
1137 cancelLoad = true;
1138 }
1139
getTreeViewLine(HWND hTreeView,HTREEITEM hItem,TCStringArray * lines)1140 void ModelWindow::getTreeViewLine(HWND hTreeView, HTREEITEM hItem,
1141 TCStringArray *lines)
1142 {
1143 TVITEM item;
1144 UCCHAR buf[1024];
1145 ucstring line;
1146 int depth = 0;
1147 HTREEITEM hParentItem = hItem;
1148
1149 while ((hParentItem = TreeView_GetParent(hTreeView, hParentItem)) != NULL)
1150 {
1151 depth++;
1152 }
1153 item.mask = TVIF_TEXT;
1154 item.hItem = hItem;
1155 item.pszText = buf;
1156 item.cchTextMax = COUNT_OF(buf);
1157 if (TreeView_GetItem(hTreeView, &item))
1158 {
1159 int i;
1160
1161 for (i = 0; i < depth; i++)
1162 {
1163 line += _UC('\t');
1164 }
1165 line += item.pszText;
1166 std::string utf8Buf;
1167 ucstringtoutf8(utf8Buf, line);
1168 lines->addString(utf8Buf.c_str());
1169 }
1170 }
1171
doErrorTreeCopy(void)1172 BOOL ModelWindow::doErrorTreeCopy(void)
1173 {
1174 HTREEITEM hItem = TreeView_GetSelection(hErrorTree);
1175
1176 if (hItem)
1177 {
1178 HTREEITEM hParentItem = TreeView_GetParent(hErrorTree, hItem);
1179 TCStringArray* textLines = new TCStringArray;
1180 int i;
1181 int count;
1182
1183 while (hParentItem)
1184 {
1185 hItem = hParentItem;
1186 hParentItem = TreeView_GetParent(hErrorTree, hItem);
1187 }
1188 getTreeViewLine(hErrorTree, hItem, textLines);
1189 hItem = TreeView_GetChild(hErrorTree, hItem);
1190 while (hItem)
1191 {
1192 getTreeViewLine(hErrorTree, hItem, textLines);
1193 hItem = TreeView_GetNextSibling(hErrorTree, hItem);
1194 }
1195 count = textLines->getCount();
1196 if (count)
1197 {
1198 size_t len = 1;
1199 char *buf;
1200
1201 for (i = 0; i < count; i++)
1202 {
1203 len += strlen((*textLines)[i]) + 2;
1204 }
1205 buf = new char[len];
1206 buf[0] = 0;
1207 for (i = 0; i < count; i++)
1208 {
1209 strcat(buf, (*textLines)[i]);
1210 strcat(buf, "\r\n");
1211 }
1212 if (copyToClipboard(buf))
1213 {
1214 delete buf;
1215 SetWindowLongPtr(hErrorWindow, DWLP_MSGRESULT, TRUE);
1216 return TRUE;
1217 }
1218 delete buf;
1219 }
1220 }
1221 return FALSE;
1222 }
1223
doErrorTreeKeyDown(LPNMTVKEYDOWN notification)1224 BOOL ModelWindow::doErrorTreeKeyDown(LPNMTVKEYDOWN notification)
1225 {
1226 // debugPrintf("ModelWindow::doErrorTreeKeyDown: 0x%08X, 0x%04X, 0x%08X\n",
1227 // notification->hdr.code, notification->wVKey, notification->flags);
1228 if (notification->wVKey == 'C' && (GetKeyState(VK_CONTROL) & 0x8000))
1229 {
1230 return doErrorTreeCopy();
1231 }
1232 return FALSE;
1233 }
1234
doErrorWindowNotify(LPNMHDR notification)1235 BOOL ModelWindow::doErrorWindowNotify(LPNMHDR notification)
1236 {
1237 // debugPrintf("ModelWindow::doErrorWindowNotify: %d\n", notification->code);
1238 switch (notification->code)
1239 {
1240 case LVN_ITEMCHANGED:
1241 LPNMLISTVIEW info = (LPNMLISTVIEW)notification;
1242 if (info->uNewState != info->uOldState)
1243 {
1244 BOOL value = ListView_GetCheckState(hErrorList, info->iItem);
1245 ErrorInfo *errorInfo = (*errorInfos)[info->iItem];
1246 char *errorKey = getErrorKey(errorInfo->getType());
1247
1248 // The new state/old state check lies when you click on an item, and
1249 // not the item's check box.
1250 if (TCUserDefaults::longForKey(errorKey, 0, false) != value)
1251 {
1252 TCUserDefaults::setLongForKey(value, errorKey, false);
1253 if (!skipErrorUpdates)
1254 {
1255 clearErrorTree();
1256 populateErrorTree();
1257 }
1258 }
1259 }
1260 break;
1261 }
1262 return FALSE;
1263 }
1264
doErrorTreeNotify(LPNMHDR notification)1265 BOOL ModelWindow::doErrorTreeNotify(LPNMHDR notification)
1266 {
1267 // debugPrintf("ModelWindow::doErrorTreeNotify: %d\n", notification->code);
1268 if (notification->code == NM_DBLCLK)
1269 {
1270 HTREEITEM hSelectedItem = TreeView_GetSelection(hErrorTree);
1271
1272 // debugPrintf("double click!\n");
1273 if (hSelectedItem)
1274 {
1275 TVITEM selectedItem;
1276 UCCHAR buf[1024];
1277
1278 selectedItem.mask = TVIF_TEXT;
1279 selectedItem.hItem = hSelectedItem;
1280 selectedItem.pszText = buf;
1281 selectedItem.cchTextMax = COUNT_OF(buf);
1282 if (TreeView_GetItem(hErrorTree, &selectedItem))
1283 {
1284 if (stringHasPrefix(selectedItem.pszText,
1285 ls(_UC("ErrorTreeFilePrefix"))))
1286 {
1287 UCSTR editor = TCUserDefaults::stringForKeyUC(EDITOR_KEY,
1288 _UC("notepad.exe"), false);
1289
1290 ShellExecute(hWindow, NULL, editor, buf + 6, _UC("."),
1291 SW_SHOWNORMAL);
1292 delete[] editor;
1293 }
1294 }
1295 }
1296 else
1297 {
1298 // debugPrintf("No selection.\n");
1299 }
1300 }
1301 else if (notification->code == TVN_KEYDOWN)
1302 {
1303 return doErrorTreeKeyDown((LPNMTVKEYDOWN)notification);
1304 }
1305 return FALSE;
1306 }
1307
doDialogNotify(HWND hDlg,int controlId,LPNMHDR notification)1308 BOOL ModelWindow::doDialogNotify(HWND hDlg, int controlId, LPNMHDR notification)
1309 {
1310 // debugPrintf("ModelWindow::doDialogNotify: 0x%04X, 0x%04X, 0x%04x\n", hDlg,
1311 // controlId, notification->code);
1312 if (hDlg == hErrorWindow)
1313 {
1314 if (controlId == IDC_ERROR_TREE)
1315 {
1316 return doErrorTreeNotify(notification);
1317 }
1318 else
1319 {
1320 return doErrorWindowNotify(notification);
1321 }
1322 }
1323 else if (hDlg == hSaveDialog)
1324 {
1325 return doSaveNotify(controlId, (LPOFNOTIFY)notification);
1326 }
1327 return FALSE;
1328 }
1329
doErrorSize(WPARAM sizeType,int newWidth,int newHeight)1330 BOOL ModelWindow::doErrorSize(WPARAM sizeType, int newWidth, int newHeight)
1331 {
1332 //RECT sizeRect;
1333
1334 SendMessage(hErrorStatusWindow, WM_SIZE, sizeType,
1335 MAKELPARAM(newWidth, newHeight));
1336 //GetClientRect(hErrorWindow, &sizeRect);
1337 errorWindowResizer->resize(newWidth, newHeight);
1338 return FALSE;
1339 }
1340
doSaveSize(WPARAM sizeType,int newWidth,int newHeight)1341 BOOL ModelWindow::doSaveSize(WPARAM sizeType, int newWidth, int newHeight)
1342 {
1343 if (saveWindowResizer)
1344 {
1345 if (sizeType != SW_MINIMIZE)
1346 {
1347 saveWindowResizer->resize(newWidth, newHeight);
1348 positionSaveAddOn();
1349 }
1350 }
1351 return FALSE;
1352 }
1353
positionSaveOptionsButton(void)1354 void ModelWindow::positionSaveOptionsButton(void)
1355 {
1356 RECT optionsButtonRect;
1357 RECT typeComboRect;
1358 HWND hParent = GetParent(hSaveDialog);
1359 HWND hTypeCombo = GetDlgItem(hParent, cmb1);
1360 int typeComboWidth;
1361 int typeComboHeight;
1362 int optionsButtonWidth;
1363 int optionsButtonHeight;
1364
1365 // Move the Options button so that it is to the right of the file type
1366 // combo box.
1367 GetWindowRect(hTypeCombo, &typeComboRect);
1368 screenToClient(hParent, &typeComboRect);
1369 GetWindowRect(hSaveOptionsButton, &optionsButtonRect);
1370 optionsButtonWidth = optionsButtonRect.right - optionsButtonRect.left;
1371 optionsButtonHeight = optionsButtonRect.bottom - optionsButtonRect.top;
1372 typeComboWidth = typeComboRect.right - typeComboRect.left;
1373 typeComboHeight = typeComboRect.bottom - typeComboRect.top;
1374 clientToScreen(hParent, &typeComboRect);
1375 screenToClient(hSaveDialog, &typeComboRect);
1376
1377 MoveWindow(hSaveOptionsButton, typeComboRect.right + 6,
1378 typeComboRect.top + typeComboHeight / 2 - optionsButtonHeight / 2,
1379 optionsButtonWidth, optionsButtonHeight, TRUE);
1380 }
1381
positionSaveAddOn(void)1382 void ModelWindow::positionSaveAddOn(void)
1383 {
1384 HWND hParent = GetParent(hSaveDialog);
1385 RECT parentClientRect;
1386 RECT addOnRect;
1387 int windowWidth;
1388 int windowHeight;
1389
1390 GetClientRect(hParent, &parentClientRect);
1391 GetWindowRect(hSaveDialog, &addOnRect);
1392 screenToClient(hParent, &addOnRect);
1393 windowWidth = parentClientRect.right - parentClientRect.left;
1394 windowHeight = parentClientRect.bottom - parentClientRect.top;
1395 if (addOnRect.left != 0 || addOnRect.top != 0 ||
1396 addOnRect.right != windowWidth || addOnRect.bottom != windowHeight)
1397 {
1398 // Only move it if it has actually changed position. That's because
1399 // this function is called from doSaveSize, and we don't want to go
1400 // into an infinite loop.
1401 MoveWindow(hSaveDialog, 0, 0, windowWidth, windowHeight, TRUE);
1402 }
1403 positionSaveOptionsButton();
1404 }
1405
doSaveInitDone(OFNOTIFY *)1406 BOOL ModelWindow::doSaveInitDone(OFNOTIFY * /*ofNotify*/)
1407 {
1408 RECT optionsButtonRect;
1409 RECT typeComboRect;
1410 RECT miscRect;
1411 RECT parentRect;
1412 RECT cancelRect;
1413 RECT windowRect;
1414 HWND hParent = GetParent(hSaveDialog);
1415 HWND hMiscBox = GetDlgItem(hSaveDialog, IDC_MISC_BOX);
1416 HWND hCancelButton = GetDlgItem(hParent, IDCANCEL);
1417 HWND hTypeCombo = GetDlgItem(hParent, cmb1);
1418 int typeComboWidth;
1419 int typeComboHeight;
1420 int optionsButtonWidth;
1421
1422 // Shrink the type combo to make space for the options button.
1423 GetWindowRect(hTypeCombo, &typeComboRect);
1424 GetWindowRect(hSaveOptionsButton, &optionsButtonRect);
1425 screenToClient(hParent, &typeComboRect);
1426 optionsButtonWidth = optionsButtonRect.right - optionsButtonRect.left;
1427 typeComboWidth = typeComboRect.right - typeComboRect.left
1428 - optionsButtonWidth - 6;
1429 typeComboHeight = typeComboRect.bottom - typeComboRect.top;
1430 MoveWindow(hTypeCombo, typeComboRect.left, typeComboRect.top,
1431 typeComboWidth, typeComboHeight, TRUE);
1432
1433 // Resize the add-on window so that the right margin between the misc box
1434 // and the add-on window is the same as the right margin between the save
1435 // dialog's cancel button and the save dialog. That way, the resizer will
1436 // consider that to be the "proper" right margin, and when we resize the
1437 // add-on to fill the available space, everything will size properly.
1438 GetClientRect(hParent, &parentRect);
1439 GetWindowRect(hCancelButton, &cancelRect);
1440 screenToClient(hParent, &cancelRect);
1441 GetWindowRect(hMiscBox, &miscRect);
1442 screenToClient(hSaveDialog, &miscRect);
1443 GetClientRect(hParent, &windowRect);
1444 windowRect.right = miscRect.right + parentRect.right - cancelRect.right;
1445 MoveWindow(hSaveDialog, 0, 0, windowRect.right, windowRect.bottom, TRUE);
1446
1447 saveWindowResizer = new CUIWindowResizer;
1448 saveWindowResizer->setHWindow(hSaveDialog);
1449
1450 if (curSaveOp == LDPreferences::SOSnapshot)
1451 {
1452 saveWindowResizer->addSubWindow(IDC_SAVE_SERIES_BOX,
1453 CUISizeHorizontal | CUIFloatRight | CUIFloatTop);
1454 saveWindowResizer->addSubWindow(IDC_SAVE_SERIES,
1455 CUIFloatRight | CUIFloatTop);
1456 saveWindowResizer->addSubWindow(IDC_SAVE_DIGITS_LABEL,
1457 CUIFloatRight | CUIFloatTop);
1458 saveWindowResizer->addSubWindow(IDC_SAVE_DIGITS,
1459 CUIFloatRight | CUIFloatTop);
1460 saveWindowResizer->addSubWindow(IDC_SAVE_DIGITS_SPIN,
1461 CUIFloatRight | CUIFloatTop);
1462
1463 saveWindowResizer->addSubWindow(IDC_SAVE_ACTUAL_SIZE_BOX,
1464 CUISizeHorizontal | CUIFloatRight | CUIFloatTop);
1465 saveWindowResizer->addSubWindow(IDC_SAVE_ACTUAL_SIZE,
1466 CUIFloatRight | CUIFloatTop);
1467 saveWindowResizer->addSubWindow(IDC_SAVE_WIDTH_LABEL,
1468 CUIFloatRight | CUIFloatTop);
1469 saveWindowResizer->addSubWindow(IDC_SAVE_WIDTH,
1470 CUIFloatRight | CUIFloatTop);
1471 saveWindowResizer->addSubWindow(IDC_SAVE_HEIGHT_LABEL,
1472 CUIFloatRight | CUIFloatTop);
1473 saveWindowResizer->addSubWindow(IDC_SAVE_HEIGHT,
1474 CUIFloatRight | CUIFloatTop);
1475 saveWindowResizer->addSubWindow(IDC_SAVE_ZOOMTOFIT,
1476 CUIFloatRight | CUIFloatTop);
1477
1478 saveWindowResizer->addSubWindow(IDC_ALL_STEPS_BOX,
1479 CUIFloatLeft | CUISizeHorizontal | CUIFloatTop);
1480 saveWindowResizer->addSubWindow(IDC_STEP_SUFFIX_LABEL,
1481 CUIFloatLeft | CUIFloatTop | CUIFloatRight);
1482 saveWindowResizer->addSubWindow(IDC_STEP_SUFFIX,
1483 CUIFloatLeft | CUIFloatTop | CUIFloatRight);
1484 saveWindowResizer->addSubWindow(IDC_SAME_SCALE,
1485 CUIFloatLeft | CUIFloatTop | CUIFloatRight);
1486
1487 saveWindowResizer->addSubWindow(IDC_MISC_BOX,
1488 CUIFloatLeft | CUISizeHorizontal | CUIFloatTop);
1489 saveWindowResizer->addSubWindow(IDC_ALL_STEPS,
1490 CUIFloatLeft | CUIFloatTop | CUIFloatRight);
1491 saveWindowResizer->addSubWindow(IDC_IGNORE_PBUFFER,
1492 CUIFloatLeft | CUIFloatTop | CUIFloatRight);
1493 saveWindowResizer->addSubWindow(IDC_IGNORE_FBO,
1494 CUIFloatLeft | CUIFloatTop | CUIFloatRight);
1495 saveWindowResizer->addSubWindow(IDC_IGNORE_PIXEL_FORMAT,
1496 CUIFloatLeft | CUIFloatTop | CUIFloatRight);
1497 saveWindowResizer->addSubWindow(IDC_TRANSPARENT_BACKGROUND,
1498 CUIFloatLeft | CUIFloatTop | CUIFloatRight);
1499 saveWindowResizer->addSubWindow(IDC_AUTO_CROP,
1500 CUIFloatLeft | CUIFloatTop | CUIFloatRight);
1501 }
1502 positionSaveAddOn();
1503
1504 return FALSE;
1505 }
1506
doDialogSize(HWND hDlg,WPARAM sizeType,int newWidth,int newHeight)1507 BOOL ModelWindow::doDialogSize(HWND hDlg, WPARAM sizeType, int newWidth,
1508 int newHeight)
1509 {
1510 // debugPrintf("ModelWindow::doDialogSize(%d, %d, %d)\n", sizeType, newWidth,
1511 // newHeight);
1512 if (hDlg == hErrorWindow)
1513 {
1514 return doErrorSize(sizeType, newWidth, newHeight);
1515 }
1516 else if (hDlg == hSaveDialog)
1517 {
1518 return doSaveSize(sizeType, newWidth, newHeight);
1519 }
1520 return FALSE;
1521 }
1522
doDialogGetMinMaxInfo(HWND hDlg,LPMINMAXINFO minMaxInfo)1523 BOOL ModelWindow::doDialogGetMinMaxInfo(HWND hDlg, LPMINMAXINFO minMaxInfo)
1524 {
1525 if (hDlg == hErrorWindow)
1526 {
1527 calcSystemSizes();
1528 minMaxInfo->ptMaxSize.x = systemMaxWidth;
1529 minMaxInfo->ptMaxSize.y = systemMaxHeight;
1530 minMaxInfo->ptMinTrackSize.x = scalePoints(475);
1531 minMaxInfo->ptMinTrackSize.y = scalePoints(260);
1532 minMaxInfo->ptMaxTrackSize.x = systemMaxTrackWidth;
1533 minMaxInfo->ptMaxTrackSize.y = systemMaxTrackHeight;
1534 return TRUE;
1535 }
1536 return FALSE;
1537 }
1538
doProgressClick(int controlId,HWND)1539 BOOL ModelWindow::doProgressClick(int controlId, HWND /*controlHWnd*/)
1540 {
1541 if (controlId == IDCANCEL)
1542 {
1543 doProgressCancel();
1544 }
1545 return TRUE;
1546 }
1547
getErrorKey(LDLErrorType errorType)1548 char* ModelWindow::getErrorKey(LDLErrorType errorType)
1549 {
1550 static char key[128];
1551
1552 sprintf(key, "%s/LDLError%02d", SHOW_ERRORS_KEY, errorType);
1553 return key;
1554 }
1555
doErrorClick(int controlId,HWND)1556 BOOL ModelWindow::doErrorClick(int controlId, HWND /*controlHWnd*/)
1557 {
1558 switch (controlId)
1559 {
1560 case IDCANCEL:
1561 return doErrorOK();
1562 break;
1563 case IDC_COPY_ERROR:
1564 if (!doErrorTreeCopy())
1565 {
1566 MessageBeep(MB_OK);
1567 }
1568 break;
1569 case IDC_SHOW_WARNINGS:
1570 bool showWarnings;
1571
1572 showWarnings = CUIDialog::buttonGetCheck(hErrorWindow, controlId);
1573 TCUserDefaults::setBoolForKey(showWarnings, SHOW_WARNINGS_KEY, false);
1574 clearErrorTree();
1575 populateErrorTree();
1576 break;
1577 case IDC_ERROR_SHOW_ALL:
1578 return setAllErrorsSelected(true);
1579 break;
1580 case IDC_ERROR_SHOW_NONE:
1581 return setAllErrorsSelected(false);
1582 break;
1583 }
1584 return TRUE;
1585 }
1586
setAllErrorsSelected(bool selected)1587 BOOL ModelWindow::setAllErrorsSelected(bool selected)
1588 {
1589 int i;
1590 int count = errorInfos->getCount();
1591 BOOL state = selected ? TRUE : FALSE;
1592
1593 skipErrorUpdates = true;
1594 for (i = 0; i < count; i++)
1595 {
1596 ListView_SetCheckState(hErrorList, i, state);
1597 }
1598 skipErrorUpdates = false;
1599 clearErrorTree();
1600 populateErrorTree();
1601 return TRUE;
1602 }
1603
doPageSetupClick(int controlId,HWND)1604 BOOL ModelWindow::doPageSetupClick(int controlId, HWND /*controlHWnd*/)
1605 {
1606 switch (controlId)
1607 {
1608 case IDC_PRINT_BACKGROUND:
1609 printBackground = CUIDialog::buttonGetCheck(hPageSetupDialog,
1610 IDC_PRINT_BACKGROUND);
1611 break;
1612 default:
1613 return FALSE;
1614 }
1615 return TRUE;
1616 }
1617
applyPrefs(void)1618 void ModelWindow::applyPrefs(void)
1619 {
1620 bool antialiasChanged = TCUserDefaults::longForKey(FSAA_MODE_KEY) !=
1621 currentAntialiasType;
1622
1623 loadSettings();
1624 ((LDViewWindow*)parentWindow)->applyPrefs();
1625 if (LDVExtensionsSetup::haveMultisampleExtension() && antialiasChanged)
1626 {
1627 setTimer(FSAA_UPDATE_TIMER, 0);
1628 }
1629 forceRedraw();
1630 }
1631
doCommand(int,int notifyCode,HWND controlHWnd)1632 LRESULT ModelWindow::doCommand(int /*itemId*/, int notifyCode, HWND controlHWnd)
1633 {
1634 if (controlHWnd == hPrefsWindow && controlHWnd != NULL)
1635 {
1636 switch (notifyCode)
1637 {
1638 case CUI_OK:
1639 stopAnimation();
1640 prefs->closePropertySheet();
1641 hPrefsWindow = NULL;
1642 applyPrefs();
1643 break;
1644 case CUI_CANCEL:
1645 stopAnimation();
1646 prefs->closePropertySheet();
1647 hPrefsWindow = NULL;
1648 break;
1649 case CUI_APPLY:
1650 applyPrefs();
1651 break;
1652 }
1653 }
1654 return 1;
1655 }
1656
doDialogHelp(HWND hDlg,LPHELPINFO helpInfo)1657 BOOL ModelWindow::doDialogHelp(HWND hDlg, LPHELPINFO helpInfo)
1658 {
1659 BOOL retValue = FALSE;
1660 DWORD dialogId = 0;
1661
1662 if (hDlg == hSaveDialog)
1663 {
1664 dialogId = IDD_SAVE_OPTIONS;
1665 }
1666 if (dialogId)
1667 {
1668 UCSTR helpPath = LDViewPreferences::getLDViewPath(
1669 ls(_UC("LDView.hlp")));
1670 DWORD helpId;
1671
1672 helpId = 0x80000000 | (dialogId << 16) | (DWORD)helpInfo->iCtrlId;
1673 WinHelp((HWND)helpInfo->hItemHandle, helpPath, HELP_CONTEXTPOPUP,
1674 helpId);
1675 retValue = TRUE;
1676 delete helpPath;
1677 }
1678 return retValue;
1679 }
1680
doDialogCommand(HWND hDlg,int controlId,int notifyCode,HWND controlHWnd)1681 BOOL ModelWindow::doDialogCommand(HWND hDlg, int controlId, int notifyCode,
1682 HWND controlHWnd)
1683 {
1684 // debugPrintf("ModelWindow::doDialogCommand(0x%08X, 0x%04X, 0x%04X, 0x%08X)\n",
1685 // hDlg, controlId, notifyCode, controlHWnd);
1686 if (hDlg == hSaveDialog)
1687 {
1688 return doSaveCommand(controlId, notifyCode, controlHWnd);
1689 }
1690 else if (hDlg == hPrintDialog)
1691 {
1692 return doPrintCommand(controlId, notifyCode, controlHWnd);
1693 }
1694 if (notifyCode == BN_CLICKED)
1695 {
1696 if (hDlg == hProgressWindow)
1697 {
1698 return doProgressClick(controlId, controlHWnd);
1699 }
1700 else if (hDlg == hErrorWindow)
1701 {
1702 return doErrorClick(controlId, controlHWnd);
1703 }
1704 else if (hDlg == hPageSetupDialog)
1705 {
1706 return doPageSetupClick(controlId, controlHWnd);
1707 }
1708 }
1709 return FALSE;
1710 }
1711
showPreferences(void)1712 BOOL ModelWindow::showPreferences(void)
1713 {
1714 prefs->setHDlgParent(GetParent(hWindow));
1715 hPrefsWindow = (HWND)prefs->show();
1716 return TRUE;
1717 }
1718
showErrors(void)1719 void ModelWindow::showErrors(void)
1720 {
1721 showErrorsIfNeeded(FALSE);
1722 }
1723
hideProgress(void)1724 void ModelWindow::hideProgress(void)
1725 {
1726 if (loading)
1727 {
1728 progressBarSetPos(hProgressBar, 0);
1729 statusBarSetText(hStatusBar, 1, _UC(""));
1730 ((LDViewWindow *)parentWindow)->redrawStatusBar();
1731 EnumThreadWindows(GetWindowThreadProcessId(hParentWindow, NULL),
1732 enableNonModalWindow, (LPARAM)hParentWindow);
1733 ((LDViewWindow*)parentWindow)->setLoading(false);
1734 // doDialogClose(hProgressWindow);
1735 loading = false;
1736 ((LDViewWindow*)parentWindow)->forceShowStatusBar(false);
1737 }
1738 }
1739
addErrorLine(HTREEITEM parent,CUCSTR line,LDLError * error,int imageIndex)1740 HTREEITEM ModelWindow::addErrorLine(HTREEITEM parent, CUCSTR line,
1741 LDLError* error, int imageIndex)
1742 {
1743 TVINSERTSTRUCT insertStruct;
1744 TVITEMEX item;
1745 ucstring lineCopy = line;
1746
1747 stripCRLF(&lineCopy[0]);
1748 memset(&item, 0, sizeof(item));
1749 item.mask = TVIF_TEXT | TVIF_PARAM;
1750 item.pszText = &lineCopy[0];
1751 item.lParam = (LPARAM)error;
1752 insertStruct.hParent = parent;
1753 insertStruct.hInsertAfter = TVI_LAST;
1754 if (error->getLevel() != LDLAWarning && parent == NULL)
1755 {
1756 item.mask |= TVIF_STATE;
1757 item.stateMask = TVIS_BOLD;
1758 item.state = TVIS_BOLD;
1759 }
1760 if (imageIndex < 0)
1761 {
1762 imageIndex = errorImageIndices[LDLELastError + 1];
1763 }
1764 item.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE;
1765 item.iImage = imageIndex;
1766 item.iSelectedImage = imageIndex;
1767 insertStruct.itemex = item;
1768 return TreeView_InsertItem(hErrorTree, &insertStruct);
1769 }
1770
addError(LDLError * error)1771 bool ModelWindow::addError(LDLError* error)
1772 {
1773 CUCSTR string;
1774 HTREEITEM parent;
1775
1776 if (!showsError(error))
1777 {
1778 return false;
1779 }
1780 string = error->getMessageUC();
1781 if (!string)
1782 {
1783 string = _UC("");
1784 }
1785 parent = addErrorLine(NULL, string, error,
1786 errorImageIndices[error->getType()]);
1787
1788 if (parent)
1789 {
1790 TCStringArray *extraInfo;
1791 ucstring filename;
1792 utf8toucstring(filename, error->getFilename());
1793 ucstring line;
1794
1795 if (!filename.empty())
1796 {
1797 line = ls(_UC("ErrorTreeFilePrefix"));
1798 line += filename;
1799 }
1800 else
1801 {
1802 line = ls(_UC("ErrorTreeUnknownFile"));
1803 }
1804 addErrorLine(parent, line.c_str(), error);
1805 ucstring formattedLine;
1806 utf8toucstring(formattedLine, error->getFormattedFileLine());
1807 if (!formattedLine.empty())
1808 {
1809 int lineNumber = error->getLineNumber();
1810 if (lineNumber > 0)
1811 {
1812 CUCSTR lineNumberFormat = ls(_UC("ErrorTreeLine#"));
1813 size_t len = ucstrlen(lineNumberFormat) + 128;
1814 line.resize(len);
1815 sucprintf(&line[0], len, lineNumberFormat, lineNumber);
1816 addErrorLine(parent, line.c_str(), error);
1817 }
1818 else
1819 {
1820 addErrorLine(parent, ls(_UC("ErrorTreeUnknownLine#")), error);
1821 }
1822 CUCSTR lineFormat = ls(_UC("ErrorTreeLine"));
1823 size_t len = formattedLine.size() + ucstrlen(lineFormat) + 1;
1824 line.resize(len);
1825 sucprintf(&line[0], len, lineFormat, formattedLine.c_str());
1826 addErrorLine(parent, line.c_str(), error);
1827 }
1828 else
1829 {
1830 addErrorLine(parent, ls(_UC("ErrorTreeUnknownLine")), error);
1831 }
1832 if ((extraInfo = error->getExtraInfo()) != NULL)
1833 {
1834 int i;
1835 int count = extraInfo->getCount();
1836
1837 for (i = 0; i < count; i++)
1838 {
1839 ucstring extraLine;
1840 utf8toucstring(extraLine, extraInfo->stringAtIndex(i));
1841 addErrorLine(parent, extraLine.c_str(), error);
1842 }
1843 }
1844 }
1845 return true;
1846 }
1847
showsError(LDLError * error)1848 bool ModelWindow::showsError(LDLError *error)
1849 {
1850 LDLErrorType errorType = error->getType();
1851
1852 if (error->getLevel() == LDLAWarning)
1853 {
1854 if (TCUserDefaults::boolForKey(SHOW_WARNINGS_KEY, false, false))
1855 {
1856 return TCUserDefaults::longForKey(getErrorKey(errorType), 0, false)
1857 != 0;
1858 }
1859 else
1860 {
1861 return false;
1862 }
1863 }
1864 else
1865 {
1866 return TCUserDefaults::longForKey(getErrorKey(errorType), 1, false) !=
1867 0;
1868 }
1869 }
1870
showsErrorType(LDLErrorType errorType)1871 BOOL ModelWindow::showsErrorType(LDLErrorType errorType)
1872 {
1873 return TCUserDefaults::longForKey(getErrorKey(errorType), 1, false);
1874 }
1875
populateErrorInfos(void)1876 void ModelWindow::populateErrorInfos(void)
1877 {
1878 if (!errorInfos)
1879 {
1880 int i;
1881
1882 errorInfos = new ErrorInfoArray;
1883 for (i = LDLEFirstError; i <= LDLELastError; i++)
1884 {
1885 ErrorInfo *errorInfo = new ErrorInfo;
1886 LDLErrorType type = (LDLErrorType)i;
1887
1888 errorInfo->setType(type);
1889 errorInfo->setTypeName(LDLError::getTypeNameUC(type));
1890 errorInfos->addObject(errorInfo);
1891 errorInfo->release();
1892 }
1893 }
1894 }
1895
setupErrorWindow(void)1896 void ModelWindow::setupErrorWindow(void)
1897 {
1898 HIMAGELIST himl; // handle to image list
1899 HBITMAP hbmp; // handle to bitmap
1900 HBITMAP hMask;
1901 bool showWarnings = TCUserDefaults::boolForKey(SHOW_WARNINGS_KEY, false,
1902 false);
1903
1904 populateErrorInfos();
1905 populateErrorList();
1906 memset(errorImageIndices, 0, sizeof(errorImageIndices));
1907 if (errorWindowResizer)
1908 {
1909 errorWindowResizer->release();
1910 }
1911 errorWindowResizer = new CUIWindowResizer;
1912 errorWindowResizer->setHWindow(hErrorWindow);
1913 errorWindowResizer->addSubWindow(IDC_ERROR_TREE,
1914 CUISizeHorizontal | CUISizeVertical);
1915 errorWindowResizer->addSubWindow(IDC_COPY_ERROR,
1916 CUIFloatLeft | CUIFloatTop);
1917 errorWindowResizer->addSubWindow(IDC_ERROR_SHOW_ALL,
1918 CUIFloatLeft | CUIFloatTop);
1919 errorWindowResizer->addSubWindow(IDC_ERROR_SHOW_NONE,
1920 CUIFloatLeft | CUIFloatTop);
1921 errorWindowResizer->addSubWindow(IDC_SHOW_WARNINGS, CUIFloatTop);
1922 errorWindowResizer->addSubWindow(IDC_SHOW_ERRORS,
1923 CUIFloatLeft | CUISizeVertical);
1924 errorWindowResizer->addSubWindow(IDC_ERROR_LIST,
1925 CUIFloatLeft | CUISizeVertical);
1926
1927 CUIDialog::buttonSetChecked(hErrorWindow, IDC_SHOW_WARNINGS, showWarnings);
1928 // Create the image list.
1929 UINT flags = CUIScaler::imageListCreateFlags();
1930 double scaleFactor = getScaleFactor();
1931 SIZE size;
1932 size.cx = size.cy = scalePoints(16);
1933 if ((himl = ImageList_Create(size.cx, size.cy, flags, 12, 0)) == NULL)
1934 return;
1935
1936 // Add the bitmaps.
1937 addImageToImageList(himl, IDR_INFO, size, scaleFactor);
1938 errorImageIndices[LDLEParse] = addImageToImageList(himl, IDR_PARSE, size, scaleFactor);
1939 errorImageIndices[LDLEGeneral] = errorImageIndices[LDLEParse];
1940 errorImageIndices[LDLEBFCError] = errorImageIndices[LDLEParse];
1941 errorImageIndices[LDLEMPDError] = errorImageIndices[LDLEParse];
1942 errorImageIndices[LDLEMetaCommand] = errorImageIndices[LDLEParse];
1943 errorImageIndices[LDLEFileNotFound] = addImageToImageList(himl, IDR_FNF, size, scaleFactor);
1944 errorImageIndices[LDLEMatrix] = addImageToImageList(himl, IDR_MATRIX, size, scaleFactor);
1945 errorImageIndices[LDLEPartDeterminant] = addImageToImageList(himl, IDR_DETERMINANT, size, scaleFactor);
1946 errorImageIndices[LDLENonFlatQuad] = addImageToImageList(himl, IDR_NON_FLAT_QUAD, size, scaleFactor);
1947 errorImageIndices[LDLEConcaveQuad] = addImageToImageList(himl, IDR_CONCAVE_QUAD, size, scaleFactor);
1948 errorImageIndices[LDLEMatchingPoints] = addImageToImageList(himl, IDR_MATCHING_POINTS, size, scaleFactor);
1949 errorImageIndices[LDLEColinear] = addImageToImageList(himl, IDR_COLINEAR, size, scaleFactor);
1950 errorImageIndices[LDLEVertexOrder] = addImageToImageList(himl, IDR_VERTEX_ORDER, size, scaleFactor);
1951 errorImageIndices[LDLEModelLoop] = addImageToImageList(himl, IDR_ERROR_LOOP, size, scaleFactor);
1952 if (scaleFactor == 1.0 || scaleFactor == 2.0)
1953 {
1954 errorImageIndices[LDLELastError + 1] = addImageToImageList(himl, IDR_DOTS, size, scaleFactor);
1955 }
1956 else
1957 {
1958 // The dots image will only look right and line up perfectly if the
1959 // scale factor is exactly 1 or 2. Do what I used to do (show the info
1960 // icon) if the scale factor is anything else.
1961 errorImageIndices[LDLELastError + 1] = addImageToImageList(himl, IDR_INFO, size, scaleFactor);
1962 }
1963
1964 // Associate the image list with the tree view control.
1965 TreeView_SetImageList(hErrorTree, himl, TVSIL_NORMAL);
1966 TreeView_SetItemHeight(hErrorTree, scalePoints(18));
1967 }
1968
setupProgress(void)1969 void ModelWindow::setupProgress(void)
1970 {
1971 cancelLoad = false;
1972 }
1973
registerErrorWindowClass(void)1974 void ModelWindow::registerErrorWindowClass(void)
1975 {
1976 WNDCLASSEX windowClass;
1977 UCCHAR prefsClassName[1024];
1978
1979 if (!hProgressWindow)
1980 {
1981 createProgress();
1982 }
1983 GetClassName(hProgressWindow, prefsClassName, 1024);
1984 memset(&windowClass, 0, sizeof(windowClass));
1985 windowClass.cbSize = sizeof(windowClass);
1986 GetClassInfoEx(getLanguageModule(), prefsClassName, &windowClass);
1987 windowClass.hIcon = LoadIcon(getLanguageModule(),
1988 MAKEINTRESOURCE(IDI_APP_ICON));
1989 windowClass.lpszMenuName = NULL;
1990 windowClass.lpszClassName = _UC("LDViewErrorWindow");
1991 RegisterClassEx(&windowClass);
1992 }
1993
initCommonControls(DWORD mask)1994 void ModelWindow::initCommonControls(DWORD mask)
1995 {
1996 static DWORD initializedMask = 0;
1997
1998 if ((initializedMask & mask) != mask)
1999 {
2000 INITCOMMONCONTROLSEX initCtrls;
2001
2002 memset(&initCtrls, 0, sizeof(initCtrls));
2003 initCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX);
2004 initCtrls.dwICC = mask;
2005 InitCommonControlsEx(&initCtrls);
2006 initializedMask |= mask;
2007 }
2008 }
2009
createErrorWindow(void)2010 void ModelWindow::createErrorWindow(void)
2011 {
2012 if (!hErrorWindow)
2013 {
2014 HWND hActiveWindow = GetActiveWindow();
2015 int parts[] = {-1};
2016
2017 initCommonControls(ICC_TREEVIEW_CLASSES | ICC_BAR_CLASSES);
2018 registerErrorWindowClass();
2019 hErrorWindow = createDialog(IDD_ERRORS, FALSE);
2020 hErrorStatusWindow = CreateStatusWindow(
2021 WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP, _UC(""), hErrorWindow,
2022 2000);
2023 statusBarSetParts(hErrorStatusWindow, 1, parts);
2024 originalErrorDlgProc = (WNDPROC)GetWindowLongPtr(hErrorWindow,
2025 DWLP_DLGPROC);
2026 SetWindowLongPtr(hErrorWindow, GWLP_USERDATA, (LONG_PTR)this);
2027 SetWindowLongPtr(hErrorWindow, DWLP_DLGPROC, (LONG_PTR)staticErrorDlgProc);
2028 hErrorTree = GetDlgItem(hErrorWindow, IDC_ERROR_TREE);
2029 hErrorList = GetDlgItem(hErrorWindow, IDC_ERROR_LIST);
2030 // hErrorOk = GetDlgItem(hErrorWindow, IDOK);
2031 setupErrorWindow();
2032 SetActiveWindow(hActiveWindow);
2033 }
2034 }
2035
createProgress(void)2036 void ModelWindow::createProgress(void)
2037 {
2038 initCommonControls(ICC_PROGRESS_CLASS | ICC_UPDOWN_CLASS);
2039 hProgressWindow = createDialog(IDD_LOAD_PROGRESS);
2040 hProgressMessage = GetDlgItem(hProgressWindow, IDC_LOAD_PROGRESS_MSG);
2041 hProgressCancelButton = GetDlgItem(hProgressWindow, IDCANCEL);
2042 hProgress = GetDlgItem(hProgressWindow, IDC_PROGRESS);
2043 }
2044
clearErrorTree(void)2045 void ModelWindow::clearErrorTree(void)
2046 {
2047 // RECT rect;
2048 // POINT topLeft;
2049
2050 SetWindowRedraw(hErrorTree, FALSE);
2051 if (hErrorWindow)
2052 {
2053 HTREEITEM hItem;
2054
2055 // Delete all is really, REALLY, slow for trees with lots of data. I
2056 // think it starts at the beginning, and keeps copying the items back
2057 // each time the first is deleted. Oh, and the "Visible" in
2058 // "LastVisible" doesn't mean it's visible on-screen, just that its
2059 // parent is expanded.
2060 while ((hItem = TreeView_GetLastVisible(hErrorTree)) != NULL)
2061 {
2062 TreeView_DeleteItem(hErrorTree, hItem);
2063 }
2064 TreeView_DeleteItem(hErrorTree, TVI_ROOT);
2065 }
2066 SetWindowRedraw(hErrorTree, TRUE);
2067 RedrawWindow(hErrorTree, NULL, NULL,
2068 RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
2069 /*
2070 GetWindowRect(hErrorTree, &rect);
2071 topLeft.x = rect.left;
2072 topLeft.y = rect.top;
2073 width = rect.right - rect.left;
2074 height = rect.bottom - rect.top;
2075 ScreenToClient(GetParent(hErrorTree), &topLeft);
2076 // MoveWindow(hErrorTree, topLeft.x, topLeft.y, width - 1, height, TRUE);
2077 MoveWindow(hErrorTree, topLeft.x, topLeft.y, width, height, TRUE);
2078 */
2079 errorTreePopulated = false;
2080 }
2081
clearErrors(void)2082 void ModelWindow::clearErrors(void)
2083 {
2084 userLoad = true;
2085 errors->removeAll();
2086 /*
2087 while (errors->getCount())
2088 {
2089 errors->removeObjectAtIndex(0);
2090 }
2091 */
2092 clearErrorTree();
2093 }
2094
populateErrorList(void)2095 void ModelWindow::populateErrorList(void)
2096 {
2097 int i;
2098 int count = errorInfos->getCount();
2099 LVCOLUMN column;
2100 DWORD exStyle = ListView_GetExtendedListViewStyle(hErrorList);
2101
2102 skipErrorUpdates = true;
2103 exStyle |= LVS_EX_CHECKBOXES;
2104 ListView_SetExtendedListViewStyle(hErrorList, exStyle);
2105 memset(&column, 0, sizeof(LVCOLUMN));
2106 column.mask = LVCF_FMT | LVCF_WIDTH;
2107 column.fmt = LVCFMT_LEFT;
2108 column.cx = 300;
2109 ListView_InsertColumn(hErrorList, 0, &column);
2110 for (i = 0; i < count; i++)
2111 {
2112 ErrorInfo *errorInfo = (*errorInfos)[i];
2113 LVITEM item;
2114 int state;
2115
2116 memset(&item, 0, sizeof(item));
2117 item.mask = TVIF_TEXT | TVIF_PARAM;
2118 item.pszText = errorInfo->getTypeName();
2119 item.lParam = errorInfo->getType();
2120 item.iItem = i;
2121 item.iSubItem = 0;
2122 state = TCUserDefaults::longForKey(getErrorKey(errorInfo->getType()),
2123 1, false);
2124 ListView_InsertItem(hErrorList, &item);
2125 ListView_SetCheckState(hErrorList, i, state);
2126 }
2127 skipErrorUpdates = false;
2128 ListView_SetColumnWidth(hErrorList, 0, LVSCW_AUTOSIZE);
2129 }
2130
populateErrorTree(void)2131 int ModelWindow::populateErrorTree(void)
2132 {
2133 UCCHAR buf[1024] = _UC("");
2134
2135 if (!windowShown)
2136 {
2137 return 0;
2138 }
2139 // De-select any item that may have been selected before.
2140 TreeView_Select(hErrorTree, NULL, TVGN_CARET);
2141 // Don't let the tree redraw while we are populating it.
2142 SetWindowRedraw(hErrorTree, FALSE);
2143 if (hErrorWindow && !errorTreePopulated)
2144 {
2145 errorCount = 0;
2146 warningCount = 0;
2147 for (int i = 0, count = errors->getCount(); i < count; i++)
2148 {
2149 LDLError *error = (*errors)[i];
2150
2151 if (addError(error))
2152 {
2153 if (error->getLevel() == LDLAWarning)
2154 {
2155 warningCount++;
2156 }
2157 else
2158 {
2159 errorCount++;
2160 }
2161 }
2162 }
2163 errorTreePopulated = true;
2164 }
2165 SetWindowRedraw(hErrorTree, TRUE);
2166 RedrawWindow(hErrorTree, NULL, NULL,
2167 RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
2168 /*
2169 GetWindowRect(hErrorTree, &rect);
2170 topLeft.x = rect.left;
2171 topLeft.y = rect.top;
2172 width = rect.right - rect.left;
2173 height = rect.bottom - rect.top;
2174 ScreenToClient(GetParent(hErrorTree), &topLeft);
2175 if (errorCount > 0 || warningCount > 0)
2176 {
2177 MoveWindow(hErrorTree, topLeft.x, topLeft.y, width - 1, height, FALSE);
2178 }
2179 MoveWindow(hErrorTree, topLeft.x, topLeft.y, width, height, TRUE);
2180 */
2181 // RedrawWindow(hErrorTree, NULL, NULL, RDW_INVALIDATE | RDW_ERASE |
2182 // RDW_FRAME | RDW_ALLCHILDREN);
2183 if (errorCount > 0)
2184 {
2185 if (errorCount == 1)
2186 {
2187 ucstrcpy(buf, ls(_UC("ErrorTreeOneError")));
2188 }
2189 else
2190 {
2191 sucprintf(buf, COUNT_OF(buf), ls(_UC("ErrorTreeNErrors")), errorCount);
2192 }
2193 if (warningCount > 0)
2194 {
2195 ucstrcat(buf, _UC(", "));
2196 }
2197 }
2198 if (warningCount > 0)
2199 {
2200 if (warningCount == 1)
2201 {
2202 ucstrcat(buf, ls(_UC("ErrorTreeOneWarning")));
2203 }
2204 else
2205 {
2206 size_t len = ucstrlen(buf);
2207 sucprintf(buf + len, COUNT_OF(buf) - len,
2208 ls(_UC("ErrorTreeNWarnings")), warningCount);
2209 }
2210 }
2211 statusBarSetText(hErrorStatusWindow, 0, buf);
2212 return errorCount;
2213 }
2214
showErrorsIfNeeded(BOOL onlyIfNeeded)2215 void ModelWindow::showErrorsIfNeeded(BOOL onlyIfNeeded)
2216 {
2217 if (windowShown && !((LDViewWindow*)parentWindow)->getFullScreen())
2218 {
2219 if (!hErrorWindow)
2220 {
2221 createErrorWindow();
2222 }
2223 if (hErrorWindow)
2224 {
2225 wchar_t text[1024];
2226
2227 populateErrorTree();
2228 GetWindowTextW(hErrorWindow, text, 1024);
2229 if (!onlyIfNeeded || (errorCount &&
2230 TCUserDefaults::longForKey(SHOW_ERRORS_KEY, 1, false)))
2231 {
2232 ShowWindow(hErrorWindow, SW_SHOWNORMAL);
2233 // For some reason, in Windows 10 (and possibly earlier
2234 // versions), the error window doesn't get brought to
2235 // the front when it is already visible and ShowWindow is
2236 // called, even with SW_SHOWNORMAL. The below brings it to the
2237 // front, so it can't be hidden behind the main LDView window.
2238 BringWindowToTop(hErrorWindow);
2239 }
2240 }
2241 }
2242 }
2243
isErrorWindowVisible(void) const2244 bool ModelWindow::isErrorWindowVisible(void) const
2245 {
2246 return hErrorWindow != NULL && IsWindowVisible(hErrorWindow) != FALSE;
2247 }
2248
stopAnimation(void)2249 void ModelWindow::stopAnimation(void)
2250 {
2251 if (modelViewer)
2252 {
2253 modelViewer->setRotationSpeed(0.0f);
2254 modelViewer->setZoomSpeed(0.0f);
2255 }
2256 }
2257
loadModel(void)2258 int ModelWindow::loadModel(void)
2259 {
2260 char* filename = modelViewer->getFilename();
2261 #ifdef _DEBUG
2262 _CrtMemState ms1, ms2, ms3;
2263 #endif // _DEBUG
2264
2265 loadCanceled = false;
2266 clearErrors();
2267 stopPolling();
2268 makeCurrent();
2269 if (strlen(filename) < 900)
2270 {
2271 ucstring ucFilename;
2272 utf8toucstring(ucFilename, filename);
2273 ucstring title = _UC("LDView: ") + ucFilename;
2274 parentWindow->setTitle(title.c_str());
2275 }
2276 else
2277 {
2278 parentWindow->setTitle(_UC("LDView"));
2279 }
2280 _CrtMemCheckpoint(&ms1);
2281 if (modelViewer->loadModel())
2282 {
2283 _CrtMemCheckpoint(&ms2);
2284 _CrtMemDifference(&ms3, &ms1, &ms2);
2285 _CrtMemDumpStatistics(&ms3);
2286 forceRedraw();
2287 stopAnimation();
2288 if (pollSetting)
2289 {
2290 if (getFileTime(&lastWriteTime))
2291 {
2292 startPolling();
2293 }
2294 }
2295 return 1;
2296 }
2297 else
2298 {
2299 modelViewer->setFilename(NULL);
2300 return 0;
2301 }
2302 }
2303
closeWindow(void)2304 void ModelWindow::closeWindow(void)
2305 {
2306 destroyWindow();
2307 CUIOGLWindow::closeWindow();
2308 }
2309
doShowWindow(BOOL showFlag,LPARAM status)2310 LRESULT ModelWindow::doShowWindow(BOOL showFlag, LPARAM status)
2311 {
2312 windowShown = true;
2313 return CUIOGLWindow::doShowWindow(showFlag, status);
2314 }
2315
initWindow(void)2316 BOOL ModelWindow::initWindow(void)
2317 {
2318 LDVExtensionsSetup::setup(hInstance);
2319 //if (((LDViewWindow*)parentWindow)->getFullScreen() ||
2320 // ((LDViewWindow*)parentWindow)->getScreenSaver() ||
2321 // ((LDViewWindow*)parentWindow)->getHParentWindow())
2322 //{
2323 // exWindowStyle &= ~WS_EX_CLIENTEDGE;
2324 //}
2325 //else
2326 //{
2327 // exWindowStyle |= WS_EX_CLIENTEDGE;
2328 //}
2329 windowStyle |= WS_CHILD;
2330 cancelLoad = false;
2331 if (CUIOGLWindow::initWindow())
2332 {
2333 TREGLExtensions::setup();
2334 setupMultisample();
2335 return TRUE;
2336 }
2337 else
2338 {
2339 return FALSE;
2340 }
2341 }
2342
setupMultisample(void)2343 void ModelWindow::setupMultisample(void)
2344 {
2345 if (LDVExtensionsSetup::haveMultisampleExtension())
2346 {
2347 debugOut("ModelWindow::setupMultisample 1\n");
2348 if (currentAntialiasType)
2349 {
2350 if (TREGLExtensions::haveNvMultisampleFilterHintExtension())
2351 {
2352 if (prefs->getUseNvMultisampleFilter())
2353 {
2354 glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);
2355 }
2356 else
2357 {
2358 glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_FASTEST);
2359 }
2360 }
2361 glEnable(GL_MULTISAMPLE_ARB);
2362 }
2363 else
2364 {
2365 if (TREGLExtensions::haveNvMultisampleFilterHintExtension())
2366 {
2367 glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_FASTEST);
2368 }
2369 glDisable(GL_MULTISAMPLE_ARB);
2370 }
2371 debugOut("ModelWindow::setupMultisample 2\n");
2372 }
2373 }
2374
staticErrorDlgProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)2375 LRESULT CALLBACK ModelWindow::staticErrorDlgProc(HWND hDlg, UINT message,
2376 WPARAM wParam, LPARAM lParam)
2377 {
2378 ModelWindow* modelWindow = (ModelWindow*)GetWindowLongPtr(hDlg,
2379 GWLP_USERDATA);
2380
2381 if (modelWindow)
2382 {
2383 return modelWindow->errorDlgProc(hDlg, message, wParam, lParam);
2384 }
2385 else
2386 {
2387 return 0;
2388 }
2389 }
2390
errorDlgProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)2391 LRESULT ModelWindow::errorDlgProc(HWND hDlg, UINT message, WPARAM wParam,
2392 LPARAM lParam)
2393 {
2394 // debugPrintf("ModelWindow::errorDlgProc: 0x%04x\n", message);
2395 return CallWindowProc(originalErrorDlgProc, hDlg, message, wParam, lParam);
2396 }
2397
windowProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)2398 LRESULT ModelWindow::windowProc(HWND hWnd, UINT message, WPARAM wParam,
2399 LPARAM lParam)
2400 {
2401 #if defined(USE_CPP11) || !defined(_NO_BOOST)
2402 if (remoteListener && remoteMessageID != 0 && message == remoteMessageID)
2403 {
2404 processRemoteMessage((char *)lParam);
2405 }
2406 #endif // !_NO_BOOST
2407 // debugPrintf("ModelWindow::windowProc: 0x%04x\n", message);
2408 return CUIOGLWindow::windowProc(hWnd, message, wParam, lParam);
2409 }
2410
processModalMessage(MSG msg)2411 void ModelWindow::processModalMessage(MSG msg)
2412 {
2413 if (msg.message == WM_KEYDOWN)
2414 {
2415 msg.hwnd = hParentWindow;
2416 }
2417 CUIWindow::processModalMessage(msg);
2418 }
2419
progressCallback(CUCSTR message,float progress,bool fromImage,bool showErrors)2420 int ModelWindow::progressCallback(
2421 CUCSTR message,
2422 float progress,
2423 bool fromImage,
2424 bool showErrors /*= false*/)
2425 {
2426 DWORD thisProgressUpdate = GetTickCount();
2427
2428 if (!windowShown)
2429 {
2430 return 1;
2431 }
2432 if (ucstrcmp(message, _UC("LoadingPNG")) == 0 ||
2433 ucstrcmp(message, _UC("LoadingPNGRow")) == 0)
2434 {
2435 // The only time we get this message is when loading built-in PNG files,
2436 // like toolbar icons and stud logo; don't show it in the progress.
2437 return 1;
2438 }
2439 if (progress == 2.0 && (!userLoad || !fromImage))
2440 {
2441 // done
2442 hideProgress();
2443 // If the window is closed during load, we will no longer be initialized.
2444 if (showErrors && initialized && !cancelLoad && userLoad)
2445 {
2446 showErrorsIfNeeded();
2447 }
2448 if (!fromImage)
2449 {
2450 userLoad = false;
2451 }
2452 makeCurrent();
2453 return 1;
2454 }
2455 if (!loading)
2456 {
2457 //clearErrors();
2458 loading = true;
2459 setupProgress();
2460 ((LDViewWindow*)parentWindow)->forceShowStatusBar(true);
2461 if (!flushModal(hParentWindow, false))
2462 {
2463 PostQuitMessage(0);
2464 cancelLoad = true;
2465 }
2466 if (cancelLoad)
2467 {
2468 loadCanceled = true;
2469 }
2470 ((LDViewWindow*)parentWindow)->setLoading(true);
2471 }
2472 if (message && message[0])
2473 {
2474 setStatusText(hStatusBar, 1, message, true);
2475 }
2476 if (progress >= 0.0f)
2477 {
2478 int oldProgress;
2479 int newProgress = (int)(progress * 100);
2480
2481 oldProgress = progressBarGetPos(hProgressBar);
2482 if (oldProgress != newProgress)
2483 {
2484 progressBarSetPos(hProgressBar, newProgress);
2485 }
2486 }
2487 if (thisProgressUpdate < lastProgressUpdate || thisProgressUpdate >
2488 lastProgressUpdate + 100 || progress == 1.0f)
2489 {
2490 if (!flushModal(hParentWindow, false))
2491 {
2492 PostQuitMessage(0);
2493 cancelLoad = true;
2494 }
2495 if (cancelLoad)
2496 {
2497 loadCanceled = true;
2498 }
2499 lastProgressUpdate = thisProgressUpdate;
2500 }
2501 if (cancelLoad)
2502 {
2503 hideProgress();
2504 makeCurrent();
2505 return 0;
2506 }
2507 else
2508 {
2509 makeCurrent();
2510 return 1;
2511 }
2512 }
2513
2514 //bool ModelWindow::staticImageProgressCallback(CUCSTR message, float progress,
2515 // void* userData)
2516 //{
2517 // return ((ModelWindow*)userData)->progressCallback(message, progress) ? true
2518 // : false;
2519 //}
2520
errorCallback(LDLError * error)2521 int ModelWindow::errorCallback(LDLError* error)
2522 {
2523 if (windowShown)
2524 {
2525 errors->addObject(error);
2526 }
2527 return 1;
2528 }
2529
doCreate(HWND hWnd,LPCREATESTRUCT lpcs)2530 LRESULT ModelWindow::doCreate(HWND hWnd, LPCREATESTRUCT lpcs)
2531 {
2532 if (CUIOGLWindow::doCreate(hWnd, lpcs) == -1)
2533 {
2534 return -1;
2535 }
2536 else
2537 {
2538 DragAcceptFiles(hWnd, TRUE);
2539 return 0;
2540 }
2541 }
2542
doDropFiles(HDROP hDrop)2543 LRESULT ModelWindow::doDropFiles(HDROP hDrop)
2544 {
2545 UCCHAR buf[1024];
2546 if (DragQueryFile(hDrop, 0, buf, COUNT_OF(buf)) > 0)
2547 {
2548 DragFinish(hDrop);
2549 ((LDViewWindow*)parentWindow)->openModel(buf);
2550 return 0;
2551 }
2552 return 1;
2553 }
2554
checkForPart(void)2555 void ModelWindow::checkForPart(void)
2556 {
2557 bool isPart = false;
2558 UCCHAR buf[MAX_PATH];
2559 UCSTR filePart;
2560 ucstring filename;
2561 utf8toucstring(filename, modelViewer->getFilename());
2562
2563 if (GetFullPathName(filename.c_str(), COUNT_OF(buf), buf, &filePart))
2564 {
2565 char partsDir[1024];
2566 std::string fullPath;
2567 ucstringtoutf8(fullPath, buf);
2568
2569 *filePart = 0;
2570 stripTrailingPathSeparators(buf);
2571 strcpy(partsDir, LDLModel::lDrawDir());
2572 strcat(partsDir, "\\PARTS");
2573 convertStringToUpper(partsDir);
2574 convertStringToUpper(&fullPath[0]);
2575 replaceStringCharacter(&fullPath[0], '/', '\\');
2576 replaceStringCharacter(partsDir, '/', '\\');
2577 if (fullPath == partsDir)
2578 {
2579 isPart = true;
2580 }
2581 else
2582 {
2583 ucstring ucPartsDir;
2584 utf8toucstring(ucPartsDir, partsDir);
2585 UCCHAR shortPath[1024];
2586
2587 if (GetShortPathName(ucPartsDir.c_str(), shortPath,
2588 COUNT_OF(shortPath)))
2589 {
2590 if (ucstrcmp(buf, shortPath) == 0)
2591 {
2592 isPart = true;
2593 }
2594 }
2595 }
2596 }
2597 modelViewer->setFileIsPart(isPart);
2598 }
2599
chDirFromFilename(CUCSTR filename,UCSTR outFilename)2600 bool ModelWindow::chDirFromFilename(CUCSTR filename, UCSTR outFilename)
2601 {
2602 UCCHAR buf[MAX_PATH];
2603 UCCHAR* fileSpot;
2604 DWORD result = GetFullPathName(filename, MAX_PATH, buf, &fileSpot);
2605
2606 if (result <= MAX_PATH && result > 0)
2607 {
2608 // if (strlen(fileSpot) < strlen(filename))
2609 {
2610 ucstrcpy(outFilename, buf);
2611 }
2612 *fileSpot = 0;
2613 if (SetCurrentDirectory(buf))
2614 {
2615 return true;
2616 }
2617 }
2618 return false;
2619 }
2620
printSystemError(void)2621 void ModelWindow::printSystemError(void)
2622 {
2623 #ifdef _DEBUG
2624 DWORD error = GetLastError();
2625 UCSTR buf;
2626
2627 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
2628 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error,
2629 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (UCSTR)&buf,
2630 0, NULL);
2631 _CrtDbgReport(_CRT_WARN, NULL, 0, NULL, "%s\n", buf);
2632 LocalFree(buf);
2633 #endif
2634 }
2635
setupMaterial(void)2636 void ModelWindow::setupMaterial(void)
2637 {
2638 // Don't call super.
2639 }
2640
setupLighting(void)2641 void ModelWindow::setupLighting(void)
2642 {
2643 // LDrawModelViewer::setPolygonOffsetFunc((GLPolygonOffsetFunc)glPolygonOffset);
2644 modelViewer->setup();
2645 }
2646
setStatusText(HWND hStatus,int part,CUCSTR text,bool redraw)2647 void ModelWindow::setStatusText(
2648 HWND hStatus,
2649 int part,
2650 CUCSTR text,
2651 bool redraw)
2652 {
2653 ((LDViewWindow*)parentWindow)->setStatusText(hStatus, part, text, redraw);
2654 }
2655
drawFPS(void)2656 void ModelWindow::drawFPS(void)
2657 {
2658 if (prefs->getShowsFPS())
2659 {
2660 if (((LDViewWindow*)parentWindow)->getFullScreen() || !hStatusBar)
2661 {
2662 if (currentAntialiasType)
2663 {
2664 glDisable(GL_MULTISAMPLE_ARB);
2665 }
2666 modelViewer->drawFPS(fps);
2667 if (currentAntialiasType)
2668 {
2669 glEnable(GL_MULTISAMPLE_ARB);
2670 }
2671 }
2672 else if (hStatusBar)
2673 {
2674 UCCHAR fpsString[1024] = _UC("");
2675
2676 if (modelViewer->getMainTREModel())
2677 {
2678 if (fps > 0.0f)
2679 {
2680 sucprintf(fpsString, COUNT_OF(fpsString),
2681 ls(_UC("FPSFormat")), fps);
2682 }
2683 else
2684 {
2685 ucstrcpy(fpsString,
2686 ls(_UC("FPSSpinPrompt")));
2687 }
2688 }
2689 setStatusText(hStatusBar, 1, fpsString);
2690 }
2691 }
2692 else if (hStatusBar)
2693 {
2694 setStatusText(hStatusBar, 1, _UC(""));
2695 }
2696 }
2697
doPostPaint(void)2698 void ModelWindow::doPostPaint(void)
2699 {
2700 checkFileForUpdates();
2701 if (hProgressBar)
2702 {
2703 if (!RedrawWindow(hProgressBar, NULL, NULL, RDW_ERASE | RDW_INVALIDATE
2704 | RDW_ERASENOW | RDW_UPDATENOW | RDW_ALLCHILDREN))
2705 {
2706 debugPrintf("RedrawWindow failed!\n");
2707 }
2708 }
2709 }
2710
updateFPS(void)2711 void ModelWindow::updateFPS(void)
2712 {
2713 DWORD thisFrameTime;
2714
2715 thisFrameTime = timeGetTime();
2716 numFramesSinceReference++;
2717 if (firstFPSPass)
2718 {
2719 fps = 0.0f;
2720 referenceFrameTime = thisFrameTime;
2721 numFramesSinceReference = 0;
2722 firstFPSPass = false;
2723 }
2724 else if (thisFrameTime - referenceFrameTime >= 250)
2725 {
2726 if (thisFrameTime > referenceFrameTime)
2727 {
2728 fps = 1000.0f / (TCFloat)(thisFrameTime - referenceFrameTime) *
2729 numFramesSinceReference;
2730 }
2731 else
2732 {
2733 fps = 0.0f;
2734 }
2735 referenceFrameTime = thisFrameTime;
2736 numFramesSinceReference = 0;
2737 firstFPSPass = false;
2738 }
2739 if (!frontBufferFPS())
2740 {
2741 drawFPS();
2742 }
2743 }
2744
frontBufferFPS(void)2745 bool ModelWindow::frontBufferFPS(void)
2746 {
2747 if (prefs->getUseNvMultisampleFilter())
2748 {
2749 static bool checkedSwapInterval = false;
2750 static int swapInterval = 0;
2751
2752 if (!checkedSwapInterval)
2753 {
2754 int (*wglGetSwapIntervalEXT)(void) =
2755 (int(*)(void))wglGetProcAddress("wglGetSwapIntervalEXT");
2756
2757 checkedSwapInterval = true;
2758 if (wglGetSwapIntervalEXT)
2759 {
2760 swapInterval = wglGetSwapIntervalEXT();
2761 }
2762 else
2763 {
2764 swapInterval = 0;
2765 }
2766 }
2767
2768 if (swapInterval > 0)
2769 {
2770 // We only want to draw the FPS text to the front buffer if vsync
2771 // is turned on.
2772 return true;
2773 }
2774 }
2775 return false;
2776 }
2777
swapBuffers(void)2778 void ModelWindow::swapBuffers(void)
2779 {
2780 if (!SwapBuffers(hdc))
2781 {
2782 DWORD error = GetLastError();
2783 UCCHAR buf[1024];
2784
2785 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
2786 FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, 0, buf,
2787 1024, NULL);
2788 char *errorMessage = ucstringtombs(buf);
2789 debugPrintf("swapBuffers error: %s\n", errorMessage);
2790 delete[] errorMessage;
2791 }
2792 if (frontBufferFPS())
2793 {
2794 glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_FASTEST);
2795 glDisable(GL_MULTISAMPLE_ARB);
2796 glDrawBuffer(GL_FRONT);
2797 drawFPS();
2798 glDrawBuffer(GL_BACK);
2799 glFlush();
2800 glEnable(GL_MULTISAMPLE_ARB);
2801 glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);
2802 }
2803 }
2804
doPaint(void)2805 void ModelWindow::doPaint(void)
2806 {
2807 bool needsPostRedraw = (modelViewer->getNeedsReload() ||
2808 modelViewer->getNeedsRecompile()) && modelViewer->getMainTREModel();
2809
2810 // debugPrintf("ModelWindow::doPaint\n");
2811 if (offscreenActive || loading)
2812 {
2813 static bool looping = false;
2814 if (!looping)
2815 {
2816 RECT rect;
2817 POINT points[2];
2818
2819 GetClientRect(hWindow, &rect);
2820 points[0].x = rect.left;
2821 points[0].y = rect.top;
2822 points[1].x = rect.right;
2823 points[1].y = rect.bottom;
2824 MapWindowPoints(hWindow, hParentWindow, points, 2);
2825 rect.left = points[0].x;
2826 rect.top = points[0].y;
2827 rect.right = points[1].x;
2828 rect.bottom = points[1].y;
2829 looping = true;
2830 // RedrawWindow(hWindow, NULL, NULL, RDW_ERASE/* | RDW_ERASENOW*/);
2831 RedrawWindow(hParentWindow, &rect, NULL, RDW_ERASE | RDW_INVALIDATE
2832 | RDW_ERASENOW | RDW_UPDATENOW);
2833 ValidateRect(hWindow, NULL);
2834 looping = false;
2835 }
2836 else
2837 {
2838 ValidateRect(hWindow, NULL);
2839 }
2840 return;
2841 }
2842 if (!initializedGL)
2843 {
2844 forceRedraw();
2845 return;
2846 }
2847 if (redrawCount > 0)
2848 {
2849 //debugPrintf("Multi-forced redraw.\n");
2850 forceRedraw();
2851 redrawCount--;
2852 return;
2853 }
2854 makeCurrent();
2855 //if (needsRecompile)
2856 //{
2857 // needsRecompile = false;
2858 // recompile();
2859 //}
2860 if (loading)
2861 {
2862 modelViewer->clear();
2863 swapBuffers();
2864 return;
2865 }
2866 forceRedraw();
2867 redrawRequested = false;
2868 modelViewer->update();
2869
2870 //updateSpinRate();
2871 //if ((fEq(rotationSpeed, 0.0f) && fEq(modelViewer->getZoomSpeed(), 0.0f)
2872 // && fEq(modelViewer->getCameraXRotate(), 0.0f) &&
2873 // fEq(modelViewer->getCameraYRotate(), 0.0f) &&
2874 // fEq(modelViewer->getCameraZRotate(), 0.0f) &&
2875 // fEq(modelViewer->getCameraMotion().length(), 0.0f))
2876 // || modelViewer->getPaused())
2877 if (!redrawRequested)
2878 {
2879 if (redrawCount == 0)
2880 {
2881 ValidateRect(hWindow, NULL);
2882 firstFPSPass = true;
2883 }
2884 }
2885 updateFPS();
2886 if (redrawCount > 0)
2887 {
2888 redrawCount--;
2889 }
2890 swapBuffers();
2891 if (needsPostRedraw)
2892 {
2893 forceRedraw();
2894 }
2895 ((LDViewWindow *)parentWindow)->showStatusLatLon();
2896 }
2897
doNCDestroy(void)2898 LRESULT ModelWindow::doNCDestroy(void)
2899 {
2900 if (prefs && !applyingPrefs)
2901 {
2902 prefs->closePropertySheet(true);
2903 hPrefsWindow = NULL;
2904 }
2905 if (hProgressWindow)
2906 {
2907 DestroyWindow(hProgressWindow);
2908 hProgressWindow = NULL;
2909 }
2910 if (hErrorWindow)
2911 {
2912 DestroyWindow(hErrorWindow);
2913 hErrorWindow = NULL;
2914 }
2915 return CUIOGLWindow::doNCDestroy();
2916 }
2917
doDestroy(void)2918 LRESULT ModelWindow::doDestroy(void)
2919 {
2920 cancelLoad = true;
2921 openGlWillEnd();
2922 // RevokeDragDrop(hWindow);
2923 return CUIOGLWindow::doDestroy();
2924 }
2925
zoom(TCFloat amount)2926 void ModelWindow::zoom(TCFloat amount)
2927 {
2928 if (modelViewer)
2929 {
2930 modelViewer->zoom(amount);
2931 forceRedraw();
2932 }
2933 }
2934
setClipZoom(bool value)2935 void ModelWindow::setClipZoom(bool value)
2936 {
2937 if (modelViewer)
2938 {
2939 modelViewer->setClipZoom(value);
2940 }
2941 }
2942
getClipZoom(void)2943 bool ModelWindow::getClipZoom(void)
2944 {
2945 if (modelViewer)
2946 {
2947 return modelViewer->getClipZoom();
2948 }
2949 else
2950 {
2951 return false;
2952 }
2953 }
2954
startPolling(void)2955 void ModelWindow::startPolling(void)
2956 {
2957 if (pollSetting && !pollTimerRunning && !loading)
2958 {
2959 setTimer(POLL_TIMER, POLL_INTERVAL);
2960 lastFileSizeHigh = lastFileSizeLow = 0;
2961 pollTimerRunning = true;
2962 }
2963 }
2964
stopPolling(void)2965 BOOL ModelWindow::stopPolling(void)
2966 {
2967 if (loading)
2968 {
2969 return TRUE;
2970 }
2971 else
2972 {
2973 pollTimerRunning = false;
2974 return killTimer(POLL_TIMER);
2975 }
2976 }
2977
setPollSetting(int value)2978 void ModelWindow::setPollSetting(int value)
2979 {
2980 if (value != pollSetting)
2981 {
2982 pollSetting = value;
2983 if (pollSetting)
2984 {
2985 startPolling();
2986 }
2987 else
2988 {
2989 stopPolling();
2990 }
2991 }
2992 }
2993
2994 //bool ModelWindow::writeImage(char *filename, int width, int height,
2995 // BYTE *buffer, char *formatName, bool saveAlpha)
2996 //{
2997 // TCImage *image = new TCImage;
2998 // bool retValue;
2999 // const char *version = LDViewWindow::getProductVersion();
3000 // char comment[1024];
3001 //
3002 // if (saveAlpha)
3003 // {
3004 // image->setDataFormat(TCRgba8);
3005 // }
3006 // image->setSize(width, height);
3007 // image->setLineAlignment(4);
3008 // image->setImageData(buffer);
3009 // image->setFormatName(formatName);
3010 // image->setFlipped(true);
3011 // if (strcasecmp(formatName, "PNG") == 0)
3012 // {
3013 // strcpy(comment, "Software:!:!:LDView");
3014 // }
3015 // else
3016 // {
3017 // strcpy(comment, "Created by LDView");
3018 // }
3019 // if (version)
3020 // {
3021 // strcat(comment, " ");
3022 // strcat(comment, version);
3023 // }
3024 // image->setComment(comment);
3025 // if (TCUserDefaults::longForKey(AUTO_CROP_KEY, 0, false))
3026 // {
3027 // image->autoCrop((BYTE)modelViewer->getBackgroundR(),
3028 // (BYTE)modelViewer->getBackgroundG(),
3029 // (BYTE)modelViewer->getBackgroundB());
3030 // }
3031 // retValue = image->saveFile(filename, staticImageProgressCallback, this);
3032 // image->release();
3033 // return retValue;
3034 //}
3035
3036 //bool ModelWindow::writeBmp(char *filename, int width, int height, BYTE *buffer)
3037 //{
3038 // return writeImage(filename, width, height, buffer, "BMP");
3039 //}
3040 //
3041 //bool ModelWindow::writePng(char *filename, int width, int height, BYTE *buffer,
3042 // bool saveAlpha)
3043 //{
3044 // return writeImage(filename, width, height, buffer, "PNG", saveAlpha);
3045 //}
3046
setupBitmapRender(int imageWidth,int imageHeight)3047 bool ModelWindow::setupBitmapRender(int imageWidth, int imageHeight)
3048 {
3049 hBitmapRenderDC = CreateCompatibleDC(NULL);
3050 BYTE *bmBuffer;
3051
3052 if (!hBitmapRenderDC)
3053 {
3054 return false;
3055 }
3056 hRenderBitmap = createDIBSection(hBitmapRenderDC, imageWidth, imageHeight,
3057 &bmBuffer);
3058 if (hRenderBitmap)
3059 {
3060 PIXELFORMATDESCRIPTOR pfd;
3061 int lpfIndex;
3062
3063 memset(&pfd, 0, sizeof(pfd));
3064 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
3065 pfd.nVersion = 1;
3066 pfd.dwFlags = PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL;
3067 pfd.iPixelType = PFD_TYPE_RGBA;
3068 pfd.cColorBits = 24;
3069 pfd.cDepthBits = 32;
3070 pfd.cStencilBits = 2;
3071 pfd.cAlphaBits = 8;
3072 SelectObject(hBitmapRenderDC, hRenderBitmap);
3073 lpfIndex = ChoosePixelFormat(hBitmapRenderDC, &pfd);
3074 if (lpfIndex)
3075 {
3076 if (SetPixelFormat(hBitmapRenderDC, lpfIndex, &pfd))
3077 {
3078 hBitmapRenderGLRC = wglCreateContext(hBitmapRenderDC);
3079 if (hBitmapRenderGLRC)
3080 {
3081 openGlWillEnd();
3082 TREGLExtensions::disableAll(true);
3083 hCurrentDC = hBitmapRenderDC;
3084 hCurrentGLRC = hBitmapRenderGLRC;
3085 wglMakeCurrent(hBitmapRenderDC, hBitmapRenderGLRC);
3086 setupMaterial();
3087 setupLighting();
3088 glDepthFunc(GL_LEQUAL);
3089 glEnable(GL_DEPTH_TEST);
3090 glDrawBuffer(GL_FRONT);
3091 glReadBuffer(GL_FRONT);
3092 modelViewer->setWidth(imageWidth);
3093 modelViewer->setHeight(imageHeight);
3094 modelViewer->setup();
3095 modelViewer->pause();
3096 modelViewer->setNeedsRecompile();
3097 return true;
3098 }
3099 }
3100 }
3101 DeleteObject(hRenderBitmap);
3102 }
3103 DeleteDC(hBitmapRenderDC);
3104 hBitmapRenderDC = NULL;
3105 return false;
3106 }
3107
setupOffscreen(int imageWidth,int imageHeight,bool antialias)3108 bool ModelWindow::setupOffscreen(
3109 int imageWidth,
3110 int imageHeight,
3111 bool antialias)
3112 {
3113 if (snapshotTaker != NULL && snapshotTaker->getUseFBO())
3114 {
3115 if (saveImageType == PNG_IMAGE_TYPE_INDEX &&
3116 TCUserDefaults::boolForKey(HDR_SNAPSHOTS_KEY))
3117 {
3118 snapshotTaker->set16BPC(true);
3119 }
3120 return true;
3121 }
3122 else if (setupPBuffer(imageWidth, imageHeight, antialias))
3123 {
3124 return true;
3125 }
3126 else
3127 {
3128 return setupBitmapRender(imageWidth, imageHeight);
3129 }
3130 }
3131
setupPBuffer(int imageWidth,int imageHeight,bool antialias)3132 bool ModelWindow::setupPBuffer(int imageWidth, int imageHeight,
3133 bool antialias)
3134 {
3135 if (LDVExtensionsSetup::havePixelBufferExtension())
3136 {
3137 GLint intValues[] = {
3138 WGL_DRAW_TO_PBUFFER_ARB, GL_TRUE,
3139 WGL_RED_BITS_ARB, 8,
3140 WGL_GREEN_BITS_ARB, 8,
3141 WGL_BLUE_BITS_ARB, 8,
3142 WGL_ALPHA_BITS_ARB, 8,
3143 WGL_STENCIL_BITS_ARB, 2,
3144 0, 0,
3145 0, 0,
3146 0, 0
3147 };
3148 int index;
3149
3150 if (antialias)
3151 {
3152 int offset = sizeof(intValues) / sizeof(GLint) - 6;
3153
3154 intValues[offset++] = WGL_SAMPLES_EXT;
3155 intValues[offset++] = prefs->getFSAAFactor();
3156 intValues[offset++] = WGL_SAMPLE_BUFFERS_EXT;
3157 intValues[offset++] = GL_TRUE;
3158 }
3159 index = LDVExtensionsSetup::choosePixelFormat(hdc, intValues);
3160 if (index >= 0)
3161 {
3162 using namespace TREGLExtensionsNS;
3163
3164 if (wglCreatePbufferARB && wglGetPbufferDCARB &&
3165 wglGetPixelFormatAttribivARB)
3166 {
3167 int pfSizeAttribs[3] = {
3168 WGL_MAX_PBUFFER_WIDTH_ARB,
3169 WGL_MAX_PBUFFER_HEIGHT_ARB,
3170 WGL_MAX_PBUFFER_PIXELS_ARB
3171 };
3172 int attribValues[3];
3173
3174 wglGetPixelFormatAttribivARB(hdc, index, 0, 3, pfSizeAttribs,
3175 attribValues);
3176 // This shouldn't be necessary, but ATI returns a PBuffer even
3177 // if we ask for one that is too big, so we can't rely on their
3178 // failure to trigger failure. The one it returns CLAIMS to be
3179 // the size we asked for; it just doesn't work right.
3180 if (attribValues[0] >= imageWidth &&
3181 attribValues[1] >= imageHeight &&
3182 attribValues[2] >= imageWidth * imageHeight)
3183 {
3184 // Given the above check, the following shouldn't really
3185 // matter, but I'll leave it in anyway.
3186 GLint cbpIntValues[] = {
3187 WGL_PBUFFER_LARGEST_ARB, 0,
3188 0, 0
3189 };
3190 hPBuffer = wglCreatePbufferARB(hdc, index, imageWidth,
3191 imageHeight, cbpIntValues);
3192
3193 if (hPBuffer)
3194 {
3195 hPBufferDC = wglGetPbufferDCARB(hPBuffer);
3196 if (hPBufferDC)
3197 {
3198 hPBufferGLRC = wglCreateContext(hPBufferDC);
3199
3200 if (hPBufferGLRC)
3201 {
3202 wglShareLists(hglrc, hPBufferGLRC);
3203 hCurrentDC = hPBufferDC;
3204 hCurrentGLRC = hPBufferGLRC;
3205 makeCurrent();
3206 if (antialias)
3207 {
3208 setupMultisample();
3209 }
3210 setupMaterial();
3211 setupLighting();
3212 glDepthFunc(GL_LEQUAL);
3213 glEnable(GL_DEPTH_TEST);
3214 glDrawBuffer(GL_FRONT);
3215 glReadBuffer(GL_FRONT);
3216 modelViewer->setWidth(imageWidth);
3217 modelViewer->setHeight(imageHeight);
3218 modelViewer->setup();
3219 modelViewer->pause();
3220 if (modelViewer->getNeedsReload())
3221 {
3222 return true;
3223 }
3224 else
3225 {
3226 // No need to recompile as before, because
3227 // we're sharing display lists.
3228 return true;
3229 }
3230 }
3231 }
3232 }
3233 }
3234 }
3235 }
3236 cleanupOffscreen();
3237 if (antialias)
3238 {
3239 return setupPBuffer(imageWidth, imageHeight, false);
3240 }
3241 }
3242 return false;
3243 }
3244
renderOffscreenImage(void)3245 void ModelWindow::renderOffscreenImage(void)
3246 {
3247 makeCurrent();
3248 modelViewer->update();
3249 //if (canSaveAlpha())
3250 //{
3251 // glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT |
3252 // GL_VIEWPORT_BIT);
3253 // CUIOGLWindow::orthoView();
3254 // glColor4ub(0, 0, 0, 255);
3255 // glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
3256 // glEnable(GL_DEPTH_TEST);
3257 // glDisable(GL_LIGHTING);
3258 // glDisable(GL_POLYGON_OFFSET_FILL);
3259 // glDepthFunc(GL_GREATER);
3260 // glDepthRange(0.0f, 1.0f);
3261 // glBegin(GL_QUADS);
3262 // treGlVertex3f(0.0f, 0.0f, -1.0f);
3263 // treGlVertex3f((TCFloat)width, 0.0f, -1.0f);
3264 // treGlVertex3f((TCFloat)width, (TCFloat)height, -1.0f);
3265 // treGlVertex3f(0.0f, (TCFloat)height, -1.0f);
3266 // glEnd();
3267 // glPopAttrib();
3268 //}
3269 }
3270
updateModelViewerSize(void)3271 void ModelWindow::updateModelViewerSize(void)
3272 {
3273 double scaleFactor = getScaleFactor(true);
3274 modelViewer->setWidth(width / scaleFactor);
3275 modelViewer->setHeight(height / scaleFactor);
3276 modelViewer->setScaleFactor(scaleFactor);
3277 }
3278
cleanupRenderSettings(void)3279 void ModelWindow::cleanupRenderSettings(void)
3280 {
3281 if (!savingFromCommandLine)
3282 {
3283 // If we're saving from the command line, there's no need to
3284 // put things back for regular rendering (particularly
3285 // recompiling the model, which takes quite a bit of extra
3286 // time.
3287 makeCurrent();
3288 updateModelViewerSize();
3289 //modelViewer->recompile();
3290 modelViewer->unpause();
3291 modelViewer->setup();
3292 }
3293 }
3294
cleanupOffscreen(void)3295 void ModelWindow::cleanupOffscreen(void)
3296 {
3297 hCurrentDC = hdc;
3298 hCurrentGLRC = hglrc;
3299 if (hPBuffer)
3300 {
3301 cleanupPBuffer();
3302 }
3303 else if (hBitmapRenderGLRC)
3304 {
3305 cleanupBitmapRender();
3306 }
3307 cleanupRenderSettings();
3308 }
3309
cleanupBitmapRender(void)3310 void ModelWindow::cleanupBitmapRender(void)
3311 {
3312 if (hBitmapRenderGLRC)
3313 {
3314 openGlWillEnd();
3315 wglDeleteContext(hBitmapRenderGLRC);
3316 hBitmapRenderGLRC = NULL;
3317 }
3318 if (hRenderBitmap)
3319 {
3320 DeleteObject(hRenderBitmap);
3321 hRenderBitmap = NULL;
3322 }
3323 if (hBitmapRenderDC)
3324 {
3325 DeleteDC(hBitmapRenderDC);
3326 hBitmapRenderDC = NULL;
3327 }
3328 TREGLExtensions::disableAll(false);
3329 modelViewer->setNeedsRecompile();
3330 }
3331
cleanupPBuffer(void)3332 void ModelWindow::cleanupPBuffer(void)
3333 {
3334 if (hPBuffer)
3335 {
3336 using namespace TREGLExtensionsNS;
3337
3338 if (hPBufferDC)
3339 {
3340 if (hPBufferGLRC)
3341 {
3342 wglDeleteContext(hPBufferGLRC);
3343 hPBufferGLRC = NULL;
3344 }
3345 wglReleasePbufferDCARB(hPBuffer, hPBufferDC);
3346 hPBufferDC = NULL;
3347 }
3348 wglDestroyPbufferARB(hPBuffer);
3349 hPBuffer = NULL;
3350 }
3351 }
3352
3353 //bool ModelWindow::canSaveAlpha(void)
3354 //{
3355 // if (saveAlpha && saveImageType == PNG_IMAGE_TYPE_INDEX)
3356 // {
3357 // int alphaBits;
3358 //
3359 // glGetIntegerv(GL_ALPHA_BITS, &alphaBits);
3360 // return alphaBits > 0;
3361 // }
3362 // return false;
3363 //}
3364
setupSnapshotBackBuffer(int imageWidth,int imageHeight,RECT & rect)3365 void ModelWindow::setupSnapshotBackBuffer(int imageWidth, int imageHeight,
3366 RECT &rect)
3367 {
3368 makeCurrent();
3369 modelViewer->setSlowClear(true);
3370 GetWindowRect(hParentWindow, &rect);
3371 MoveWindow(hParentWindow, 0, 0, rect.right - rect.left,
3372 rect.bottom - rect.top, TRUE);
3373 modelViewer->setWidth(imageWidth);
3374 modelViewer->setHeight(imageHeight);
3375 modelViewer->setup();
3376 glReadBuffer(GL_BACK);
3377 }
3378
cleanupSnapshotBackBuffer(RECT & rect)3379 void ModelWindow::cleanupSnapshotBackBuffer(RECT &rect)
3380 {
3381 MoveWindow(hParentWindow, rect.left, rect.top, rect.right - rect.left,
3382 rect.bottom - rect.top, TRUE);
3383 RedrawWindow(hParentWindow, NULL, NULL,
3384 RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW);
3385 updateModelViewerSize();
3386 modelViewer->setup();
3387 }
3388
getSaveImageType(void)3389 LDSnapshotTaker::ImageType ModelWindow::getSaveImageType(void)
3390 {
3391 switch (saveImageType)
3392 {
3393 case PNG_IMAGE_TYPE_INDEX:
3394 return LDSnapshotTaker::ITPng;
3395 case BMP_IMAGE_TYPE_INDEX:
3396 return LDSnapshotTaker::ITBmp;
3397 case JPG_IMAGE_TYPE_INDEX:
3398 return LDSnapshotTaker::ITJpg;
3399 case SVG_IMAGE_TYPE_INDEX:
3400 return LDSnapshotTaker::ITSvg;
3401 case EPS_IMAGE_TYPE_INDEX:
3402 return LDSnapshotTaker::ITEps;
3403 case PDF_IMAGE_TYPE_INDEX:
3404 return LDSnapshotTaker::ITPdf;
3405 default:
3406 return LDSnapshotTaker::ITPng;
3407 }
3408 }
3409
grabSetup(int & imageWidth,int & imageHeight,RECT & origRect,bool & origSlowClear)3410 void ModelWindow::grabSetup(
3411 int &imageWidth,
3412 int &imageHeight,
3413 RECT &origRect,
3414 bool &origSlowClear)
3415 {
3416 currentAntialiasType = TCUserDefaults::longForKey(FSAA_MODE_KEY);
3417 int newWidth = 1600;
3418 int newHeight = 1200;
3419 int numXTiles, numYTiles;
3420
3421 memset(&origRect, 0, sizeof(origRect));
3422 origSlowClear = modelViewer->getSlowClear();
3423 offscreenActive = true;
3424 snapshotTaker->calcTiling(imageWidth, imageHeight, newWidth, newHeight,
3425 numXTiles, numYTiles);
3426 if (!setupOffscreen(newWidth, newHeight, currentAntialiasType > 0))
3427 {
3428 newWidth = width; // width is OpenGL window width
3429 newHeight = height; // height is OpenGL window height
3430 snapshotTaker->calcTiling(imageWidth, imageHeight, newWidth, newHeight,
3431 numXTiles, numYTiles);
3432 setupSnapshotBackBuffer(newWidth, newHeight, origRect);
3433 }
3434 }
3435
grabCleanup(RECT origRect,bool origSlowClear)3436 void ModelWindow::grabCleanup(RECT origRect, bool origSlowClear)
3437 {
3438 if (snapshotTaker->getUseFBO())
3439 {
3440 snapshotTaker->set16BPC(false);
3441 cleanupRenderSettings();
3442 }
3443 else if (hPBuffer || hBitmapRenderGLRC)
3444 {
3445 cleanupOffscreen();
3446 }
3447 else
3448 {
3449 cleanupSnapshotBackBuffer(origRect);
3450 }
3451 offscreenActive = false;
3452 modelViewer->setSlowClear(origSlowClear);
3453 }
3454
saveImage(UCSTR filename,int imageWidth,int imageHeight,bool zoomToFit)3455 bool ModelWindow::saveImage(
3456 UCSTR filename,
3457 int imageWidth,
3458 int imageHeight,
3459 bool zoomToFit)
3460 {
3461 RECT origRect;
3462 bool origSlowClear;
3463 bool retValue = false;
3464
3465 if (!snapshotTaker)
3466 {
3467 snapshotTaker = new LDSnapshotTaker(modelViewer);
3468 // Only try FBO if the user hasn't unchecked the "Use Pixel Buffer"
3469 // check box. Note that snapshotTaker will also check that the
3470 // FBO extension is available before using it.
3471 if (LDVExtensionsSetup::havePixelBufferExtension())
3472 {
3473 snapshotTaker->setUseFBO(true);
3474 }
3475 }
3476 snapshotTaker->setImageType(getSaveImageType());
3477 snapshotTaker->setTrySaveAlpha(saveAlpha);
3478 snapshotTaker->setAutoCrop(autoCrop);
3479 std::string productVersion;
3480 ucstringtoutf8(productVersion,
3481 LDViewWindow::getProductVersion());
3482 snapshotTaker->setProductVersion(productVersion);
3483 grabSetup(imageWidth, imageHeight, origRect, origSlowClear);
3484 std::string utf8Filename;
3485 ucstringtoutf8(utf8Filename, filename);
3486 retValue = snapshotTaker->saveImage(utf8Filename.c_str(), imageWidth,
3487 imageHeight, zoomToFit);
3488 grabCleanup(origRect, origSlowClear);
3489 return retValue;
3490 }
3491
doDialogInit(HWND hDlg,HWND,LPARAM)3492 BOOL ModelWindow::doDialogInit(HWND hDlg, HWND /*hFocusWindow*/,
3493 LPARAM /*lParam*/)
3494 {
3495 if (hDlg == hPrintDialog)
3496 {
3497 setupPrintExtras();
3498 }
3499 else if (hDlg == hSaveDialog)
3500 {
3501 setupSaveExtras();
3502 }
3503 else if (hDlg == hPageSetupDialog)
3504 {
3505 setupPageSetupExtras();
3506 }
3507 return TRUE;
3508 }
3509
staticPrintHook(HWND hDlg,UINT uiMsg,WPARAM wParam,LPARAM lParam)3510 UINT_PTR CALLBACK ModelWindow::staticPrintHook(
3511 HWND hDlg,
3512 UINT uiMsg,
3513 WPARAM wParam,
3514 LPARAM lParam)
3515 {
3516 ModelWindow* modelWindow = (ModelWindow*)GetWindowLongPtr(hDlg,
3517 GWLP_USERDATA);
3518
3519 if (uiMsg == WM_INITDIALOG)
3520 {
3521 modelWindow = (ModelWindow*)((PRINTDLG*)lParam)->lCustData;
3522 if (modelWindow)
3523 {
3524 modelWindow->hPrintDialog = hDlg;
3525 SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)modelWindow);
3526 }
3527 }
3528 if (modelWindow)
3529 {
3530 return modelWindow->dialogProc(hDlg, uiMsg, wParam, lParam);
3531 }
3532 else
3533 {
3534 return 0;
3535 }
3536 }
3537
selectPrinter(PRINTDLG & pd)3538 bool ModelWindow::selectPrinter(PRINTDLG &pd)
3539 {
3540 HGLOBAL hDevMode = GlobalAlloc(GHND, sizeof(DEVMODE));
3541 DEVMODE *devMode = (DEVMODE *)GlobalLock(hDevMode);
3542 bool retValue;
3543
3544 devMode->dmFields = DM_ORIENTATION | DM_PAPERSIZE;
3545 devMode->dmOrientation = (short)printOrientation;
3546 devMode->dmPaperSize = (short)printPaperSize;
3547 GlobalUnlock(hDevMode);
3548 // Initialize the PRINTDLG members.
3549 pd.lStructSize = sizeof(PRINTDLG);
3550 pd.hDevMode = hDevMode;
3551 pd.hDevNames = NULL;
3552 pd.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION;// |
3553 // PD_ENABLEPRINTHOOK | PD_ENABLEPRINTTEMPLATE;
3554 pd.hwndOwner = NULL;//parentWindow->getHWindow();
3555 pd.hDC = NULL;
3556 pd.nFromPage = 1;
3557 pd.nToPage = 1;
3558 pd.nMinPage = 0;
3559 pd.nMaxPage = 0;
3560 pd.nCopies = 1;
3561 pd.hInstance = getLanguageModule();
3562 pd.lCustData = (LPARAM)this;
3563 pd.lpfnPrintHook = staticPrintHook;
3564 pd.lpfnSetupHook = NULL;
3565 pd.lpPrintTemplateName = MAKEINTRESOURCE(PRINTDLGORD);
3566 pd.lpSetupTemplateName = NULL;
3567 pd.hPrintTemplate = NULL;
3568 pd.hSetupTemplate = NULL;
3569
3570 // Display the PRINT dialog box.
3571
3572 if (PrintDlg(&pd))
3573 {
3574 hPrintDialog = NULL;
3575 retValue = true;
3576 }
3577 else
3578 {
3579 // DWORD error = CommDlgExtendedError();
3580 hPrintDialog = NULL;
3581 retValue = false;
3582 }
3583 GlobalFree(hDevMode);
3584 return retValue;
3585 }
3586
swap(int & left,int & right)3587 void ModelWindow::swap(int &left, int &right)
3588 {
3589 int temp = left;
3590
3591 left = right;
3592 right = temp;
3593 }
3594
calcTiling(int desiredWidth,int desiredHeight,int & bitmapWidth,int & bitmapHeight,int & numXTiles,int & numYTiles)3595 void ModelWindow::calcTiling(int desiredWidth, int desiredHeight,
3596 int &bitmapWidth, int &bitmapHeight,
3597 int &numXTiles, int &numYTiles)
3598 {
3599 if (desiredWidth > bitmapWidth)
3600 {
3601 numXTiles = (desiredWidth + bitmapWidth - 1) / bitmapWidth;
3602 }
3603 else
3604 {
3605 numXTiles = 1;
3606 }
3607 bitmapWidth = desiredWidth / numXTiles;
3608 if (desiredHeight > bitmapHeight)
3609 {
3610 numYTiles = (desiredHeight + bitmapHeight - 1) / bitmapHeight;
3611 }
3612 else
3613 {
3614 numYTiles = 1;
3615 }
3616 bitmapHeight = desiredHeight / numYTiles;
3617 }
3618
calcTiling(HDC hPrinterDC,int & bitmapWidth,int & bitmapHeight,int & numXTiles,int & numYTiles)3619 void ModelWindow::calcTiling(HDC hPrinterDC, int &bitmapWidth,
3620 int &bitmapHeight, int &numXTiles, int &numYTiles)
3621 {
3622 int hRes;
3623 int vRes;
3624 int printXOffset;
3625 int printYOffset;
3626 int printWidth;
3627 int printHeight;
3628 int printRMarginPixels;
3629 int printBMarginPixels;
3630 int maxBitmapWidth = bitmapWidth;
3631 int maxBitmapHeight = bitmapHeight;
3632
3633 printHDPI = GetDeviceCaps(hPrinterDC, LOGPIXELSX);
3634 printVDPI = GetDeviceCaps(hPrinterDC, LOGPIXELSY);
3635 printXOffset = GetDeviceCaps(hPrinterDC, PHYSICALOFFSETX);
3636 printYOffset = GetDeviceCaps(hPrinterDC, PHYSICALOFFSETY);
3637 printWidth = GetDeviceCaps(hPrinterDC, PHYSICALWIDTH);
3638 printHeight = GetDeviceCaps(hPrinterDC, PHYSICALHEIGHT);
3639 hRes = GetDeviceCaps(hPrinterDC, HORZRES);
3640 vRes = GetDeviceCaps(hPrinterDC, VERTRES);
3641 printLMarginPixels = (int)(printLeftMargin * printHDPI) - printXOffset;
3642 printRMarginPixels = (int)(printRightMargin * printHDPI) + hRes -
3643 printWidth + printXOffset;
3644 printTMarginPixels = (int)(printTopMargin * printVDPI) - printYOffset;
3645 printBMarginPixels = (int)(printBottomMargin * printVDPI) + vRes -
3646 printHeight + printYOffset;
3647 bitmapWidth = hRes - printLMarginPixels - printRMarginPixels;
3648 if (bitmapWidth > maxBitmapWidth)
3649 {
3650 numXTiles = (bitmapWidth + maxBitmapWidth - 1) / maxBitmapWidth;
3651 }
3652 else
3653 {
3654 numXTiles = 1;
3655 }
3656 bitmapWidth = bitmapWidth / numXTiles;
3657 bitmapHeight = vRes - printTMarginPixels - printBMarginPixels;
3658 if (bitmapHeight > maxBitmapHeight)
3659 {
3660 numYTiles = (bitmapHeight + maxBitmapHeight - 1) / maxBitmapHeight;
3661 }
3662 else
3663 {
3664 numYTiles = 1;
3665 }
3666 bitmapHeight = bitmapHeight / numYTiles;
3667 }
3668
printPage(const PRINTDLG & pd)3669 bool ModelWindow::printPage(const PRINTDLG &pd)
3670 {
3671 bool retValue = false;
3672 HDC hBitmapDC = CreateCompatibleDC(pd.hDC);
3673
3674 if (hBitmapDC)
3675 {
3676 int bitmapWidth = 1600;
3677 int bitmapHeight = 1200;
3678 int renderWidth;
3679 int renderHeight;
3680 int numXTiles;
3681 int numYTiles;
3682 bool oldSlowClear = modelViewer->getSlowClear();
3683 int oldR = modelViewer->getBackgroundR();
3684 int oldG = modelViewer->getBackgroundG();
3685 int oldB = modelViewer->getBackgroundB();
3686 int oldA = modelViewer->getBackgroundA();
3687 LDVStereoMode oldStereoMode = modelViewer->getStereoMode();
3688 BYTE *bmBuffer = NULL;
3689 HBITMAP hBitmap = NULL;
3690 bool canceled = false;
3691 bool landscape = printOrientation == DMORIENT_LANDSCAPE;
3692
3693 calcTiling(pd.hDC, bitmapWidth, bitmapHeight, numXTiles, numYTiles);
3694 if (landscape)
3695 {
3696 renderWidth = bitmapHeight;
3697 renderHeight = bitmapWidth;
3698 swap(numXTiles, numYTiles);
3699 }
3700 else
3701 {
3702 renderWidth = bitmapWidth;
3703 renderHeight = bitmapHeight;
3704 }
3705 offscreenActive = true;
3706 if (printHDPI != printVDPI)
3707 {
3708 modelViewer->setPixelAspectRatio((float)printHDPI / printVDPI);
3709 }
3710 if (printBackground)
3711 {
3712 modelViewer->setBackgroundRGBA(oldR, oldG, oldB, oldA);
3713 }
3714 else
3715 {
3716 modelViewer->setBackgroundRGBA(255, 255, 255, 255);
3717 }
3718 modelViewer->setStereoMode(LDVStereoNone);
3719 if (!setupOffscreen(renderWidth, renderHeight))
3720 {
3721 if (!modelViewer->getCompiled())
3722 {
3723 canceled = true;
3724 }
3725 else
3726 {
3727 if (landscape)
3728 {
3729 bitmapWidth = height;
3730 bitmapHeight = width;
3731 swap(numXTiles, numYTiles);
3732 }
3733 else
3734 {
3735 bitmapWidth = width;
3736 bitmapHeight = height;
3737 }
3738 calcTiling(pd.hDC, bitmapWidth, bitmapHeight, numXTiles,
3739 numYTiles);
3740 if (landscape)
3741 {
3742 renderWidth = bitmapHeight;
3743 renderHeight = bitmapWidth;
3744 }
3745 else
3746 {
3747 renderWidth = bitmapWidth;
3748 renderHeight = bitmapHeight;
3749 }
3750 modelViewer->setWidth(renderWidth);
3751 modelViewer->setHeight(renderHeight);
3752 makeCurrent();
3753 glReadBuffer(GL_BACK);
3754 modelViewer->setSlowClear(true);
3755 }
3756 }
3757 if (!canceled)
3758 {
3759 hBitmap = createDIBSection(hBitmapDC, bitmapWidth, bitmapHeight,
3760 &bmBuffer);
3761 }
3762 if (hBitmap)
3763 {
3764 int xTile, yTile;
3765 int renderLineSize = roundUp(renderWidth * 3, 4);
3766 BYTE *buffer = new BYTE[renderLineSize * renderHeight];
3767 TCFloat32 oldHighlightLineWidth =
3768 modelViewer->getHighlightLineWidth();
3769 TCFloat32 oldWireframeLineWidth =
3770 modelViewer->getWireframeLineWidth();
3771
3772 modelViewer->setNumXTiles(numXTiles);
3773 modelViewer->setNumYTiles(numYTiles);
3774 if (landscape)
3775 {
3776 swap(numXTiles, numYTiles);
3777 }
3778 modelViewer->setHighlightLineWidth(printHDPI / 100 *
3779 oldHighlightLineWidth);
3780 modelViewer->setWireframeLineWidth(printHDPI / 100 *
3781 oldWireframeLineWidth);
3782 for (yTile = 0; yTile < numYTiles && !canceled; yTile++)
3783 {
3784 if (landscape)
3785 {
3786 modelViewer->setXTile(yTile);
3787 }
3788 else
3789 {
3790 modelViewer->setYTile(yTile);
3791 }
3792 progressCallback(ls(_UC("PrintingModel")),
3793 0.0f, false);
3794 for (xTile = 0; xTile < numXTiles && !canceled; xTile++)
3795 {
3796 int lx, ly;
3797
3798 if (progressCallback((CUCSTR)NULL, (float)(yTile *
3799 numXTiles + xTile) / (numYTiles * numXTiles), false))
3800 {
3801 if (landscape)
3802 {
3803 modelViewer->setYTile(numXTiles - xTile - 1);
3804 }
3805 else
3806 {
3807 modelViewer->setXTile(xTile);
3808 }
3809 renderOffscreenImage();
3810 glReadPixels(0, 0, renderWidth, renderHeight, GL_RGB,
3811 GL_UNSIGNED_BYTE, buffer);
3812 if (landscape)
3813 {
3814 int bitmapLineSize = roundUp(bitmapWidth * 3, 4);
3815
3816 for (ly = 0; ly < renderHeight; ly++)
3817 {
3818 int offset = ly * renderLineSize;
3819 for (lx = 0; lx < renderWidth; lx++)
3820 {
3821 int renderSpot = offset + lx * 3;
3822 int bitmapSpot = (renderWidth - lx - 1)
3823 * bitmapLineSize + ly * 3;
3824
3825 bmBuffer[bitmapSpot] =
3826 buffer[renderSpot + 2];
3827 bmBuffer[bitmapSpot + 1] =
3828 buffer[renderSpot + 1];
3829 bmBuffer[bitmapSpot + 2] =
3830 buffer[renderSpot];
3831 }
3832 }
3833 }
3834 else
3835 {
3836 for (ly = 0; ly < bitmapHeight; ly++)
3837 {
3838 int offset = ly * renderLineSize;
3839
3840 for (lx = 0; lx < bitmapWidth; lx++)
3841 {
3842 int spot = offset + lx * 3;
3843
3844 bmBuffer[spot] = buffer[spot + 2];
3845 bmBuffer[spot + 1] = buffer[spot + 1];
3846 bmBuffer[spot + 2] = buffer[spot];
3847 }
3848 }
3849 }
3850 SelectObject(hBitmapDC, hBitmap);
3851 if (BitBlt(pd.hDC,
3852 printLMarginPixels + xTile * bitmapWidth,
3853 printTMarginPixels + yTile * bitmapHeight,
3854 bitmapWidth, bitmapHeight, hBitmapDC, 0, 0,
3855 SRCCOPY))
3856 {
3857 retValue = true;
3858 }
3859 }
3860 else
3861 {
3862 canceled = true;
3863 retValue = false;
3864 }
3865 }
3866 }
3867 progressCallback((CUCSTR)NULL, 1.0f, false);
3868 DeleteObject(hBitmap);
3869 modelViewer->setHighlightLineWidth(oldHighlightLineWidth);
3870 modelViewer->setWireframeLineWidth(oldWireframeLineWidth);
3871 modelViewer->setXTile(0);
3872 modelViewer->setYTile(0);
3873 modelViewer->setNumXTiles(1);
3874 modelViewer->setNumYTiles(1);
3875 delete buffer;
3876 progressCallback((CUCSTR)NULL, 2.0f, false);
3877 }
3878 if (hPBuffer)
3879 {
3880 cleanupOffscreen();
3881 }
3882 else
3883 {
3884 updateModelViewerSize();
3885 modelViewer->setSlowClear(oldSlowClear);
3886 }
3887 modelViewer->setBackgroundRGBA(oldR, oldG, oldB, oldA);
3888 modelViewer->setStereoMode(oldStereoMode);
3889 modelViewer->setPixelAspectRatio(1.0f);
3890 DeleteDC(hBitmapDC);
3891 }
3892 offscreenActive = false;
3893 return retValue;
3894 }
3895
parseDevMode(HGLOBAL hDevMode)3896 bool ModelWindow::parseDevMode(HGLOBAL hDevMode)
3897 {
3898 DEVMODE *devMode = (DEVMODE *)GlobalLock(hDevMode);
3899 bool retValue = true;
3900
3901 if (devMode)
3902 {
3903 if (devMode->dmOrientation != printOrientation)
3904 {
3905 printOrientation = devMode->dmOrientation;
3906 TCUserDefaults::setLongForKey(printOrientation, ORIENTATION_KEY, false);
3907 }
3908 if (devMode->dmPaperSize != printPaperSize)
3909 {
3910 if (devMode->dmPaperSize < DMPAPER_USER)
3911 {
3912 printPaperSize = devMode->dmPaperSize;
3913 TCUserDefaults::setLongForKey(printPaperSize, PAPER_SIZE_KEY,
3914 false);
3915 }
3916 else
3917 {
3918 retValue = false;
3919 }
3920 }
3921 GlobalUnlock(hDevMode);
3922 }
3923 return retValue;
3924 }
3925
staticPageSetupHook(HWND hDlg,UINT uiMsg,WPARAM wParam,LPARAM lParam)3926 UINT_PTR CALLBACK ModelWindow::staticPageSetupHook(
3927 HWND hDlg,
3928 UINT uiMsg,
3929 WPARAM wParam,
3930 LPARAM lParam)
3931 {
3932 ModelWindow* modelWindow = (ModelWindow*)GetWindowLongPtr(hDlg,
3933 GWLP_USERDATA);
3934
3935 if (uiMsg == WM_INITDIALOG)
3936 {
3937 modelWindow = (ModelWindow*)((PAGESETUPDLG*)lParam)->lCustData;
3938 if (modelWindow)
3939 {
3940 modelWindow->hPageSetupDialog = hDlg;
3941 SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)modelWindow);
3942 }
3943 }
3944 if (modelWindow)
3945 {
3946 return modelWindow->dialogProc(hDlg, uiMsg, wParam, lParam);
3947 }
3948 else
3949 {
3950 return 0;
3951 }
3952 }
3953
pageSetup(void)3954 bool ModelWindow::pageSetup(void)
3955 {
3956 PAGESETUPDLG psd;
3957 HGLOBAL hDevMode = GlobalAlloc(GHND, sizeof(DEVMODE));
3958 DEVMODE *devMode = (DEVMODE *)GlobalLock(hDevMode);
3959 bool retValue;
3960
3961 devMode->dmFields = DM_ORIENTATION | DM_PAPERSIZE;
3962 devMode->dmOrientation = (short)printOrientation;
3963 devMode->dmPaperSize = (short)printPaperSize;
3964 GlobalUnlock(hDevMode);
3965 psd.lStructSize = sizeof(PAGESETUPDLG);
3966 psd.hwndOwner = GetParent(hWindow);
3967 psd.hDevMode = hDevMode;
3968 psd.hDevNames = NULL;
3969 psd.Flags = PSD_DISABLEPRINTER | PSD_INTHOUSANDTHSOFINCHES | PSD_MARGINS |
3970 PSD_ENABLEPAGESETUPTEMPLATE | PSD_ENABLEPAGESETUPHOOK;
3971 psd.rtMargin.left = (long)(printLeftMargin * 1000);
3972 psd.rtMargin.right = (long)(printRightMargin * 1000);
3973 psd.rtMargin.top = (long)(printTopMargin * 1000);
3974 psd.rtMargin.bottom = (long)(printBottomMargin * 1000);
3975 psd.lCustData = (LPARAM)this;
3976 psd.hInstance = getLanguageModule();
3977 psd.lpfnPageSetupHook = staticPageSetupHook;
3978 psd.lpPageSetupTemplateName = MAKEINTRESOURCE(PAGESETUPDLGORD);
3979
3980 stopAnimation();
3981 if (PageSetupDlg(&psd))
3982 {
3983 printLeftMargin = psd.rtMargin.left / 1000.0f;
3984 printRightMargin = psd.rtMargin.right / 1000.0f;
3985 printTopMargin = psd.rtMargin.top / 1000.0f;
3986 printBottomMargin = psd.rtMargin.bottom / 1000.0f;
3987 if (!parseDevMode(psd.hDevMode))
3988 {
3989 MessageBox(hParentWindow,
3990 ls(_UC("PrintCustomPaperError")),
3991 ls(_UC("PrintPaperSize")),
3992 MB_OK | MB_ICONEXCLAMATION);
3993 }
3994 TCUserDefaults::setLongForKey(psd.rtMargin.left, LEFT_MARGIN_KEY,
3995 false);
3996 TCUserDefaults::setLongForKey(psd.rtMargin.right, RIGHT_MARGIN_KEY,
3997 false);
3998 TCUserDefaults::setLongForKey(psd.rtMargin.top, TOP_MARGIN_KEY, false);
3999 TCUserDefaults::setLongForKey(psd.rtMargin.bottom, BOTTOM_MARGIN_KEY,
4000 false);
4001 TCUserDefaults::setLongForKey(printBackground ? 1 : 0,
4002 PRINT_BACKGROUND_KEY, false);
4003 retValue = true;
4004 }
4005 else
4006 {
4007 retValue = false;
4008 }
4009 GlobalFree(hDevMode);
4010 return retValue;
4011 }
4012
print(void)4013 bool ModelWindow::print(void)
4014 {
4015 PRINTDLG pd;
4016 bool retValue = false;
4017
4018 stopAnimation();
4019 memset(&pd, 0, sizeof(pd));
4020 pd.lStructSize = sizeof(pd);
4021 if (selectPrinter(pd))
4022 {
4023 DOCINFO di;
4024 int printJobId;
4025 CUCSTR docName = parentWindow->getWindowTitle();
4026
4027 parseDevMode(pd.hDevMode);
4028 TCUserDefaults::setLongForKey(usePrinterDPI ? 1 : 0,
4029 USE_PRINTER_DPI_KEY);
4030 TCUserDefaults::setLongForKey(printDPI, PRINT_DPI_KEY);
4031 TCUserDefaults::setLongForKey(printBackground ? 1 : 0,
4032 PRINT_BACKGROUND_KEY, false);
4033
4034 di.cbSize = sizeof(DOCINFO);
4035 di.lpszDocName = docName;
4036 di.lpszOutput = NULL;
4037 di.lpszDatatype = NULL;
4038 di.fwType = 0;
4039 printJobId = StartDoc(pd.hDC, &di);
4040 if (printJobId > 0 && StartPage(pd.hDC) > 0)
4041 {
4042 if (printPage(pd))
4043 {
4044 retValue = true;
4045 EndPage(pd.hDC);
4046 EndDoc(pd.hDC);
4047 }
4048 else
4049 {
4050 EndPage(pd.hDC);
4051 AbortDoc(pd.hDC);
4052 }
4053 }
4054 }
4055 return retValue;
4056 }
4057
disableSaveSize(void)4058 void ModelWindow::disableSaveSize(void)
4059 {
4060 enableSaveSize(FALSE);
4061 }
4062
enableSaveSize(BOOL enable)4063 void ModelWindow::enableSaveSize(BOOL enable /*= TRUE*/)
4064 {
4065 EnableWindow(hSaveWidthLabel, enable);
4066 EnableWindow(hSaveWidth, enable);
4067 EnableWindow(hSaveHeightLabel, enable);
4068 EnableWindow(hSaveHeight, enable);
4069 EnableWindow(hSaveZoomToFitButton, enable);
4070 if (enable)
4071 {
4072 CUIDialog::windowSetValue(hSaveDialog, IDC_SAVE_WIDTH, saveWidth);
4073 SendDlgItemMessage(hSaveDialog, IDC_SAVE_WIDTH, EM_LIMITTEXT, 4, 0);
4074 CUIDialog::windowSetValue(hSaveDialog, IDC_SAVE_HEIGHT, saveHeight);
4075 SendDlgItemMessage(hSaveDialog, IDC_SAVE_HEIGHT, EM_LIMITTEXT, 4, 0);
4076 CUIDialog::buttonSetChecked(hSaveDialog, IDC_SAVE_ZOOMTOFIT,
4077 saveZoomToFit);
4078 }
4079 else
4080 {
4081 CUIDialog::windowSetText(hSaveDialog, IDC_SAVE_WIDTH, _UC(""));
4082 CUIDialog::windowSetText(hSaveDialog, IDC_SAVE_HEIGHT, _UC(""));
4083 CUIDialog::buttonSetChecked(hSaveDialog, IDC_SAVE_ZOOMTOFIT, false);
4084 }
4085 }
4086
disableSaveSeries(void)4087 void ModelWindow::disableSaveSeries(void)
4088 {
4089 enableSaveSeries(FALSE);
4090 }
4091
enableSaveSeries(BOOL enable)4092 void ModelWindow::enableSaveSeries(BOOL enable /*= TRUE*/)
4093 {
4094 EnableWindow(hSaveDigitsLabel, enable);
4095 EnableWindow(hSaveDigitsField, enable);
4096 EnableWindow(hSaveDigitsSpin, enable);
4097 if (enable)
4098 {
4099 SendDlgItemMessage(hSaveDialog, IDC_SAVE_DIGITS_SPIN, UDM_SETPOS, 0,
4100 MAKELONG(saveDigits, 0));
4101 }
4102 else
4103 {
4104 CUIDialog::windowSetText(hSaveDialog, IDC_SAVE_DIGITS, _UC(""));
4105 }
4106 }
4107
disableSaveAllSteps(void)4108 void ModelWindow::disableSaveAllSteps(void)
4109 {
4110 enableSaveAllSteps(FALSE);
4111 }
4112
enableSaveAllSteps(BOOL enable)4113 void ModelWindow::enableSaveAllSteps(BOOL enable /*= TRUE*/)
4114 {
4115 BOOL sameScaleEnable = enable && !saveActualSize && saveZoomToFit;
4116
4117 EnableWindow(hSaveStepSuffixLabel, enable);
4118 EnableWindow(hSaveStepSuffixField, enable);
4119 EnableWindow(hSaveStepsSameScaleButton, sameScaleEnable);
4120 if (enable)
4121 {
4122 CUIDialog::windowSetText(hSaveDialog, IDC_STEP_SUFFIX, saveStepSuffix);
4123 }
4124 else
4125 {
4126 CUIDialog::windowSetText(hSaveDialog, IDC_STEP_SUFFIX, _UC(""));
4127 }
4128 if (sameScaleEnable)
4129 {
4130 CUIDialog::buttonSetChecked(hSaveDialog, IDC_SAME_SCALE,
4131 saveStepsSameScale);
4132 }
4133 else
4134 {
4135 CUIDialog::buttonSetChecked(hSaveDialog, IDC_SAME_SCALE, false);
4136 }
4137 }
4138
updatePrintDPIField(void)4139 void ModelWindow::updatePrintDPIField(void)
4140 {
4141 if (usePrinterDPI)
4142 {
4143 EnableWindow(hPrintDPI, FALSE);
4144 CUIDialog::windowSetText(hPrintDialog, IDC_PRINT_DPI, _UC(""));
4145 }
4146 else
4147 {
4148 EnableWindow(hPrintDPI, TRUE);
4149 CUIDialog::windowSetValue(hPrintDialog, IDC_PRINT_DPI, printDPI);
4150 }
4151 }
4152
setupPrintExtras(void)4153 void ModelWindow::setupPrintExtras(void)
4154 {
4155 HWND hIconWindow = GetDlgItem(hPrintDialog, 1086);
4156 RECT iconRect;
4157 POINT iconPoint;
4158
4159 hPrintDPI = GetDlgItem(hPrintDialog, IDC_PRINT_DPI);
4160 GetWindowRect(hIconWindow, &iconRect);
4161 iconPoint.x = iconRect.left;
4162 iconPoint.y = iconRect.top;
4163 ScreenToClient(hPrintDialog, &iconPoint);
4164 MoveWindow(hIconWindow, iconPoint.x, iconPoint.y, 114, 36, TRUE);
4165 CUIDialog::buttonSetChecked(hPrintDialog, IDC_PRINT_PRINTER_DPI,
4166 usePrinterDPI);
4167 CUIDialog::buttonSetChecked(hPrintDialog, IDC_PRINT_SPECIFY_DPI,
4168 !usePrinterDPI);
4169 CUIDialog::buttonSetChecked(hPrintDialog, IDC_PRINT_BACKGROUND,
4170 printBackground);
4171 SendDlgItemMessage(hPrintDialog, IDC_PRINT_DPI, EM_LIMITTEXT, 4, 0);
4172 updatePrintDPIField();
4173 }
4174
setupPageSetupExtras(void)4175 void ModelWindow::setupPageSetupExtras(void)
4176 {
4177 CUIDialog::buttonSetChecked(hPageSetupDialog, IDC_PRINT_BACKGROUND,
4178 printBackground);
4179 }
4180
updateSaveSizeEnabled(void)4181 void ModelWindow::updateSaveSizeEnabled(void)
4182 {
4183 if (saveActualSize)
4184 {
4185 disableSaveSize();
4186 }
4187 else
4188 {
4189 enableSaveSize();
4190 }
4191 }
4192
updateSaveSeriesEnabled(void)4193 void ModelWindow::updateSaveSeriesEnabled(void)
4194 {
4195 if (saveSeries)
4196 {
4197 enableSaveSeries();
4198 }
4199 else
4200 {
4201 disableSaveSeries();
4202 }
4203 }
4204
updateSaveAllStepsEnabled(void)4205 void ModelWindow::updateSaveAllStepsEnabled(void)
4206 {
4207 if (saveAllSteps)
4208 {
4209 enableSaveAllSteps();
4210 }
4211 else
4212 {
4213 disableSaveAllSteps();
4214 }
4215 }
4216
saveTypeUpdated(void)4217 void ModelWindow::saveTypeUpdated(void)
4218 {
4219 switch (curSaveOp)
4220 {
4221 case LDPreferences::SOExport:
4222 saveExportTypeUpdated();
4223 break;
4224 case LDPreferences::SOSnapshot:
4225 default:
4226 saveImageTypeUpdated();
4227 break;
4228 }
4229 }
4230
saveImageTypeUpdated(void)4231 void ModelWindow::saveImageTypeUpdated(void)
4232 {
4233 BOOL enable = FALSE;
4234 WPARAM transBg = 0;
4235
4236 EnableWindow(hSaveOptionsButton, saveImageType == JPG_IMAGE_TYPE_INDEX);
4237 if (saveImageType == PNG_IMAGE_TYPE_INDEX)
4238 {
4239 enable = TRUE;
4240 transBg = saveAlpha ? 1 : 0;
4241 }
4242 buttonSetChecked(hSaveTransBgButton, transBg);
4243 EnableWindow(hSaveTransBgButton, enable);
4244 }
4245
saveExportTypeUpdated(void)4246 void ModelWindow::saveExportTypeUpdated(void)
4247 {
4248 BOOL enable = FALSE;
4249 const LDExporter *exporter;
4250
4251 exporter = modelViewer->getExporter(
4252 (LDrawModelViewer::ExportType)saveExportType);
4253 if (exporter != NULL && exporter->getSettings().size() > 0)
4254 {
4255 enable = TRUE;
4256 }
4257 EnableWindow(hSaveOptionsButton, enable);
4258 }
4259
setupSaveExtras(void)4260 void ModelWindow::setupSaveExtras(void)
4261 {
4262 hSaveOptionsButton = GetDlgItem(hSaveDialog, IDC_SAVE_OPTIONS);
4263 hSaveTransBgButton = GetDlgItem(hSaveDialog, IDC_TRANSPARENT_BACKGROUND);
4264 hSaveWidthLabel = GetDlgItem(hSaveDialog, IDC_SAVE_WIDTH_LABEL);
4265 hSaveWidth = GetDlgItem(hSaveDialog, IDC_SAVE_WIDTH);
4266 hSaveHeightLabel = GetDlgItem(hSaveDialog, IDC_SAVE_HEIGHT_LABEL);
4267 hSaveHeight = GetDlgItem(hSaveDialog, IDC_SAVE_HEIGHT);
4268 hSaveZoomToFitButton = GetDlgItem(hSaveDialog, IDC_SAVE_ZOOMTOFIT);
4269 hSaveDigitsLabel = GetDlgItem(hSaveDialog, IDC_SAVE_DIGITS_LABEL);
4270 hSaveDigitsField = GetDlgItem(hSaveDialog, IDC_SAVE_DIGITS);
4271 hSaveDigitsSpin = GetDlgItem(hSaveDialog, IDC_SAVE_DIGITS_SPIN);
4272 hSaveStepSuffixLabel = GetDlgItem(hSaveDialog, IDC_STEP_SUFFIX_LABEL);
4273 hSaveStepSuffixField = GetDlgItem(hSaveDialog, IDC_STEP_SUFFIX);
4274 hSaveStepsSameScaleButton = GetDlgItem(hSaveDialog, IDC_SAME_SCALE);
4275 CUIDialog::buttonSetChecked(hSaveDialog, IDC_SAVE_ACTUAL_SIZE,
4276 !saveActualSize);
4277 CUIDialog::buttonSetChecked(hSaveDialog, IDC_SAVE_SERIES, saveSeries);
4278 SendDlgItemMessage(hSaveDialog, IDC_SAVE_DIGITS_SPIN, UDM_SETRANGE32, 1, 5);
4279 SendDlgItemMessage(hSaveDialog, IDC_SAVE_DIGITS_SPIN, UDM_SETPOS, 0,
4280 MAKELONG(saveDigits, 0));
4281 CUIDialog::buttonSetChecked(hSaveDialog, IDC_IGNORE_PBUFFER, ignorePBuffer);
4282 CUIDialog::buttonSetChecked(hSaveDialog, IDC_IGNORE_FBO, ignoreFBO);
4283 CUIDialog::buttonSetChecked(hSaveDialog, IDC_IGNORE_PIXEL_FORMAT,
4284 ignorePixelFormat);
4285 CUIDialog::buttonSetChecked(hSaveDialog, IDC_AUTO_CROP, autoCrop);
4286 CUIDialog::buttonSetChecked(hSaveDialog, IDC_ALL_STEPS, saveAllSteps);
4287 updateSaveSizeEnabled();
4288 updateSaveSeriesEnabled();
4289 updateSaveAllStepsEnabled();
4290 saveTypeUpdated();
4291 }
4292
updateSaveWidth(void)4293 void ModelWindow::updateSaveWidth(void)
4294 {
4295 if (!saveActualSize)
4296 {
4297 int temp;
4298
4299 if (CUIDialog::windowGetValue(hSaveDialog, IDC_SAVE_WIDTH, temp) &&
4300 temp > 0 && temp <= MAX_SNAPSHOT_WIDTH)
4301 {
4302 saveWidth = temp;
4303 }
4304 else
4305 {
4306 CUIDialog::windowSetValue(hSaveDialog, IDC_SAVE_WIDTH, saveWidth);
4307 MessageBeep(MB_OK);
4308 }
4309 }
4310 }
4311
updateSaveHeight(void)4312 void ModelWindow::updateSaveHeight(void)
4313 {
4314 if (!saveActualSize)
4315 {
4316 int temp;
4317
4318 if (CUIDialog::windowGetValue(hSaveDialog, IDC_SAVE_HEIGHT, temp) &&
4319 temp > 0 && temp <= MAX_SNAPSHOT_HEIGHT)
4320 {
4321 saveHeight = temp;
4322 }
4323 else
4324 {
4325 CUIDialog::windowSetValue(hSaveDialog, IDC_SAVE_HEIGHT, saveHeight);
4326 MessageBeep(MB_OK);
4327 }
4328 }
4329 }
4330
updateStepSuffix(void)4331 void ModelWindow::updateStepSuffix(void)
4332 {
4333 if (saveAllSteps)
4334 {
4335 ucstring newSuffix;
4336
4337 CUIDialog::windowGetText(hSaveDialog, IDC_STEP_SUFFIX, newSuffix);
4338 delete saveStepSuffix;
4339 saveStepSuffix = copyString(newSuffix.c_str());
4340 }
4341 updateSaveFilename();
4342 }
4343
updateSaveFilename(void)4344 void ModelWindow::updateSaveFilename(void)
4345 {
4346 UCCHAR buf[1024];
4347
4348 if (calcSaveFilename(buf, 1024))
4349 {
4350 SendMessage(GetParent(hSaveDialog), CDM_SETCONTROLTEXT, edt1,
4351 (LPARAM)buf);
4352 }
4353 }
4354
updateSaveDigits(void)4355 void ModelWindow::updateSaveDigits(void)
4356 {
4357 int temp;
4358
4359 if (CUIDialog::windowGetValue(hSaveDialog, IDC_SAVE_DIGITS, temp) &&
4360 temp > 0 && temp <= 6)
4361 {
4362 saveDigits = temp;
4363 }
4364 updateSaveFilename();
4365 }
4366
doSaveOptionsClick(void)4367 void ModelWindow::doSaveOptionsClick(void)
4368 {
4369 switch (curSaveOp)
4370 {
4371 case LDPreferences::SOExport:
4372 {
4373 LDExporter *exporter = modelViewer->getExporter();
4374
4375 if (exporter != NULL)
4376 {
4377 ExportOptionsDialog *dialog = new ExportOptionsDialog(
4378 getLanguageModule(), exporter);
4379
4380 if (dialog->doModal(hSaveDialog) != IDOK)
4381 {
4382 // Force a new exporter to be created in order to forget
4383 // about any settings changes that might have happened as
4384 // a result of a reset.
4385 modelViewer->getExporter((LDrawModelViewer::ExportType)0,
4386 true);
4387 }
4388 dialog->release();
4389 }
4390 }
4391 break;
4392 case LDPreferences::SOSnapshot:
4393 default:
4394 {
4395 JpegOptionsDialog *dialog = new JpegOptionsDialog(
4396 getLanguageModule(), hSaveDialog);
4397
4398 dialog->doModal(hSaveDialog);
4399 dialog->release();
4400 }
4401 break;
4402 }
4403 }
4404
doSaveClick(int controlId,HWND)4405 BOOL ModelWindow::doSaveClick(int controlId, HWND /*hControlWnd*/)
4406 {
4407 switch (controlId)
4408 {
4409 case IDC_SAVE_OPTIONS:
4410 doSaveOptionsClick();
4411 break;
4412 case IDC_SAVE_ACTUAL_SIZE:
4413 saveActualSize = !CUIDialog::buttonGetCheck(hSaveDialog, controlId);
4414 updateSaveSizeEnabled();
4415 updateSaveAllStepsEnabled();
4416 break;
4417 case IDC_SAVE_SERIES:
4418 saveSeries = CUIDialog::buttonGetCheck(hSaveDialog, controlId);
4419 updateSaveSeriesEnabled();
4420 break;
4421 case IDC_ALL_STEPS:
4422 saveAllSteps = CUIDialog::buttonGetCheck(hSaveDialog, controlId);
4423 updateSaveAllStepsEnabled();
4424 break;
4425 case IDC_IGNORE_PBUFFER:
4426 ignorePBuffer = CUIDialog::buttonGetCheck(hSaveDialog, controlId);
4427 break;
4428 case IDC_IGNORE_FBO:
4429 ignoreFBO = CUIDialog::buttonGetCheck(hSaveDialog, controlId);
4430 break;
4431 case IDC_IGNORE_PIXEL_FORMAT:
4432 ignorePixelFormat = CUIDialog::buttonGetCheck(hSaveDialog, controlId);
4433 break;
4434 case IDC_TRANSPARENT_BACKGROUND:
4435 saveAlpha = CUIDialog::buttonGetCheck(hSaveDialog, controlId);
4436 break;
4437 case IDC_AUTO_CROP:
4438 autoCrop = CUIDialog::buttonGetCheck(hSaveDialog, controlId);
4439 break;
4440 case IDC_SAME_SCALE:
4441 saveStepsSameScale = CUIDialog::buttonGetCheck(hSaveDialog, controlId);
4442 break;
4443 case IDC_SAVE_ZOOMTOFIT:
4444 saveZoomToFit = CUIDialog::buttonGetCheck(hSaveDialog, controlId);
4445 updateSaveAllStepsEnabled();
4446 break;
4447 default:
4448 return FALSE;
4449 }
4450 return TRUE;
4451 }
4452
doSaveKillFocus(int controlId,HWND)4453 BOOL ModelWindow::doSaveKillFocus(int controlId, HWND /*hControlWnd*/)
4454 {
4455 switch (controlId)
4456 {
4457 case IDC_SAVE_WIDTH:
4458 updateSaveWidth();
4459 break;
4460 case IDC_SAVE_HEIGHT:
4461 updateSaveHeight();
4462 break;
4463 case IDC_SAVE_DIGITS:
4464 updateSaveDigits();
4465 break;
4466 default:
4467 return FALSE;
4468 }
4469 return TRUE;
4470 }
4471
doSaveNotify(int,LPOFNOTIFY notification)4472 BOOL ModelWindow::doSaveNotify(int /*controlId*/, LPOFNOTIFY notification)
4473 {
4474 switch(notification->hdr.code)
4475 {
4476 case CDN_TYPECHANGE:
4477 {
4478 UCCHAR buf[1024];
4479
4480 saveType = notification->lpOFN->nFilterIndex;
4481 switch (curSaveOp)
4482 {
4483 case LDPreferences::SOExport:
4484 saveExportType = saveType;
4485 break;
4486 case LDPreferences::SOSnapshot:
4487 default:
4488 saveImageType = saveType;
4489 break;
4490 }
4491 if (calcSaveFilename(buf, 1024))
4492 {
4493 SendMessage(GetParent(hSaveDialog), CDM_SETCONTROLTEXT, edt1,
4494 (LPARAM)buf);
4495 }
4496 saveTypeUpdated();
4497 }
4498 break;
4499 case CDN_INITDONE:
4500 return doSaveInitDone(notification);
4501 break;
4502 default:
4503 // debugPrintf("%d\n", notification->hdr.code);
4504 break;
4505 }
4506 return FALSE;
4507 }
4508
doSaveCommand(int controlId,int notifyCode,HWND hControlWnd)4509 BOOL ModelWindow::doSaveCommand(int controlId, int notifyCode, HWND hControlWnd)
4510 {
4511 // debugPrintf("ModelWindow::doSaveCommand: 0x%04X, 0x%04X, 0x%04x\n",
4512 // controlId, notifyCode, hControlWnd);
4513 switch (notifyCode)
4514 {
4515 case BN_CLICKED:
4516 return doSaveClick(controlId, hControlWnd);
4517 break;
4518 case EN_KILLFOCUS:
4519 return doSaveKillFocus(controlId, hControlWnd);
4520 break;
4521 case EN_CHANGE:
4522 switch (controlId)
4523 {
4524 case IDC_SAVE_DIGITS:
4525 updateSaveDigits();
4526 break;
4527 case IDC_STEP_SUFFIX:
4528 updateStepSuffix();
4529 break;
4530 }
4531 break;
4532 }
4533 return FALSE;
4534 }
4535
doPrintClick(int controlId,HWND)4536 BOOL ModelWindow::doPrintClick(int controlId, HWND /*hControlWnd*/)
4537 {
4538 switch (controlId)
4539 {
4540 case IDC_PRINT_PRINTER_DPI:
4541 usePrinterDPI = true;
4542 updatePrintDPIField();
4543 break;
4544 case IDC_PRINT_SPECIFY_DPI:
4545 usePrinterDPI = false;
4546 updatePrintDPIField();
4547 break;
4548 case IDC_PRINT_BACKGROUND:
4549 printBackground = CUIDialog::buttonGetCheck(hPrintDialog, controlId);
4550 break;
4551 default:
4552 return FALSE;
4553 }
4554 return TRUE;
4555 }
4556
updatePrintDPI(void)4557 void ModelWindow::updatePrintDPI(void)
4558 {
4559 int temp;
4560
4561 if (CUIDialog::windowGetValue(hPrintDialog, IDC_PRINT_DPI, temp) && temp > 0
4562 && temp <= 2400)
4563 {
4564 printDPI = temp;
4565 }
4566 else
4567 {
4568 CUIDialog::windowSetValue(hSaveDialog, IDC_PRINT_DPI, printDPI);
4569 MessageBeep(MB_OK);
4570 }
4571 }
4572
doPrintKillFocus(int controlId,HWND)4573 BOOL ModelWindow::doPrintKillFocus(int controlId, HWND /*hControlWnd*/)
4574 {
4575 switch (controlId)
4576 {
4577 case IDC_PRINT_DPI:
4578 updatePrintDPI();
4579 break;
4580 default:
4581 return FALSE;
4582 }
4583 return TRUE;
4584 }
doPrintCommand(int controlId,int notifyCode,HWND hControlWnd)4585 BOOL ModelWindow::doPrintCommand(int controlId, int notifyCode,
4586 HWND hControlWnd)
4587 {
4588 switch (notifyCode)
4589 {
4590 case BN_CLICKED:
4591 return doPrintClick(controlId, hControlWnd);
4592 break;
4593 case EN_KILLFOCUS:
4594 return doPrintKillFocus(controlId, hControlWnd);
4595 break;
4596 }
4597 return FALSE;
4598 }
4599
staticSaveHook(HWND hDlg,UINT uiMsg,WPARAM wParam,LPARAM lParam)4600 UINT_PTR CALLBACK ModelWindow::staticSaveHook(
4601 HWND hDlg,
4602 UINT uiMsg,
4603 WPARAM wParam,
4604 LPARAM lParam)
4605 {
4606 ModelWindow* modelWindow = (ModelWindow*)GetWindowLongPtr(hDlg, GWLP_USERDATA);
4607
4608 if (uiMsg == WM_INITDIALOG)
4609 {
4610 modelWindow = (ModelWindow*)((OPENFILENAME*)lParam)->lCustData;
4611 if (modelWindow)
4612 {
4613 modelWindow->hSaveDialog = hDlg;
4614 SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)modelWindow);
4615 // Add the context help button to the OpenFilename window.
4616 HWND hOpen = GetParent(hDlg);
4617 long styleEx = GetWindowLong(hOpen, GWL_EXSTYLE);
4618 styleEx = styleEx | WS_EX_CONTEXTHELP;
4619 SetWindowLong(hOpen, GWL_EXSTYLE, styleEx);
4620 }
4621 }
4622 else if (uiMsg == WM_HELP)
4623 {
4624 return CUIDialog::DoHtmlHelp(hDlg, (LPHELPINFO)lParam);
4625 }
4626 if (modelWindow)
4627 {
4628 return modelWindow->dialogProc(hDlg, uiMsg, wParam, lParam);
4629 }
4630 else
4631 {
4632 return 0;
4633 }
4634 }
4635
saveExtension(int type) const4636 CUCSTR ModelWindow::saveExtension(int type /*= -1*/) const
4637 {
4638 if (type == -1)
4639 {
4640 type = saveImageType;
4641 }
4642 switch (type)
4643 {
4644 case BMP_IMAGE_TYPE_INDEX:
4645 return _UC("bmp");
4646 case JPG_IMAGE_TYPE_INDEX:
4647 return _UC("jpg");
4648 case SVG_IMAGE_TYPE_INDEX:
4649 return _UC("svg");
4650 case EPS_IMAGE_TYPE_INDEX:
4651 return _UC("eps");
4652 case PDF_IMAGE_TYPE_INDEX:
4653 return _UC("pdf");
4654 default:
4655 return _UC("png");
4656 }
4657 }
4658
calcSaveFilename(UCSTR saveFilename,int len)4659 bool ModelWindow::calcSaveFilename(
4660 UCSTR saveFilename,
4661 int len)
4662 {
4663 char* filename = filenameFromPath(modelViewer->getFilename());
4664
4665 if (filename != NULL)
4666 {
4667 bool found = false;
4668 std::string baseFilename = filename;
4669 size_t dotSpot;
4670 LDLModel *mpdChild = modelViewer->getMpdChild();
4671
4672 delete[] filename;
4673 dotSpot = baseFilename.rfind('.');
4674 if (dotSpot < baseFilename.size())
4675 {
4676 baseFilename.erase(dotSpot);
4677 }
4678 if (mpdChild != NULL && mpdChild->getName() != NULL &&
4679 modelViewer->getMpdChildIndex() > 0)
4680 {
4681 std::string mpdName = mpdChild->getName();
4682
4683 dotSpot = mpdName.rfind('.');
4684 if (dotSpot < mpdName.size())
4685 {
4686 std::string mpdExt = mpdName.substr(dotSpot);
4687
4688 convertStringToLower(&mpdExt[0]);
4689 if (mpdExt == ".dat" || mpdExt == ".ldr" || mpdExt == ".mpd")
4690 {
4691 mpdName = mpdName.substr(0, dotSpot);
4692 }
4693 }
4694 baseFilename += '-';
4695 baseFilename += mpdName;
4696 }
4697 ucstring ucBaseFilename;
4698 utf8toucstring(ucBaseFilename, baseFilename.c_str());
4699 if (curSaveOp == LDPreferences::SOExport)
4700 {
4701 LDExporter *exporter = modelViewer->getExporter(
4702 (LDrawModelViewer::ExportType)saveExportType);
4703 std::string extension;
4704
4705 if (exporter)
4706 {
4707 extension = exporter->getExtension();
4708 }
4709 else
4710 {
4711 extension = "pov";
4712 }
4713 ucstring ucExtension;
4714 utf8toucstring(ucExtension, extension.c_str());
4715 sucprintf(saveFilename, len, _UC("%s.%s"), ucBaseFilename.c_str(),
4716 ucExtension.c_str());
4717 return true;
4718 }
4719 else
4720 {
4721 CUCSTR extension = saveExtension();
4722 UCCHAR format[32] = _UC("%s.%s");
4723 int max;
4724 int i;
4725
4726 if (saveSeries)
4727 {
4728 sucprintf(format, COUNT_OF(format), _UC("%%s%%0%dd.%%s"), saveDigits);
4729 max = (int)(pow(10.0, saveDigits) + 0.1);
4730 }
4731 else
4732 {
4733 max = 2;
4734 }
4735 std::string utf8SaveFilename;
4736 for (i = 1; i < max && !found; i++)
4737 {
4738 if (saveSeries)
4739 {
4740 sucprintf(saveFilename, len, format, ucBaseFilename.c_str(), i,
4741 extension);
4742 }
4743 else
4744 {
4745 sucprintf(saveFilename, len, format, ucBaseFilename.c_str(), extension);
4746 }
4747 if (saveAllSteps)
4748 {
4749 std::string suffix;
4750 ucstringtoutf8(suffix, saveStepSuffix);
4751 ucstringtoutf8(utf8SaveFilename, saveFilename);
4752 std::string temp = LDSnapshotTaker::addStepSuffix(utf8SaveFilename,
4753 suffix, 1, modelViewer->getNumSteps());
4754 ucstring ucTemp;
4755 utf8toucstring(ucTemp, temp.c_str());
4756 ucstrcpy(saveFilename, ucTemp.c_str());
4757 }
4758 utf8SaveFilename = ucstringtoutf8(saveFilename);
4759 if (!LDrawModelViewer::fileExists(utf8SaveFilename.c_str()))
4760 {
4761 found = true;
4762 }
4763 }
4764 return true;
4765 }
4766 }
4767 else
4768 {
4769 return false;
4770 }
4771 }
4772
4773 // Note: static method
defaultDir(LDPreferences::DefaultDirMode mode,const char * lastPath,const char * defaultPath)4774 std::string ModelWindow::defaultDir(
4775 LDPreferences::DefaultDirMode mode,
4776 const char *lastPath,
4777 const char *defaultPath)
4778 {
4779 switch (mode)
4780 {
4781 case LDPreferences::DDMLastDir:
4782 {
4783 return lastPath;
4784 }
4785 case LDPreferences::DDMSpecificDir:
4786 return defaultPath;
4787 }
4788 return ".";
4789 }
4790
getSaveDir(LDPreferences::SaveOp saveOp)4791 std::string ModelWindow::getSaveDir(LDPreferences::SaveOp saveOp)
4792 {
4793 LDPreferences *ldPrefs = prefs->getLDPrefs();
4794
4795 if (ldPrefs != NULL)
4796 {
4797 return ldPrefs->getDefaultSaveDir(saveOp, modelViewer->getFilename());
4798 }
4799 return ".";
4800 }
4801
getSaveDir(void)4802 std::string ModelWindow::getSaveDir(void)
4803 {
4804 return getSaveDir(curSaveOp);
4805 }
4806
fillSnapshotFileTypes(UCSTR fileTypes)4807 void ModelWindow::fillSnapshotFileTypes(UCSTR fileTypes)
4808 {
4809 memset(fileTypes, 0, 2 * sizeof(fileTypes[0]));
4810 addFileType(fileTypes, ls(_UC("PngFileType")), _UC("*.png"));
4811 addFileType(fileTypes, ls(_UC("BmpFileType")), _UC("*.bmp"));
4812 addFileType(fileTypes, ls(_UC("JpgFileType")), _UC("*.jpg"));
4813 if (TCUserDefaults::boolForKey(GL2PS_ALLOWED_KEY, false, false))
4814 {
4815 addFileType(fileTypes, ls(_UC("SvgFileType")), _UC("*.svg"));
4816 addFileType(fileTypes, ls(_UC("EpsFileType")), _UC("*.eps"));
4817 addFileType(fileTypes, ls(_UC("PdfFileType")), _UC("*.pdf"));
4818 }
4819 }
4820
fillExportFileTypes(UCSTR fileTypes)4821 void ModelWindow::fillExportFileTypes(UCSTR fileTypes)
4822 {
4823 memset(fileTypes, 0, 2 * sizeof(fileTypes[0]));
4824 for (int i = LDrawModelViewer::ETFirst; i <= LDrawModelViewer::ETLast; i++)
4825 {
4826 const LDExporter *exporter = modelViewer->getExporter(
4827 (LDrawModelViewer::ExportType)i);
4828
4829 if (exporter != NULL)
4830 {
4831 ucstring fileType = exporter->getTypeDescription();
4832 ucstring extension = _UC("*.");
4833 std::string exporterExtension = exporter->getExtension();
4834 ucstring ucExporterExtension;
4835 utf8toucstring(ucExporterExtension, exporterExtension);
4836
4837 extension += ucExporterExtension;
4838 addFileType(fileTypes, fileType.c_str(), extension.c_str());
4839 }
4840 }
4841 }
4842
getSaveFilename(UCSTR saveFilename,int len)4843 bool ModelWindow::getSaveFilename(
4844 UCSTR saveFilename,
4845 int len)
4846 {
4847 OPENFILENAME openStruct;
4848 UCCHAR fileTypes[1024];
4849 std::string initialDir = getSaveDir();
4850 int maxImageType = 3;
4851 ucstring defaultExt;
4852
4853 stopAnimation();
4854 memset(&openStruct, 0, sizeof(OPENFILENAME));
4855 if (!calcSaveFilename(saveFilename, len))
4856 {
4857 saveFilename[0] = 0;
4858 }
4859 openStruct.Flags = OFN_EXPLORER | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT |
4860 OFN_ENABLESIZING;
4861 switch (curSaveOp)
4862 {
4863 case LDPreferences::SOExport:
4864 {
4865 const LDExporter *exporter = modelViewer->getExporter();
4866 std::string extension = exporter->getExtension();
4867
4868 fillExportFileTypes(fileTypes);
4869 modelViewer->setExportType(
4870 (LDrawModelViewer::ExportType)saveExportType);
4871 saveType = saveExportType;
4872 openStruct.lpstrTitle = ls(_UC("ExportModel"));
4873 openStruct.Flags |= OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
4874 openStruct.hInstance = getLanguageModule();
4875 openStruct.lpTemplateName = MAKEINTRESOURCE(IDD_EXPORT_SAVE_OPTIONS);
4876 openStruct.lpfnHook = staticSaveHook;
4877 utf8toucstring(defaultExt, extension);
4878 }
4879 break;
4880 case LDPreferences::SOSnapshot:
4881 default:
4882 fillSnapshotFileTypes(fileTypes);
4883 if (saveImageType < 1 || saveImageType > maxImageType)
4884 {
4885 saveImageType = 1;
4886 }
4887 saveType = saveImageType;
4888 openStruct.lpstrTitle = ls(_UC("SaveSnapshot"));
4889 openStruct.Flags |= OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
4890 openStruct.hInstance = getLanguageModule();
4891 openStruct.lpTemplateName = MAKEINTRESOURCE(IDD_SAVE_OPTIONS);
4892 openStruct.lpfnHook = staticSaveHook;
4893 defaultExt = saveExtension();
4894 break;
4895 }
4896 openStruct.lStructSize = getOpenFilenameSize(false);
4897 openStruct.hwndOwner = hWindow;
4898 openStruct.lpstrFilter = fileTypes;
4899 openStruct.nFilterIndex = saveType;
4900 openStruct.lpstrFile = saveFilename;
4901 openStruct.lpstrDefExt = defaultExt.c_str();
4902 openStruct.nMaxFile = len;
4903 ucstring ucInitialDir;
4904 utf8toucstring(ucInitialDir, initialDir);
4905 openStruct.lpstrInitialDir = ucInitialDir.c_str();
4906 openStruct.lCustData = (LPARAM)this;
4907 if (GetSaveFileName(&openStruct))
4908 {
4909 int index = (int)openStruct.nFilterIndex;
4910 ucstring dir = directoryFromPath(saveFilename);
4911 LDPreferences *ldPrefs = prefs->getLDPrefs();
4912
4913 if (ldPrefs != NULL)
4914 {
4915 std::string utf8Dir;
4916 ucstringtoutf8(utf8Dir, dir);
4917 ldPrefs->setLastSaveDir(curSaveOp, utf8Dir.c_str(), true);
4918 }
4919 switch (curSaveOp)
4920 {
4921 case LDPreferences::SOExport:
4922 TCUserDefaults::setLongForKey(saveExportType,
4923 SAVE_EXPORT_TYPE_KEY, false);
4924 break;
4925 case LDPreferences::SOSnapshot:
4926 default:
4927 if (index > 0 && index <= maxImageType)
4928 {
4929 TCUserDefaults::setLongForKey(saveImageType,
4930 SAVE_IMAGE_TYPE_KEY, false);
4931 }
4932 break;
4933 }
4934 TCObject::release(saveWindowResizer);
4935 saveWindowResizer = NULL;
4936 TCUserDefaults::setBoolForKey(saveAlpha, SAVE_ALPHA_KEY, false);
4937 TCUserDefaults::setBoolForKey(autoCrop, AUTO_CROP_KEY, false);
4938 TCUserDefaults::setBoolForKey(saveAllSteps, SAVE_STEPS_KEY, false);
4939 if (saveAllSteps)
4940 {
4941 TCUserDefaults::setStringForKey(saveStepSuffix,
4942 SAVE_STEPS_SUFFIX_KEY, false);
4943 TCUserDefaults::setBoolForKey(saveStepsSameScale,
4944 SAVE_STEPS_SAME_SCALE_KEY, false);
4945 }
4946 return true;
4947 }
4948 else
4949 {
4950 loadSaveSettings();
4951 }
4952 TCObject::release(saveWindowResizer);
4953 saveWindowResizer = NULL;
4954 return false;
4955 }
4956
exportModel(void)4957 void ModelWindow::exportModel(void)
4958 {
4959 UCCHAR filename[1024];
4960
4961 curSaveOp = LDPreferences::SOExport;
4962 if (getSaveFilename(filename, COUNT_OF(filename)))
4963 {
4964 modelViewer->setExportType(
4965 (LDrawModelViewer::ExportType)saveExportType);
4966 setWaitCursor();
4967 std::string utf8Filename;
4968 ucstringtoutf8(utf8Filename, filename);
4969 modelViewer->exportCurModel(utf8Filename.c_str(),
4970 LDViewWindow::getAppVersion().c_str(),
4971 LDViewWindow::getAppAsciiCopyright().c_str());
4972 setArrowCursor();
4973 }
4974 }
4975
saveSnapshot(void)4976 bool ModelWindow::saveSnapshot(void)
4977 {
4978 UCCHAR saveFilename[1024] = _UC("");
4979 bool retValue = saveSnapshot(saveFilename);
4980
4981 forceRedraw();
4982 return retValue;
4983 }
4984
saveSnapshot(UCSTR saveFilename,bool fromCommandLine,bool notReallyCommandLine)4985 bool ModelWindow::saveSnapshot(UCSTR saveFilename, bool fromCommandLine,
4986 bool notReallyCommandLine)
4987 {
4988 bool externalFilename = saveFilename[0] != 0;
4989
4990 curSaveOp = LDPreferences::SOSnapshot;
4991 savingFromCommandLine = fromCommandLine && !notReallyCommandLine;
4992 if (saveFilename[0])
4993 {
4994 UCSTR snapshotSuffixTemp =
4995 TCUserDefaults::stringForKeyUC(SNAPSHOT_SUFFIX_KEY, NULL, false);
4996 ucstring snapshotSuffix(snapshotSuffixTemp ? snapshotSuffixTemp : _UC(""));
4997 delete[] snapshotSuffixTemp;
4998
4999 if (snapshotSuffix.empty())
5000 {
5001 UCCHAR *suffixSpot = ucstrrchr(saveFilename, _UC('.'));
5002
5003 if (suffixSpot != NULL)
5004 {
5005 snapshotSuffix = suffixSpot;
5006 }
5007 }
5008 if (stringHasCaseInsensitiveSuffix(snapshotSuffix.c_str(), _UC(".png")))
5009 {
5010 saveImageType = PNG_IMAGE_TYPE_INDEX;
5011 }
5012 else if (stringHasCaseInsensitiveSuffix(snapshotSuffix.c_str(),
5013 _UC(".bmp")))
5014 {
5015 saveImageType = BMP_IMAGE_TYPE_INDEX;
5016 }
5017 else if (stringHasCaseInsensitiveSuffix(snapshotSuffix.c_str(),
5018 _UC(".jpg")))
5019 {
5020 saveImageType = JPG_IMAGE_TYPE_INDEX;
5021 }
5022 else
5023 {
5024 if (fromCommandLine)
5025 {
5026 consolePrintf(ls(_UC("ConsoleSnapshotFailed")));
5027 }
5028 return false;
5029 }
5030 }
5031 if (saveFilename[0] || getSaveFilename(saveFilename, 1024))
5032 {
5033 if (!fromCommandLine)
5034 {
5035 TCUserDefaults::setLongForKey(ignorePBuffer ? 1 : 0,
5036 IGNORE_PBUFFER_KEY, false);
5037 TCUserDefaults::setLongForKey(ignoreFBO ? 1 : 0,
5038 IGNORE_FRAMEBUFFER_OBJECT_KEY, false);
5039 TCUserDefaults::setLongForKey(ignorePixelFormat ? 1 : 0,
5040 IGNORE_PIXEL_FORMAT_KEY, false);
5041 if (saveSeries)
5042 {
5043 TCUserDefaults::setLongForKey(1, SAVE_SERIES_KEY, false);
5044 TCUserDefaults::setLongForKey(saveDigits, SAVE_DIGITS_KEY,
5045 false);
5046 }
5047 else
5048 {
5049 TCUserDefaults::setLongForKey(0, SAVE_SERIES_KEY, false);
5050 }
5051 }
5052 if (saveActualSize)
5053 {
5054 if (!fromCommandLine)
5055 {
5056 TCUserDefaults::setLongForKey(1, SAVE_ACTUAL_SIZE_KEY, false);
5057 }
5058 return saveImage(saveFilename, width, height, externalFilename &&
5059 saveZoomToFit);
5060 }
5061 else
5062 {
5063 if (!fromCommandLine)
5064 {
5065 TCUserDefaults::setLongForKey(0, SAVE_ACTUAL_SIZE_KEY, false);
5066 TCUserDefaults::setLongForKey(saveWidth, SAVE_WIDTH_KEY, false);
5067 TCUserDefaults::setLongForKey(saveHeight, SAVE_HEIGHT_KEY,
5068 false);
5069 TCUserDefaults::setLongForKey(saveZoomToFit,
5070 SAVE_ZOOM_TO_FIT_KEY, false);
5071 }
5072 return saveImage(saveFilename, saveWidth, saveHeight,
5073 saveZoomToFit);
5074 }
5075 }
5076 else
5077 {
5078 return false;
5079 }
5080 }
5081
setupPFD(void)5082 BOOL ModelWindow::setupPFD(void)
5083 {
5084 currentAntialiasType = TCUserDefaults::longForKey(FSAA_MODE_KEY);
5085
5086 if (currentAntialiasType && LDVExtensionsSetup::haveMultisampleExtension())
5087 {
5088 debugOut("ModelWindow::setupPFD 1\n");
5089 GLint intValues[] = {
5090 WGL_SAMPLE_BUFFERS_EXT, GL_TRUE,
5091 WGL_SAMPLES_EXT, 1,
5092 WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
5093 WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
5094 WGL_ALPHA_BITS_ARB, 4,
5095 WGL_STENCIL_BITS_ARB, 2,
5096 0, 0
5097 };
5098 int numIntValues = COUNT_OF(intValues);
5099
5100 if (currentAntialiasType)
5101 {
5102 intValues[3] = prefs->getFSAAFactor();
5103 }
5104 else
5105 {
5106 // Remove the first four items in the array.
5107 memmove(intValues, intValues + 4, sizeof(intValues) -
5108 sizeof(intValues[0]) * 4);
5109 numIntValues -= 4;
5110 }
5111 pfIndex = LDVExtensionsSetup::choosePixelFormat(hdc, intValues);
5112 debugOut("ModelWindow::setupPFD 2\n");
5113 if (pfIndex < 0)
5114 {
5115 // Try with dest alpha but no stencil by clearing the last two used
5116 // elements in the array (there are two terminating zeros after
5117 // them).
5118 intValues[numIntValues - 4] = 0;
5119 intValues[numIntValues - 3] = 0;
5120 pfIndex = LDVExtensionsSetup::choosePixelFormat(hdc, intValues);
5121 }
5122 debugOut("ModelWindow::setupPFD 3\n");
5123 if (pfIndex < 0)
5124 {
5125 // Try with stencil but no dest alpha by changing the last two used
5126 // elements in the array back to their original values that specify
5127 // the stencil request.
5128 intValues[numIntValues - 6] = WGL_STENCIL_BITS_ARB;
5129 intValues[numIntValues - 5] = 1;
5130 pfIndex = LDVExtensionsSetup::choosePixelFormat(hdc, intValues);
5131 }
5132 debugOut("ModelWindow::setupPFD 4\n");
5133 if (pfIndex < 0)
5134 {
5135 // Try with no stencil OR dest alpha by clearing two more elements
5136 // at the end of the array.
5137 intValues[numIntValues - 6] = 0;
5138 intValues[numIntValues - 5] = 0;
5139 pfIndex = LDVExtensionsSetup::choosePixelFormat(hdc, intValues);
5140 }
5141 debugOut("ModelWindow::setupPFD 5\n");
5142 if (pfIndex >= 0)
5143 {
5144 debugOut("ModelWindow::setupPFD 6\n");
5145 if (setPixelFormat(pfIndex))
5146 {
5147 return TRUE;
5148 }
5149 }
5150 debugOut("ModelWindow::setupPFD 7\n");
5151 }
5152 currentAntialiasType = 0;
5153 return CUIOGLWindow::setupPFD();
5154 }
5155
setKeepRightSideUp(bool value,bool saveSetting)5156 void ModelWindow::setKeepRightSideUp(bool value, bool saveSetting /*= true*/)
5157 {
5158 if (modelViewer != NULL)
5159 {
5160 modelViewer->setKeepRightSideUp(value);
5161 }
5162 if (saveSetting)
5163 {
5164 TCUserDefaults::setBoolForKey(value, KEEP_RIGHT_SIDE_UP_KEY, false);
5165 }
5166 }
5167
setViewMode(LDInputHandler::ViewMode mode,bool examineLatLong,bool saveSetting)5168 void ModelWindow::setViewMode(
5169 LDInputHandler::ViewMode mode,
5170 bool examineLatLong,
5171 bool saveSetting)
5172 {
5173 inputHandler->setViewMode(mode);
5174 viewMode = mode;
5175 if (saveSetting)
5176 {
5177 TCUserDefaults::setLongForKey(viewMode, VIEW_MODE_KEY, false);
5178 }
5179 if (modelViewer)
5180 {
5181 if (viewMode == LDInputHandler::VMExamine)
5182 {
5183 LDrawModelViewer::ExamineMode examineMode;
5184
5185 modelViewer->setConstrainZoom(true);
5186 if (examineLatLong)
5187 {
5188 examineMode = LDrawModelViewer::EMLatLong;
5189 }
5190 else
5191 {
5192 examineMode = LDrawModelViewer::EMFree;
5193 }
5194 if (saveSetting)
5195 {
5196 TCUserDefaults::setLongForKey(examineMode, EXAMINE_MODE_KEY,
5197 false);
5198 }
5199 modelViewer->setExamineMode(examineMode);
5200 }
5201 else
5202 {
5203 modelViewer->setConstrainZoom(false);
5204 }
5205 }
5206 }
5207
processKeyDown(int keyCode,LPARAM)5208 LRESULT ModelWindow::processKeyDown(int keyCode, LPARAM /*keyData*/)
5209 {
5210 if (keyCode == VK_ESCAPE)
5211 {
5212 cancelLoad = true;
5213 }
5214 if (inputHandler->keyDown(getCurrentKeyModifiers(),
5215 convertKeyCode(keyCode)))
5216 {
5217 return 0;
5218 }
5219 return 1;
5220 //if (modelViewer && viewMode == LDVViewFlythrough)
5221 //{
5222 // TCVector cameraMotion = modelViewer->getCameraMotion();
5223 // TCFloat motionAmount = 1.0f;
5224 // TCFloat rotationAmount = 0.01f;
5225 // TCFloat strafeAmount = 1.0f;
5226 // int i;
5227
5228 // if (modelViewer)
5229 // {
5230 // TCFloat fov = modelViewer->getFov();
5231
5232 // motionAmount = modelViewer->getDefaultDistance() / 400.0f;
5233 // rotationAmount *= (TCFloat)tan(deg2rad(fov));
5234 // strafeAmount *= (TCFloat)sqrt(fov / 45.0f);
5235 // }
5236 // if (GetKeyState(VK_SHIFT) & 0x8000)
5237 // {
5238 // motionAmount *= 2.0f;
5239 // strafeAmount *= 2.0f;
5240 // }
5241 // switch (keyCode)
5242 // {
5243 // case 'W':
5244 // cameraMotion[2] = -motionAmount;
5245 // break;
5246 // case 'S':
5247 // cameraMotion[2] = motionAmount;
5248 // break;
5249 // case 'A':
5250 // cameraMotion[0] = -strafeAmount;
5251 // break;
5252 // case 'D':
5253 // cameraMotion[0] = strafeAmount;
5254 // break;
5255 // case 'R':
5256 // cameraMotion[1] = strafeAmount;
5257 // break;
5258 // case 'F':
5259 // cameraMotion[1] = -strafeAmount;
5260 // break;
5261 // case 'E':
5262 // modelViewer->setCameraZRotate(0.01f);
5263 // break;
5264 // case 'Q':
5265 // modelViewer->setCameraZRotate(-0.01f);
5266 // break;
5267 // case VK_UP:
5268 // modelViewer->setCameraYRotate(rotationAmount);
5269 // break;
5270 // case VK_DOWN:
5271 // modelViewer->setCameraYRotate(-rotationAmount);
5272 // break;
5273 // case VK_LEFT:
5274 // modelViewer->setCameraXRotate(-rotationAmount);
5275 // break;
5276 // case VK_RIGHT:
5277 // modelViewer->setCameraXRotate(rotationAmount);
5278 // break;
5279 // case VK_SHIFT:
5280 // for (i = 0; i < 3; i++)
5281 // {
5282 // if (cameraMotion[i] > 0.0f)
5283 // {
5284 // cameraMotion[i] = 2.0;
5285 // }
5286 // else if (cameraMotion[i] < 0.0f)
5287 // {
5288 // cameraMotion[i] = -2.0;
5289 // }
5290 // }
5291 // break;
5292 // default:
5293 // return 1;
5294 // break;
5295 // }
5296 // modelViewer->setCameraMotion(cameraMotion);
5297 // forceRedraw(2);
5298 // return 0;
5299 //}
5300 //return 1;
5301 }
5302
processKeyUp(int keyCode,LPARAM)5303 LRESULT ModelWindow::processKeyUp(int keyCode, LPARAM /*keyData*/)
5304 {
5305 if (inputHandler->keyUp(getCurrentKeyModifiers(),
5306 convertKeyCode(keyCode)))
5307 {
5308 return 0;
5309 }
5310 return 1;
5311 //if (modelViewer && viewMode == LDVViewFlythrough)
5312 //{
5313 // TCVector cameraMotion = modelViewer->getCameraMotion();
5314 // int i;
5315
5316 // switch (keyCode)
5317 // {
5318 // case 'W':
5319 // cameraMotion[2] = 0.0f;
5320 // break;
5321 // case 'S':
5322 // cameraMotion[2] = 0.0f;
5323 // break;
5324 // case 'A':
5325 // cameraMotion[0] = 0.0f;
5326 // break;
5327 // case 'D':
5328 // cameraMotion[0] = 0.0f;
5329 // break;
5330 // case 'R':
5331 // cameraMotion[1] = 0.0f;
5332 // break;
5333 // case 'F':
5334 // cameraMotion[1] = 0.0f;
5335 // break;
5336 // case 'E':
5337 // modelViewer->setCameraZRotate(0.0f);
5338 // break;
5339 // case 'Q':
5340 // modelViewer->setCameraZRotate(0.0f);
5341 // break;
5342 // case VK_UP:
5343 // modelViewer->setCameraYRotate(0.0f);
5344 // break;
5345 // case VK_DOWN:
5346 // modelViewer->setCameraYRotate(0.0f);
5347 // break;
5348 // case VK_LEFT:
5349 // modelViewer->setCameraXRotate(0.0f);
5350 // break;
5351 // case VK_RIGHT:
5352 // modelViewer->setCameraXRotate(0.0f);
5353 // break;
5354 // case VK_SHIFT:
5355 // for (i = 0; i < 3; i++)
5356 // {
5357 // if (cameraMotion[i] > 0.0f)
5358 // {
5359 // cameraMotion[i] = 1.0;
5360 // }
5361 // else if (cameraMotion[i] < 0.0f)
5362 // {
5363 // cameraMotion[i] = -1.0;
5364 // }
5365 // }
5366 // break;
5367 // default:
5368 // return 1;
5369 // break;
5370 // }
5371 // modelViewer->setCameraMotion(cameraMotion);
5372 // forceRedraw(2);
5373 // return 0;
5374 //}
5375 //return 1;
5376 }
5377
doMove(int newX,int newY)5378 LRESULT ModelWindow::doMove(int newX, int newY)
5379 {
5380 return CUIOGLWindow::doMove(newX, newY);
5381 }
5382
makeCurrent(void)5383 void ModelWindow::makeCurrent(void)
5384 {
5385 if (initializedGL)
5386 {
5387 if (hCurrentDC && hCurrentGLRC)
5388 {
5389 wglMakeCurrent(hCurrentDC, hCurrentGLRC);
5390 }
5391 else
5392 {
5393 CUIOGLWindow::makeCurrent();
5394 }
5395 }
5396 }
5397
performHotKey(int hotKeyIndex)5398 bool ModelWindow::performHotKey(int hotKeyIndex)
5399 {
5400 if (prefs)
5401 {
5402 return prefs->performHotKey(hotKeyIndex);
5403 }
5404 else
5405 {
5406 return false;
5407 }
5408 }
5409
initFail(char *)5410 void ModelWindow::initFail(char * /*reason*/)
5411 {
5412 MessageBox(hWindow, ls(_UC("OpenGlInitFailed")),
5413 ls(_UC("FatalError")), MB_OK | MB_ICONERROR);
5414 PostQuitMessage(-1);
5415 }
5416
drawLight(GLenum,TCFloat,TCFloat,TCFloat)5417 void ModelWindow::drawLight(GLenum /*light*/, TCFloat /*x*/, TCFloat /*y*/,
5418 TCFloat /*z*/)
5419 {
5420 // Don't call super.
5421 }
5422
drawLights(void)5423 void ModelWindow::drawLights(void)
5424 {
5425 // Don't call super.
5426 }
5427
orthoView(void)5428 void ModelWindow::orthoView(void)
5429 {
5430 // Don't call super.
5431 }
5432
setupLight(GLenum)5433 void ModelWindow::setupLight(GLenum /*light*/)
5434 {
5435 // Don't call super.
5436 }
5437
setSaveZoomToFit(bool value,bool commit)5438 void ModelWindow::setSaveZoomToFit(bool value, bool commit /*= false*/)
5439 {
5440 saveZoomToFit = value;
5441 if (commit)
5442 {
5443 TCUserDefaults::setLongForKey(value, SAVE_ZOOM_TO_FIT_KEY, false);
5444 }
5445 }
5446
boundingBoxToggled(void)5447 void ModelWindow::boundingBoxToggled(void)
5448 {
5449 ((LDViewWindow*)parentWindow)->boundingBoxToggled();
5450 }
5451