home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Science⁄Math / VideoToolbox / Demos / Grating.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-03  |  5.6 KB  |  151 lines  |  [TEXT/KAHL]

  1. /*
  2. Grating.c
  3. This demo shows how to load the clut and put a vignetted grating onto the
  4. screen. This demo has been kept as simple as possible, to enhance readability,
  5. forsaking accurate control of time and contrast of the stimulus. The
  6. FlickeringGrating demo, on the other hand, is somewhat more elaborate and
  7. presents a research-grade stimulus if the LuminanceRecord.h calibration data are
  8. accurate.
  9.  
  10. For a real experiment there are some refinements you should consider. This demo
  11. takes a while to create the image on the screen, but you probably want
  12. frame-accurate timing in your experiment. You could either create the image in
  13. an offscreen GWorld and copy it to the screen with CopyBitsQuickly. Or you could
  14. set the clut to uniform gray (every clut entry equal to the background
  15. luminance) while you're computing the image on-screen, and then load a grayscale
  16. ramp into the clut when you want the display to start. Similarly you can make
  17. the image disappear by either loading a new image, or clearing the screen by
  18. calling EraseRect(), or loading a uniform-gray clut.
  19.  
  20. Another issue that matters for a real experiment is gamma correction. The
  21. numbers loaded into the clut are faithfully transformed into voltages by the
  22. three digital-to-analog converters on your video card, but the resulting
  23. luminance produced on your monitor will be an approximately parabolic function
  24. of the video voltage. Apple provides crude gamma correction by means of a
  25. generic 8-bit gamma table in the video driver, which does make things look
  26. better, but is not accurately matched to the gamma of your particular monitor,
  27. which depends on the current settings of its brightness and contrast knobs.
  28. Furthermore the Apple 8-bit gamma-correction scheme, which simply transforms the
  29. nominal 8-bit clut value into a new 8-bit clut value, necessarily restricts the
  30. range of available values, mapping several onto one output value, and omitting
  31. some output values. In other words your luminances will be 8-bit quantized
  32. twice, both before and after gamma correction. It is preferable to do gamma
  33. correction first, without quantization. Therefore I suggest you eliminate
  34. Apple's gamma correction, by calling GDUncorrectedGamma(), and use the
  35. Luminance.c package to do gamma correction. That package implements the
  36. published algorithm of Pelli and Zhang (1991). The FlickeringGrating demo uses
  37. Luminance.c.
  38.  
  39. HISTORY:
  40. 2/7/93    dgp wrote it, as an answer to questions from Bill Merigan and David Brainard.
  41. 2/18/93    dgp    added fpu test.
  42. 2/23/93    dgp    use new GDOpenWindow1 and GDDisposeWindow1.
  43. 4/18/93    dgp    support directType.
  44. 7/7/93    dgp    prefer screen 1. Added ScrollRect for compatibility with Radius PowerView.
  45. 10/2/93    dgp    added SAVE_PICT to test PixMapToPICT().
  46. */
  47. #include "VideoToolbox.h"
  48. #include <math.h>
  49. #if THINK_C
  50.     #include <console.h>
  51. #endif
  52. #define SIZE 300
  53. #define SAVE_PICT    1    // set to zero to disable saving image to disk.
  54.  
  55. void main(void)
  56. {
  57.     short i,j,error,clutSize,pixelSize,mode;
  58.     short preferredPixelSize[6]={8,32,16,4,2,1};    // Order of preference
  59.     GDHandle device;
  60.     static ColorSpec table[256];
  61.     WindowPtr window,oldPort,w;
  62.     Rect r;
  63.     double a,fX[SIZE],fY[SIZE];
  64.     char string[100];
  65.     Point pt={100,0};
  66.     RgnHandle rgn;
  67.     
  68.     StackGrow(10000);
  69.     #if THINK_C
  70.         console_options.top = 0;
  71.         console_options.left = 0;
  72.         console_options.nrows = 4;
  73.         console_options.ncols = 60;
  74.         printf("\n");
  75.     #else
  76.         InitGraf((Ptr) &thePort);
  77.         InitFonts();
  78.         InitWindows();
  79.         InitCursor();
  80.     #endif
  81.     printf("Welcome to Grating.\n");
  82.     Require(gestalt8BitQD);
  83.     GetPort(&oldPort);
  84.     device=GetScreenDevice(1);
  85.     if(device==NULL)device=GetScreenDevice(0);
  86.     
  87.     // Try to get the best possible pixelSize.
  88.     pixelSize=(**(**device).gdPMap).pixelSize;
  89.     if(pixelSize!=preferredPixelSize[i] && NewPaletteManager()){
  90.         for(i=0;i<sizeof(preferredPixelSize)/sizeof(short);i++){
  91.             if(pixelSize==preferredPixelSize[i])break;
  92.             mode=HasDepth(device,preferredPixelSize[i],0,0);
  93.             if(mode!=0){
  94.                 printf("Excuse me while I change the pixelSize to %d bits.\n"
  95.                     ,preferredPixelSize[i]);
  96.                 error=SetDepth(device,mode,0,0);
  97.                 break;
  98.             }
  99.         }
  100.         pixelSize=(**(**device).gdPMap).pixelSize;
  101.     }
  102.  
  103.     // Load the clut with a grayscale ramp.
  104.     GDSaveGamma(device);
  105.     GDUncorrectedGamma(device);    // Tell the driver to faithfully copy our colors into 
  106.                                 // the clut without any transformation.
  107.     clutSize=GDClutSize(device);
  108.     for(i=0;i<clutSize;i++){
  109.         table[i].rgb.red=table[i].rgb.green=table[i].rgb.blue=i*(long)0xffff/(clutSize-1);
  110.     }
  111.     error=GDSetEntriesByType(device,0,clutSize-1,table);
  112.  
  113.     // Open window and put grating in it.
  114.     SetMouse(pt);
  115.     window=GDOpenWindow1(device);
  116.     SetPort(window);
  117.     PmBackColor((clutSize-1)*0.5);    // This works because GDOpenWindow1 marked
  118.     EraseRect(&window->portRect);    // all the colors as pmExplicit.
  119.     SetRect(&r,0,0,SIZE,SIZE);
  120.     CenterRectInRect(&r,&window->portRect);
  121.     for(i=0;i<SIZE;i++){
  122.         a=(i-SIZE/2)/(SIZE/6.);
  123.         fY[i]=exp(-a*a);
  124.         fX[i]=fY[i]*sin((i-SIZE/2)*(2.0*PI/80.0));
  125.     }
  126.     for(j=0;j<SIZE;j++){
  127.         unsigned long row[SIZE];
  128.         for(i=0;i<SIZE;i++) row[i]=0.5+(clutSize-1)*0.5*(1.0+fY[j]*fX[i]);
  129.         if(pixelSize==16)for(i=0;i<SIZE;i++) row[i]*=1+(1<<5)+(1<<10);
  130.         if(pixelSize==32)for(i=0;i<SIZE;i++) row[i]*=1+(1<<8)+(1UL<<16);
  131.         SetPixelsQuickly(r.left,r.top+j,row,SIZE);
  132.     }
  133.     // This conditional code forces the Radius PowerView
  134.     // to update the screen from the video buffer in memory.
  135.     #if 1    // Ok, but I don't actually want to scroll.
  136.         rgn=NewRgn();
  137.         ScrollRect(&r,0,1,rgn);
  138.         ScrollRect(&r,0,-1,rgn);
  139.         DisposeRgn(rgn);
  140.     #endif
  141.     if(SAVE_PICT)PixMapToPICT("grating.pict",((CWindowPtr)window)->portPixMap
  142.         ,&r,2,NULL);
  143.     printf("Done. Hit return to quit.\n");
  144.     gets(string);
  145.     SetPort((WindowPtr)oldPort);
  146.     GDDisposeWindow1(window);
  147.     GDRestoreGamma(device);
  148.     GDRestoreDeviceClut(device);
  149.     abort();
  150. }
  151.