1 #include "EgOSUtils.h"
2
3 #include "CEgFileSpec.h"
4 #include "CEgErr.h"
5 #include "UtilStr.h"
6
7 #include <stdlib.h>
8 #include <time.h>
9 #include <math.h>
10
11 #ifdef EG_MAC
12 #include <Resources.h>
13 #include <Sound.h>
14 #include <Fonts.h>
15 #endif
16
17
18 #ifdef EG_WIN
19 #include <windows.h>
20 #endif
21
22 #ifdef UNIX_X
23 #include <stdio.h>
24 #include <sys/stat.h>
25 #include <sys/time.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <dirent.h>
29 #endif
30
31
32 int EgOSUtils::sXdpi = 72;
33 int EgOSUtils::sYdpi = 72;
34 long EgOSUtils::sLastCursor = -1;
35 long EgOSUtils::sLastCursorChange = -1;
36 CEgFileSpec EgOSUtils::sAppSpec;
37 char EgOSUtils::sInitialDir[ INITAL_DIR_STRLEN + 2 ];
38 XStrList EgOSUtils::sFontList( cDuplicatesAllowed );
39
40
41
42
ShowFileErr(const UtilStr * inName,char * inErrMsg,bool wasReading)43 void EgOSUtils::ShowFileErr( const UtilStr* inName, char* inErrMsg, bool wasReading ) {
44 UtilStr s;
45
46 if ( wasReading )
47 s.Assign( "Error reading : " );
48 else
49 s.Assign( "Error writing : " );
50 s.Append( inErrMsg );
51
52 #ifdef EG_MAC
53 s.Insert( 14, "��" );
54 #else
55 s.Insert( 14, "\"\"" );
56 #endif
57
58 s.Insert( 15, inName );
59 ShowMsg( s );
60 }
61
62
ShowFileErr(const UtilStr * inName,CEgErr & inErr,bool wasReading)63 void EgOSUtils::ShowFileErr( const UtilStr* inName, CEgErr& inErr, bool wasReading ) {
64 UtilStr msg;
65
66 inErr.GetErrStr( msg );
67 ShowFileErr( inName, msg.getCStr(), wasReading );
68 }
69
70
71
ShowFileErr(const CEgFileSpec & inFileSpec,CEgErr & inErr,bool wasReading)72 void EgOSUtils::ShowFileErr( const CEgFileSpec& inFileSpec, CEgErr& inErr, bool wasReading ) {
73 UtilStr msg, fileName;
74
75 inFileSpec.GetFileName( fileName );
76 inErr.GetErrStr( msg );
77 ShowFileErr( &fileName, msg.getCStr(), wasReading );
78 }
79
80
81
82
83
Initialize(void * inModuleInstance)84 void EgOSUtils::Initialize( void* inModuleInstance ) {
85
86 srand( clock() );
87
88 #if EG_MAC
89
90 #pragma unused( inModuleInstance )
91 OSStatus status;
92 FCBPBRec fcbPBRec;
93 Str255 appName;
94 FSSpec spec;
95
96 fcbPBRec.ioCompletion = nil;
97 fcbPBRec.ioFCBIndx = 0;
98 fcbPBRec.ioVRefNum = 0;
99 fcbPBRec.ioRefNum = ::CurResFile();
100 fcbPBRec.ioNamePtr = appName;
101
102 status = ::PBGetFCBInfoSync(&fcbPBRec);
103
104 ::FSMakeFSSpec(fcbPBRec.ioFCBVRefNum, fcbPBRec.ioFCBParID, appName, &spec );
105 sAppSpec.Assign( &spec, 0 );
106 #endif
107
108 #ifdef EG_WIN
109 HDC hDC = ::CreateDC( "DISPLAY", 0, 0, 0 );
110 if ( hDC ) {
111 sXdpi = ::GetDeviceCaps( hDC, LOGPIXELSX );
112 sYdpi = ::GetDeviceCaps( hDC, LOGPIXELSY );
113 ::DeleteDC( hDC );
114 }
115
116 char path[ 700 ];
117 long len = ::GetModuleFileName( (HINSTANCE) inModuleInstance, path, 699 );
118 if ( len ) {
119 UtilStr fdir( path, len );
120 fdir.Keep( fdir.FindLastInstanceOf( '\\' ) );
121 sAppSpec.Assign( fdir.getCStr(), 0 );
122 }
123
124
125 // Init timer accuracy...
126 ///::timeBeginPeriod( 1 );
127
128 // Remember the initial dir
129 ::GetCurrentDirectory( INITAL_DIR_STRLEN, sInitialDir );
130 #endif
131
132 // For mac, sXspi and sYdpi are already correct by default
133 #ifdef UNIX_X
134
135 unsigned char pal[256*3];
136 for (int pp = 0; pp < 256 ; pp++) {
137 pal[pp*3] = pp;
138 pal[pp*3+1] = pp;
139 pal[pp*3+2] = pp;
140 }
141
142 sXdpi = sYdpi = 75;
143 #endif
144 }
145
146
147
148
149
Shutdown()150 void EgOSUtils::Shutdown() {
151 #ifdef UNIX_X
152 // xpce_CloseGraph();
153 #endif
154 #if EG_WIN
155
156 // Restore the initial dir
157 ::SetCurrentDirectory( sInitialDir );
158
159 // Init timer accuracy...
160 //::timeEndPeriod( 1 );
161
162 #endif
163
164 }
165
166
167
168
169
170
171
AskSaveAs(const char * inPrompt,const char * inDefaultName,CEgFileSpec & outSpec,long inFileType)172 bool EgOSUtils::AskSaveAs( const char* inPrompt, const char* inDefaultName, CEgFileSpec& outSpec, long inFileType ) {
173 UtilStr inName( inDefaultName );
174
175 return AskSaveAs( inPrompt, inName, outSpec, inFileType );
176 }
177
178
179 #ifdef EG_ZINC
180 #include <z_fildlg.hpp>
181 #endif
182
183
184
185
AskSaveAs(const char * inPrompt,const UtilStr & inDefaultName,CEgFileSpec & outSpec,long inFileType)186 bool EgOSUtils::AskSaveAs( const char* inPrompt, const UtilStr& inDefaultName, CEgFileSpec& outSpec, long inFileType ) {
187 int doSave = false;
188 UtilStr prompt( inPrompt );
189
190 #ifdef EG_MAC
191 StandardFileReply reply;
192
193 //::UDesktop::Deactivate();
194 ::StandardPutFile( prompt.getPasStr(), inDefaultName.getPasStr(), &reply );
195 //::UDesktop::Activate();
196
197 if (reply.sfGood) {
198 outSpec.Assign( &reply.sfFile, inFileType );
199 doSave = true;
200 }
201 #endif
202
203 #if EG_WIN && EG_ZINC
204 UtilStr defName( inDefaultName );
205
206 ZafFileDialog fileDialog( 20, 5, 60, 14 );
207
208 if ( inFileType )
209 CEgFileSpec::TypeToExt( defName, inFileType );
210
211 fileDialog.SetFile( defName.getCStr() );
212
213 if ( fileDialog.GetFile( ZAF_FILE_DIALOG_SAVEAS ) == S_DLG_OK ) {
214 doSave = true;
215 outSpec.Assign( fileDialog.File(), inFileType );
216 }
217 /*
218 unsigned char c;
219 UtilStr winFilter;
220 OPENFILENAME paramBlk;
221 char pathName[ 601 ];
222
223 inDefaultName.copyTo( pathName, 600 );
224
225 // See page 519 of Vol 5 in Win32 Ref for descrip of the lpstrFilter scheme.
226 winFilter.Append( "/0*" );
227
228 // Append the ext mask...
229 for ( int d = 0; d <= 24; d += 8 ) { // Go thru each byte in ID num
230 c = ((inFileType << d) >> 24 );
231 winFilter.Append( (char) c );
232 }
233 winFilter.Append( (char) 0 ); // Windows exptects an extra NUL to end the filter
234
235 visual_mem_set( ¶mBlk, 0, sizeof(OPENFILENAME) );
236 paramBlk.lStructSize = sizeof(OPENFILENAME);
237 paramBlk.lpstrFilter = winFilter.getCStr();
238 paramBlk.lpstrFile = pathName;
239 paramBlk.nMaxFile = 600;
240 paramBlk.lpstrTitle = prompt.getCStr();
241 if ( ::GetSaveFileName( ¶mBlk ) ) {
242 outSpec.Assign( pathName );
243 doSave = true;
244 }*/
245 #endif
246
247 return doSave;
248 }
249
250
251
252
AskOpen(const char * inPrompt,CEgFileSpec & outSpec,long inTypeMask)253 bool EgOSUtils::AskOpen( const char* inPrompt, CEgFileSpec& outSpec, long inTypeMask ) {
254 bool didOpen = false;
255 UtilStr prompt( inPrompt );
256
257 #ifdef EG_MAC
258 StandardFileReply macFileReply;
259 SFTypeList typeList;
260
261 // clear the rec
262 for ( int i = 0; i < sizeof( macFileReply ); i++ )
263 ( (char*) &macFileReply )[ i ] = 0;
264
265 //UDesktop::Deactivate();
266 typeList[0] = inTypeMask;
267 ::StandardGetFile( 0, inTypeMask ? 1 : 0, typeList, &macFileReply );
268 //UDesktop::Activate();
269
270 if ( macFileReply.sfGood ) {
271 outSpec.Assign( &macFileReply.sfFile );
272 didOpen = true;
273 }
274 #endif
275
276 #if EG_WIN && EG_ZINC
277 ZafFileDialog fileDialog( 5, 5, 60, 14 );
278 UtilStr str( "*" );
279
280 if ( inTypeMask ) {
281 CEgFileSpec::TypeToExt( str, inTypeMask );
282 fileDialog.SetFilter( str.getCStr() );
283 }
284
285 if ( fileDialog.GetFile( ZAF_FILE_DIALOG_OPEN ) == S_DLG_OK ) {
286 char path[ 401 ];
287 didOpen = true;
288
289 fileDialog.FullPath( path, 400 );
290 outSpec.Assign( path );
291 }
292 /*
293 unsigned char c;
294 UtilStr winFilter;
295 OPENFILENAME paramBlk;
296 char pathName[ 601 ];
297
298 // See page 519 of Vol 5 in Win32 Ref for descrip of the lpstrFilter scheme.
299 winFilter.Append( "/0*" );
300
301 // Append the ext mask...
302 for ( int d = 0; d <= 24; d += 8 ) { // Go thru each byte in ID num
303 c = ((inTypeMask << d) >> 24 );
304 winFilter.Append( (char) c );
305 }
306 winFilter.Append( (char) 0 ); // Windows exptects an extra NUL to end the filter
307
308 visual_mem_set( ¶mBlk, 0, sizeof(OPENFILENAME) );
309 paramBlk.lStructSize = sizeof(OPENFILENAME);
310 paramBlk.lpstrFilter = winFilter.getCStr();
311 paramBlk.lpstrFile = pathName;
312 paramBlk.nMaxFile = 600;
313 paramBlk.lpstrTitle = prompt.getCStr();
314 if ( ::GetOpenFileName( ¶mBlk ) ) {
315 outSpec.Assign( pathName );
316 didOpen = true;
317 }*/
318 #endif
319
320 return didOpen;
321 }
322
323
324
325
326
327
328
329
AreYouSure(const UtilStr & inMsg)330 bool EgOSUtils::AreYouSure( const UtilStr& inMsg ) {
331 int ans;
332
333 #ifdef EG_MAC
334 ::ParamText( inMsg.getPasStr(), "\p", "\p", "\p");
335 //UDesktop::Deactivate();
336 ans = ::CautionAlert( 2000, 0 );
337 //UDesktop::Activate();
338
339 return ans == 1; //answer_Save;
340 #endif
341
342 #ifdef EG_WIN
343 ans = ::MessageBox( 0, inMsg.getCStr(), "Examgen Message", MB_ICONEXCLAMATION | MB_YESNO | MB_SETFOREGROUND | MB_TASKMODAL );
344 return ans == IDYES;
345 #endif
346 }
347
348
AreYouSure(const char * inMsg)349 bool EgOSUtils::AreYouSure( const char* inMsg ) {
350 UtilStr msg( inMsg );
351
352 return AreYouSure( msg );
353 }
354
355
356
AskSaveChanges(const char * inName)357 int EgOSUtils::AskSaveChanges( const char* inName ) {
358 UtilStr name( inName );
359 return AskSaveChanges( name );
360 }
361
362
363
AskSaveChanges(const UtilStr & inName)364 int EgOSUtils::AskSaveChanges( const UtilStr& inName ) {
365 int ans;
366
367 #ifdef EG_MAC
368 ::ParamText( inName.getPasStr(), "\p", "\p", "\p" );
369 //UDesktop::Deactivate();
370 ans = ::CautionAlert( 2001, 0 );
371 //UDesktop::Activate();
372
373 return 2 - ans;
374 #endif
375
376 #ifdef EG_WIN
377 UtilStr msg( "Save changes to \"" );
378 msg.Append( inName );
379 msg.Append( "\" before closing?" );
380 ans = ::MessageBox( 0, msg.getCStr(), "Examgen Message", MB_ICONEXCLAMATION | MB_YESNOCANCEL | MB_SETFOREGROUND | MB_TASKMODAL );
381 if ( ans == IDYES )
382 return 1;
383 else if ( ans == IDNO )
384 return -1;
385 else
386 return 0;
387 #endif
388 }
389
390
SpinCursor()391 void EgOSUtils::SpinCursor() {
392 long time = clock();
393
394 if ( sLastCursorChange == -1 )
395 sLastCursorChange = time;
396 else if ( time - CLOCKS_PER_SEC / 3 > sLastCursorChange ) { // Every 1/3 second...
397 #ifdef EG_MAC
398 Handle cursHndl;
399 sLastCursor = ( sLastCursor + 1 ) % 8; // 8 Cursors
400 cursHndl = ::GetResource( 'CURS', 6500 + sLastCursor ); // 6500 = Base ID
401 sLastCursorChange = time;
402 if ( cursHndl )
403 ::SetCursor( (Cursor*) *cursHndl );
404 #endif
405
406 #ifdef EG_WIN
407 SetCursor( ::LoadCursor( 0, IDC_WAIT ) );
408 sLastCursor = 1;
409 #endif
410 }
411 }
412
413
414
415
416
417
418
419
ShowCursor()420 void EgOSUtils::ShowCursor() {
421
422 #ifdef EG_MAC
423 ::ShowCursor();
424 ::InitCursor();
425 #endif
426
427 #ifdef EG_WIN
428 ::SetCursor( ::LoadCursor( 0, IDC_ARROW ) );
429 while ( ::ShowCursor( true ) < 0 ) { }
430 #endif
431
432 sLastCursor = -1;
433 sLastCursorChange = -1;
434 }
435
436
HideCursor()437 void EgOSUtils::HideCursor() {
438
439 #ifdef EG_MAC
440 ::HideCursor();
441 #endif
442
443 #ifdef EG_WIN
444 while ( ::ShowCursor( false ) >= 0 ) { }
445 #endif
446
447 sLastCursor = -1;
448 sLastCursorChange = -1;
449 }
450
451
452
GetNextFile(const CEgFileSpec & folderSpec,CEgFileSpec & outSpec,bool inStartOver,bool inFolders)453 bool EgOSUtils::GetNextFile( const CEgFileSpec& folderSpec, CEgFileSpec& outSpec, bool inStartOver, bool inFolders ) {
454 bool ok;
455
456 #ifdef EG_MAC
457 static int sLastIndex;
458 OSErr err;
459 HFileInfo pb;
460 FSSpec spec;
461 long parID;
462 Str255 str;
463
464 parID = ( (FSSpec*) folderSpec.OSSpec() ) -> parID;
465 pb.ioVRefNum = ( (FSSpec*) folderSpec.OSSpec() ) -> vRefNum;
466 pb.ioNamePtr = str;
467
468 if ( inStartOver )
469 pb.ioFDirIndex = 1;
470 else
471 pb.ioFDirIndex = sLastIndex;
472
473 ok = false;
474 do {
475 pb.ioDirID = parID;
476 err = PBGetCatInfoSync( (CInfoPBRec*) &pb );
477
478 if ( err == noErr && ( (pb.ioFlFndrInfo.fdFlags & fInvisible) == 0) /*&& pb.ioFlFndrInfo.fdCreator == cEGCreator*/ ) {
479 ok = ( (pb.ioFlAttrib & ioDirMask ) == 0 );
480 if ( inFolders )
481 ok = ! ok;
482 if ( ok ) {
483 if ( inFolders )
484 pb.ioFlParID = pb.ioDirID;
485 ::FSMakeFSSpec( pb.ioVRefNum, pb.ioFlParID, str, &spec );
486 outSpec.Assign( &spec, pb.ioFlFndrInfo.fdType );
487 }
488 }
489
490 pb.ioFDirIndex++;
491 sLastIndex = pb.ioFDirIndex;
492 } while ( err == noErr && ! ok );
493
494 #endif
495
496
497
498 #ifdef EG_WIN
499 WIN32_FIND_DATA fileData;
500 static HANDLE hSearch;
501 UtilStr name;
502 bool isDir, tryAgain;
503
504 do {
505 if ( inStartOver ) {
506 inStartOver = false;
507 if ( name.getChar( name.length() ) == '\\' )
508 name.Trunc( 1 );
509 ok = SetCurrentDirectory( name.getCStr() );
510 if ( ok ) {
511 hSearch = ::FindFirstFile( "*.*", &fileData );
512 ok = hSearch != INVALID_HANDLE_VALUE;
513 } }
514 else
515 ok = ::FindNextFile( hSearch, &fileData );
516 if ( ok ) {
517 name.Assign( fileData.cFileName );
518 isDir = ::GetFileAttributes( fileData.cFileName ) & FILE_ATTRIBUTE_DIRECTORY;
519 if ( isDir == inFolders ) {
520 tryAgain = name.compareTo( "." ) == 0 || name.compareTo( ".." ) == 0;
521 outSpec.Assign( folderSpec );
522 if ( isDir )
523 name.Append( "\\" );
524 outSpec.Rename( name ); }
525 else
526 tryAgain = true;
527 }
528 } while ( ok && tryAgain );
529
530 #endif
531
532 #ifdef UNIX_X
533
534 UtilStr name;
535 bool isDir, tryAgain;
536 UtilStr fullname;
537
538 static DIR *d = 0;
539 struct dirent *de;
540
541 ok = true;
542 do {
543 if ( inStartOver ) {
544 if (d != 0) {
545 closedir(d);
546 d = 0;
547 }
548 inStartOver = false;
549 name.Assign( (char*) folderSpec.OSSpec() );
550 if ( name.getChar( name.length() ) == '/' )
551 name.Trunc( 1 );
552 d = opendir(name.getCStr());
553 if (d == 0) return 0;
554 }
555 de = readdir(d);
556 if (de == 0) return 0;
557 name.Assign(de->d_name);
558 struct stat statdata;
559 fullname.Assign( (char*) folderSpec.OSSpec() );
560 if ( fullname.getChar( name.length() ) != '/' )
561 fullname.Append( '/' );
562 fullname.Append(de->d_name);
563 if (stat(fullname.getCStr(), &statdata) != 0)
564 return 0;
565 if (S_ISDIR(statdata.st_mode))
566 isDir = 1;
567 else
568 isDir = 0;
569
570 if ( isDir == inFolders ) {
571
572 tryAgain = name.compareTo( "." ) == 0 || name.compareTo( ".." ) == 0;
573 outSpec.Assign( folderSpec );
574 if ( isDir )
575 name.Append( "\\" );
576 outSpec.Rename( name ); }
577 else
578 tryAgain = true;
579 } while ( ok && tryAgain );
580
581 #endif
582
583 return ok;
584 }
585
586
587
588
589
590
591
592
593
594
Beep()595 void EgOSUtils::Beep() {
596
597 #ifdef EG_MAC
598 ::SysBeep( 200 );
599 #endif
600
601 #ifdef EG_WIN
602 MessageBeep(0);
603 #endif
604 }
605
606
607 #ifdef UNIX_X
608
609 #include <sys/times.h>
610 #endif
CurTimeMS()611 long EgOSUtils::CurTimeMS() {
612 #if EG_WIN
613 return ::timeGetTime();
614 #elif EG_MAC
615 return ::TickCount() * 16;
616 #else
617 struct timeval tv;
618 struct timezone tz;
619 tz.tz_minuteswest = 0;
620 tz.tz_dsttime = 0;
621 gettimeofday(&tv, &tz);
622 return ((tv.tv_sec * 1000) & 0x7fffffff) + tv.tv_usec / 1000;
623 #endif
624 }
625
626
GetMouse(Point & outPt)627 void EgOSUtils::GetMouse( Point& outPt ) {
628
629 #if EG_MAC
630 ::GetMouse( &outPt );
631 ::LocalToGlobal( &outPt );
632 #endif
633
634 #if EG_WIN
635 POINT p;
636 ::GetCursorPos( &p );
637 outPt.h = p.x;
638 outPt.v = p.y;
639 #endif
640
641 #ifdef UNIX_X
642 int x, y;
643
644 // xpce_QueryMouse(&x, &y); // FIXME replace this
645 x = 0;
646 y = 0;
647 outPt.h = x;
648 outPt.v = y;
649 #endif
650 }
651
652
ShowMsg(const UtilStr & inMsg)653 void EgOSUtils::ShowMsg( const UtilStr& inMsg ) {
654
655 #ifdef EG_MAC
656 //UDesktop::Deactivate();
657 ::ParamText( inMsg.getPasStr(), "\p", "\p", "\p");
658 ::StopAlert( 2002, 0 );
659 //#pragma rem back in!
660 //UDesktop::Activate();
661 #endif
662
663 #ifdef WIN32
664 ::MessageBox( 0, inMsg.getCStr(), "Examgen Message", MB_ICONEXCLAMATION | MB_OK | MB_SETFOREGROUND | MB_APPLMODAL );
665 //ZafMessageWindow* w = new ZafMessageWindow( "Message", ZAF_EXCLAMATION_ICON, ZAF_DIALOG_OK, ZAF_DIALOG_OK, inMsg.getCStr() );
666 //zafWindowManager -> Add( w );
667 //w -> Control();
668 #endif
669
670 }
671
672
673
ShowMsg(const char * inMsg)674 void EgOSUtils::ShowMsg( const char* inMsg ) {
675 UtilStr msg( inMsg );
676
677 ShowMsg( msg );
678 }
679
680
681
Rnd(long min,long max)682 long EgOSUtils::Rnd( long min, long max ) {
683 long maxRnd = RAND_MAX;
684 long retNum = rand() * ( max - min + 1 ) / maxRnd + min;
685
686 if ( retNum >= max )
687 return max;
688 else
689 return retNum;
690 }
691
692
693
694
RevBytes(unsigned long inNum)695 unsigned long EgOSUtils::RevBytes( unsigned long inNum ) {
696
697
698 return ( inNum << 24 ) | ( ( inNum & 0xFF00 ) << 8 ) | ( ( inNum & 0xFF0000 ) >> 8 ) | ( inNum >> 24 );
699 }
700
701
702
703 #define __SET_RGB( R, G, B ) \
704 if ( R < 0 ) \
705 outRGB.red = 0; \
706 else if ( R <= 0xFFFF ) \
707 outRGB.red = R; \
708 else \
709 outRGB.red = 0xFFFF; \
710 if ( G < 0 ) \
711 outRGB.green = 0; \
712 else if ( G <= 0xFFFF ) \
713 outRGB.green = G; \
714 else \
715 outRGB.green = 0xFFFF; \
716 if ( B < 0 ) \
717 outRGB.blue = 0; \
718 else if ( B <= 0xFFFF ) \
719 outRGB.blue = B; \
720 else \
721 outRGB.blue = 0xFFFF; \
722 break;
723
724
725
726
727
HSV2RGB(float H,float S,float V,RGBColor & outRGB)728 void EgOSUtils::HSV2RGB( float H, float S, float V, RGBColor& outRGB ) {
729
730
731 // H is given on [0, 1] or WRAPPED. S and V are given on [0, 1].
732 // RGB are each returned on [0, 1].
733 long hexQuadrant, m, n, v;
734 H = ( H - floor( H ) ) * 6; // Wrap the Hue angle around 1.0, then find quadrant
735
736 hexQuadrant = H;
737 float f = H - hexQuadrant;
738
739 // Check sat bounds
740 if ( S < 0 )
741 S = 0;
742 if ( S > 1 )
743 S = 1;
744
745 // Check val bounds
746 if ( V < 0 )
747 V = 0;
748 if ( V > 1 )
749 V = 1;
750
751 if ( ! ( hexQuadrant & 1 ) )
752 f = 1 - f; // hexQuadrant i is even
753
754 V *= 65535.0;
755 v = V;
756 m = V * (1 - S);
757 n = V * (1 - S * f);
758
759 switch ( hexQuadrant ) {
760 case 1: __SET_RGB( n, v, m );
761 case 2: __SET_RGB( m, v, n );
762 case 3: __SET_RGB( m, n, v );
763 case 4: __SET_RGB( n, m, v );
764 case 5: __SET_RGB( v, m, n );
765 default:
766 __SET_RGB( v, n, m );
767 }
768 }
769
770
771
772 /*
773 #define RETURN_HSV(h, w, b) {HSV.H = h; HSV.S = s; HSV.V = v; return HSV;}
774
775 #define RETURN_RGB(r, g, b) {RGB.R = r; RGB.G = g; RGB.B = b; return RGB;}
776
777 #define UNDEFINED -1
778
779 // Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms. Pure
780
781 // red always maps to 6 in this implementation. Therefore UNDEFINED can be
782
783 // defined as 0 in situations where only unsigned numbers are desired.
784
785 typedef struct {float R, G, B;} RGBType;
786
787 typedef struct {float H, S, V;} HSVType;
788
789 HSVType
790
791 RGB_to_HSV( RGBType RGB ) {
792
793 // RGB are each on [0, 1]. S and V are returned on [0, 1] and H is
794 // returned on [0, 6]. Exception: H is returned UNDEFINED if S==0.
795 float R = RGB.R, G = RGB.G, B = RGB.B, v, x, f;
796 int i;
797 HSVType HSV;
798 x = min(R, G, B);
799 v = max(R, G, B);
800 if(v == x) RETURN_HSV(UNDEFINED, 0, v);
801 f = (R == x) ? G - B : ((G == x) ? B - R : R - G);
802 i = (R == x) ? 3 : ((G == x) ? 5 : 1);
803 RETURN_HSV(i - f /(v - x), (v - x)/v, v);
804
805
806 }
807
808
809 RGBType
810
811 HSV_to_RGB( HSVType HSV ) {
812
813 // H is given on [0, 6] or UNDEFINED. S and V are given on [0, 1].
814 // RGB are each returned on [0, 1].
815 float h = HSV.H, s = HSV.S, v = HSV.V, m, n, f;
816 int i;
817 RGBType RGB;
818 if(h == UNDEFINED) RETURN_RGB(v, v, v);
819 i = floor(h);
820 f = h - i;
821 if(!(i & 1)) f = 1 - f; // if i is even
822 m = v * (1 - s);
823 n = v * (1 - s * f);
824 switch (i) {
825 case 6:
826 case 0: RETURN_RGB(v, n, m);
827 case 1: RETURN_RGB(n, v, m);
828 case 2: RETURN_RGB(m, v, n)
829 case 3: RETURN_RGB(m, n, v);
830 case 4: RETURN_RGB(n, m, v);
831 case 5: RETURN_RGB(v, m, n);
832 }
833
834
835 }
836 */
837
838