home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / dlib06.zip / DLIB / DMAIN.C < prev    next >
Text File  |  1994-07-12  |  18KB  |  568 lines

  1. #define INCL_DEV
  2. #define INCL_DOS
  3. #define INCL_WIN
  4. #define INCL_32
  5. #include <os2.h>
  6. #include <string.h>
  7. #include <stdlib.h>
  8. #include <stdio.h>  
  9. #include "dlib.h"
  10. #include "portio.h"
  11.  
  12. struct {
  13.   ULONG ulPhysicalAddress;              /* Physical address                         */
  14.   ULONG ulApertureSize;                 /* 1 Meg, 4 Meg or 64k                      */
  15.   ULONG ulScanLineSize;                 /* This is >= the screen width in bytes.    */
  16.   RECTL rctlScreen;                     /* Device independant co-ordinates          */
  17. } ApertureInfo;
  18.  
  19. HAB   hab;                              /* Need a handle to an allocation block.      */
  20. HDC   hdc;                              /* Need a device context for the DecEsc's     */
  21. PBYTE pbLinearAddress;                  /* Holds the linear address to the video card.*/
  22. ULONG ulTotalScreenColors= 0L;          /* Holds the total number of colors.          */
  23. HFILE hDeviceDriver;                    /* Handle to the device driver to do mapping. */
  24. PCHAR VScreen;                          /* Pointer to Virtual Screen                  */
  25. PCHAR Dbuf = NULL;                      /* 2nd virtual screen for double buffering    */
  26. ULONG VScreenX, VScreenY, VScreenSize;  /* Virtual screen details                     */
  27. ULONG VHeight, VWidth;                  /* View width and height                      */
  28. ULONG OriginX = 0, OriginY = 0;         /* View origin x and y (within virtual screen)*/
  29. ULONG Vatx = 0, Vaty = 0;               /* where window will be on screen             */
  30. CHAR  VPalette[768];                    /* Copy of Virtual Palette                    */
  31. CHAR  PPalette[768];                    /* Copy of Physical Palette                   */
  32. CHAR  _TranslateRGB[256];               /* RGB <--> RGB color translation table       */
  33. ULONG _startbank;
  34. PBYTE _startaddr;
  35. PBYTE _Ostartaddr;
  36. ULONG _ulAperture;
  37. void ( *DisplayFunction )( void );      /* which blt method to use....                */
  38.  
  39.  
  40. struct _COLOR_CHANGE_ITEM {             /* list of images needing color translation...*/
  41.    ULONG size;                          /* ..... in case of palette change            */
  42.    ULONG type;
  43.    PCHAR image;
  44.    struct _COLOR_CHANGE_ITEM *next;
  45. } ImageListHead = {0,NULL,NULL};
  46.  
  47.  
  48.  
  49. extern void memcpyd(char *dest,char *src,ULONG size);
  50. #pragma aux memcpyd = \
  51.     "shr ecx,2"       \
  52.     "rep movsd"       \
  53.     parm [edi][esi][ecx];
  54.  
  55.  
  56.  
  57. void _segmented_aperture_256(void)
  58. /* used internally by dlib, for 256 color modes, with 64k aperture */
  59. {
  60.    #define DEVESC_ACQUIREFB   33010L
  61.    #define DEVESC_DEACQUIREFB 33020L
  62.    #define DEVESC_SWITCHBANK  33030L
  63.    ULONG ulNumBytes;
  64.    PBYTE pbSrc = _Ostartaddr;
  65.    ULONG rc = 0L;
  66.    ULONG X, Y, ulAperture = _ulAperture;
  67.    PBYTE pbDst = _startaddr;
  68.    struct {
  69.           ULONG  fAFBFlags;
  70.           ULONG  ulBankNumber;
  71.           RECTL  rctlXRegion;
  72.           } acquireFb;
  73.  
  74.    acquireFb.rctlXRegion.xLeft   = 0L;
  75.    acquireFb.rctlXRegion.xRight  = 0L;
  76.    acquireFb.rctlXRegion.yTop    = 0L;
  77.    acquireFb.rctlXRegion.yBottom = 0L;
  78.    acquireFb.ulBankNumber        = _startbank;
  79.    acquireFb.fAFBFlags           = 1L;  /* Acquire and switch simultaneously.*/
  80.  
  81.    if ( DevEscape ( hdc, DEVESC_ACQUIREFB, sizeof (acquireFb),
  82.             (PBYTE) &acquireFb, (PLONG) &ulNumBytes, (PBYTE) NULL ) !=DEV_OK )
  83.       return;
  84.  
  85.    Y = VHeight;
  86.    while ( Y-- ) {
  87.        /* Check if this line will pass through an aperture switch.      */
  88.        if ( ulAperture < VWidth ) {
  89.            /* Move the rest of bytes for this aperture to the screen.    */
  90.            memcpyd ( pbDst, pbSrc, ulAperture );
  91.            pbDst += VWidth;
  92.            pbSrc += VScreenX;
  93.  
  94.            /* Now I need to do a bank switch.                            */
  95.            acquireFb.ulBankNumber++;
  96.            DevEscape ( hdc, DEVESC_SWITCHBANK, 4L, (PBYTE) &acquireFb.ulBankNumber,(PLONG) &ulNumBytes, (PBYTE) NULL );
  97.  
  98.            /* Set up the rest of the line to move to the screen.         */
  99.            X = VWidth - ulAperture;
  100.  
  101.            /* Reset the linear address to the begining of the bank.      */
  102.            pbDst = pbLinearAddress;
  103.            ulAperture = ApertureInfo.ulApertureSize + ulAperture;
  104.        } else
  105.            /* There's room on this aperture for the whole line, so do it.*/
  106.            X = VWidth;
  107.  
  108.        /* Move the pixels to the screen.                                */
  109.        memcpyd ( pbDst, pbSrc, X );
  110.        pbSrc += VScreenX;
  111.        pbDst += X;
  112.  
  113.        /* Adjust the output line destination.                           */
  114.        pbDst += ApertureInfo.ulScanLineSize - VWidth;
  115.        ulAperture -= ApertureInfo.ulScanLineSize;
  116.        /* If aperture size is non-positive, then we do a switch banks.  */
  117.        if ((LONG)ulAperture <= 0 ) {
  118.            ulAperture += ApertureInfo.ulApertureSize;
  119.            pbDst -= ApertureInfo.ulApertureSize;
  120.            acquireFb.ulBankNumber++;
  121.            DevEscape( hdc, DEVESC_SWITCHBANK, 4L,(PBYTE) &acquireFb.ulBankNumber,(PLONG) &ulNumBytes,(PBYTE) NULL);
  122.        }
  123.    }
  124.    /* Release the frame buffer... this is important.                         */
  125.    DevEscape ( hdc, DEVESC_DEACQUIREFB, (ULONG)0L, (PBYTE) NULL,(PLONG)0L, (PBYTE) NULL );
  126.    return;
  127. }
  128.  
  129.  
  130.  
  131. void _large_aperture_256(void)
  132. /* used internally by dlib, for 256 color modes, with linear mode */
  133. {
  134.    #define DEVESC_ACQUIREFB   33010L
  135.    #define DEVESC_DEACQUIREFB 33020L
  136.    #define DEVESC_SWITCHBANK  33030L
  137.    ULONG ulNumBytes;
  138.    PBYTE pbSrc = _Ostartaddr;
  139.    ULONG rc = 0L;
  140.    ULONG X, Y, ulAperture = _ulAperture;
  141.    PBYTE pbDst = _startaddr;
  142.    struct {
  143.           ULONG  fAFBFlags;
  144.           ULONG  ulBankNumber;
  145.           RECTL  rctlXRegion;
  146.           } acquireFb;
  147.  
  148.    acquireFb.rctlXRegion.xLeft   = 0L;
  149.    acquireFb.rctlXRegion.xRight  = 0L;
  150.    acquireFb.rctlXRegion.yTop    = 0L;
  151.    acquireFb.rctlXRegion.yBottom = 0L;
  152.    acquireFb.ulBankNumber        = 0;
  153.    acquireFb.fAFBFlags           = 1L;  /* Acquire and switch simultaneously.*/
  154.  
  155.    if ( DevEscape ( hdc, DEVESC_ACQUIREFB, sizeof (acquireFb),
  156.             (PBYTE) &acquireFb, (PLONG) &ulNumBytes, (PBYTE) NULL ) !=DEV_OK )
  157.       return;
  158.  
  159.    Y = VHeight;
  160.    while ( Y-- ) {
  161.        /* Move the pixels to the screen.                                */
  162.        memcpyd ( pbDst, pbSrc, VWidth );
  163.        pbSrc += VScreenX;
  164.        pbDst += ApertureInfo.ulScanLineSize;
  165.    }
  166.    /* Release the frame buffer... this is important.                         */
  167.    DevEscape ( hdc, DEVESC_DEACQUIREFB, (ULONG)0L, (PBYTE) NULL,(PLONG)0L, (PBYTE) NULL );
  168.    return;
  169. }
  170.  
  171.  
  172.  
  173. ULONG __syscall dShowView(void)
  174. {
  175.     DisplayFunction();
  176.     return 0UL;
  177. }
  178.  
  179.  
  180.  
  181.  
  182. ULONG MapPhysicalToLinear ( ULONG ulPhysicalAddress )
  183. /* used internally by dlib */
  184. {
  185.    ULONG  ulActionTaken;
  186.    ULONG  ulDLength;
  187.    ULONG  ulPLength;
  188.    struct {
  189.           ULONG   hstream;
  190.           ULONG   hid;
  191.           ULONG   ulFlag;
  192.           ULONG   ulPhysAddr;
  193.           ULONG   ulVram_length;
  194.           } parameter;
  195.    #pragma pack (1)
  196.    struct {
  197.           USHORT usXga_rng3_selector;
  198.           ULONG  ulLinear_address;
  199.           } ddstruct;
  200.    #pragma pack ()
  201.  
  202.    /* Attempt to open up the device driver.                                  */
  203.    if ( DosOpen( (PSZ)"\\DEV\\SMVDD01$", (PHFILE) &hDeviceDriver,
  204.             (PULONG) &ulActionTaken, (ULONG)  0L, (ULONG) FILE_SYSTEM,
  205.             OPEN_ACTION_OPEN_IF_EXISTS, OPEN_SHARE_DENYNONE  |
  206.             OPEN_FLAGS_NOINHERIT | OPEN_ACCESS_READONLY, (ULONG) 0L)   )
  207.       return ( 3L );
  208.  
  209.    /* Set up the parameters for the IOCtl to map the vram to linear addr.    */
  210.    parameter.hstream       = 0L;
  211.    parameter.hid           = 0L;
  212.    parameter.ulFlag        = 1L;     /* Meaning MapRam. */
  213.    parameter.ulPhysAddr    = ulPhysicalAddress;
  214.    parameter.ulVram_length = ApertureInfo.ulApertureSize;
  215.    ulPLength               = sizeof (parameter);
  216.    ulDLength               = 0L;
  217.  
  218.    /* Call the IOCtl to do the map.                                          */
  219.    if ( DosDevIOCtl ( hDeviceDriver, (ULONG)0x81,
  220.                       (ULONG)0x42L, (PVOID)¶meter,
  221.                       (ULONG)ulPLength, (PULONG)&ulPLength,
  222.                       (PVOID)&ddstruct, (ULONG)6, (PULONG)&ulDLength ) )
  223.       return ( 4L );
  224.  
  225.    /* Set the variable to the linear address, and return.                    */
  226.    pbLinearAddress= (PBYTE) ddstruct.ulLinear_address;
  227.  
  228.    return ( 0L );
  229. }
  230.  
  231.  
  232.  
  233.  
  234.  
  235. ULONG DirectScreenInit ( VOID )
  236. /* used internally by dlib, see DIVE.ZIP on ftp-os2.cdrom.com for more details */
  237. {
  238.    #define DEVESC_GETAPERTURE 33000L
  239.    ULONG          rc;
  240.    ULONG          ulFunction;
  241.    LONG           lOutCount;
  242.    HPS            hps;
  243.    DEVOPENSTRUC   dop= {0L,(PSZ)"DISPLAY",NULL,0L,0L,0L,0L,0L,0L};
  244.  
  245.    if ( ulTotalScreenColors )
  246.       return ( 0xffffffff );
  247.  
  248.    DisplayFunction = NULL;
  249.    hab= WinInitialize ( 0L );
  250.    hps= WinGetPS ( HWND_DESKTOP );
  251.    hdc= DevOpenDC ( hab, OD_MEMORY, (PSZ)"*", 5L,(PDEVOPENDATA)&dop, (HDC)NULL);
  252.    DevQueryCaps ( hdc, CAPS_COLORS, 1L, (PLONG)&ulTotalScreenColors);
  253.  
  254.    ulFunction = DEVESC_GETAPERTURE;
  255.    if ( DevEscape( hdc, DEVESC_QUERYESCSUPPORT, 4L,(PBYTE)&ulFunction, NULL, (PBYTE)NULL ) == DEV_OK ){
  256.       lOutCount= sizeof (ApertureInfo);
  257.       if ( DevEscape ( hdc, DEVESC_GETAPERTURE, 0L, (PBYTE) NULL,
  258.             &lOutCount, (PBYTE)&ApertureInfo) != DEV_OK ){
  259.          ulTotalScreenColors= 0L;
  260.          rc= 2L;
  261.       }else{
  262.          if ( ulTotalScreenColors==16L ){
  263.             ApertureInfo.ulScanLineSize= ApertureInfo.ulScanLineSize >> 1;
  264. /*          DisplayFunction = ;   <-- 4 bit color routine*/
  265.          } else if ( ulTotalScreenColors==256L ) {
  266.             if (ApertureInfo.ulApertureSize > 65536) {
  267.                DisplayFunction = _large_aperture_256;
  268.             } else {
  269.                DisplayFunction = _segmented_aperture_256;
  270.             } 
  271.          } else if ( ulTotalScreenColors==65536L ){
  272.             ApertureInfo.ulScanLineSize= ApertureInfo.ulScanLineSize << 1;
  273. /*          DisplayFunction = ;   <--16 bit color routine*/
  274.          }else if ( ulTotalScreenColors==16777216L ) {
  275.             ApertureInfo.ulScanLineSize= ApertureInfo.ulScanLineSize +
  276.             ( ApertureInfo.ulScanLineSize << 1 );
  277. /*          DisplayFunction = ;   <--24 bit color routine*/
  278.          }
  279.          rc= 0L;
  280.       }
  281.    } else {
  282.       ulTotalScreenColors= 0L;
  283.       rc= 1L;
  284.    }
  285.  
  286.    WinReleasePS ( hps );
  287.    if ( !rc )
  288.       rc = MapPhysicalToLinear ( ApertureInfo.ulPhysicalAddress );
  289.  
  290.    return ( rc );
  291. }
  292.  
  293.  
  294.  
  295.  
  296. ULONG DirectScreenTerm ( VOID )
  297. /* used internally by dlib */
  298. {
  299.    if ( !ulTotalScreenColors )
  300.       return ( 1L );
  301.    ulTotalScreenColors= 0L;
  302.    DevCloseDC ( hdc );
  303.    WinTerminate ( hab );
  304.    return ( DosClose ( hDeviceDriver ) );
  305. }
  306.  
  307.  
  308.  
  309.  
  310.  
  311. void __syscall dWaitRetrace(void)
  312. /* returns in the next verticle retrace, could be used for smooth animation. */
  313. {
  314.    while ((inp(0x3da)&0x08)!=0);        /* poll VR bit */
  315.    while ((inp(0x3da)&0x08)==0);
  316. }
  317.  
  318.  
  319.  
  320.  
  321.  
  322. PCHAR __syscall dCreateVirtualScreen( ULONG xsize, ULONG ysize )
  323. /* Creates a virtual screen, and returns a pointer to it. This MUST be
  324.    called before any other dlib functions */
  325. {
  326.     int i;
  327.  
  328.     if (DirectScreenInit() != 0)        /* retrieve MMPM/2 SMV details and int */
  329.         return NULL;
  330.     VScreenX = xsize;
  331.     VScreenY = ysize;
  332.     VScreenSize = xsize * ysize;
  333.     VScreen = (PCHAR)malloc( VScreenSize );
  334.     for (i=0; i<256; i++)               /* set colors to the OS/2 default palette */
  335.         _TranslateRGB[i] = i;
  336.     return VScreen;
  337. }
  338.  
  339.  
  340. void __syscall dSetOrigin(ULONG x, ULONG y)
  341. /*  (x,y) sets the offset into the virtual screen. Can be used for scrolling.*/
  342. {
  343.     if (x > (VScreenX - VWidth))
  344.        x = (VScreenX - VWidth);
  345.     if (y > (VScreenY - VWidth))
  346.        y = (VScreenY - VWidth);
  347.  
  348.     OriginX = x;
  349.     OriginY = y;
  350.     _Ostartaddr = VScreen + OriginX + (OriginY * VScreenX);
  351. }
  352.  
  353.  
  354. void __syscall dSetViewArea( ULONG atx, ULONG aty, ULONG xsize, ULONG ysize )
  355. /* This set the information about the view window. 
  356.    (atx,aty)     give the position on the screen. (0,0) is the top left of the screen.
  357.    (xsize,ysize) is the size of the window to display. */
  358. {
  359.     if (xsize > VScreenX)
  360.        xsize = VScreenX;
  361.     if (ysize > VScreenY)
  362.        ysize = VScreenY;
  363.  
  364.     VHeight = ysize;                    /* size of viewport into virtual screen */
  365.     VWidth = xsize;
  366.     Vatx = atx;                         /* location on screen */
  367.     Vaty = aty;
  368.  
  369.     if (ApertureInfo.ulApertureSize == 0)
  370.        ApertureInfo.ulApertureSize = 64000;
  371.     
  372.     _startbank = (Vaty * ApertureInfo.ulScanLineSize) / ApertureInfo.ulApertureSize;
  373.     _startaddr = pbLinearAddress + Vatx + ((Vaty * ApertureInfo.ulScanLineSize) % ApertureInfo.ulApertureSize);
  374.     _ulAperture = ApertureInfo.ulApertureSize - ((Vaty * ApertureInfo.ulScanLineSize) % ApertureInfo.ulApertureSize);
  375.     _Ostartaddr = VScreen + OriginX + (OriginY * VScreenX);
  376. }
  377.  
  378.  
  379.  
  380.  
  381.  
  382. #define SQR(x) ((x) * (x))
  383. int rgb_diff(int r1,int g1,int b1,int r2,int g2,int b2)
  384. /* Used internally by dlib to setup the color translation table */
  385. {
  386.    int tmp, rd, gd, bd;
  387.    rd = abs(r1 - r2);
  388.    gd = abs(g1 - g2);
  389.    bd = abs(b1 - b2);
  390.    tmp = SQR((rd)) + SQR((gd)) + SQR((bd));
  391.    return abs(tmp);
  392. }
  393.  
  394.  
  395.  
  396. void SetupTranslationTable(void)
  397. /* Used internally by dlib to setup the color translation table */
  398. {
  399.    unsigned int c, i, min, conv2, dif;
  400.  
  401.    for (c=0; c<256; c++) {
  402.         outp(0x3c7, c);
  403.         PPalette[c*3] = inp(0x3c9);
  404.         PPalette[(c * 3) + 1] = inp(0x3c9);
  405.         PPalette[(c * 3) + 2] = inp(0x3c9);
  406.    } 
  407.    for (c=1; c<256; c++) {
  408.       min = 0xffffff;
  409.       for (i=1; i<256; i++) {
  410.          dif = rgb_diff(VPalette[(c*3)], VPalette[(c*3)+1], VPalette[(c*3)+2], 
  411.                         PPalette[(i*3)], PPalette[(i*3)+1],PPalette[(i*3)+2]);
  412.          if (dif < min) {
  413.             min = dif;
  414.             conv2 = i;
  415.          }
  416.       }
  417.       _TranslateRGB[c] = conv2;
  418.    } 
  419. }
  420.  
  421.  
  422.  
  423.  
  424. void __syscall dSetVirtualPalette(PCHAR *rgb)
  425. /* Tells dlib to use a virtual palette. This isn't perfect, but usually 
  426.    does a good job matching palettes. */
  427. {
  428.     memcpy( VPalette, rgb, 768 );
  429.     SetupTranslationTable();
  430. }
  431.  
  432.  
  433.  
  434.  
  435. unsigned char __syscall dNearestColor(unsigned char index)
  436. /* returns the number of the physical color most closely matching the 
  437.    color requested from the 'virtual palette' */
  438. {
  439.     return _TranslateRGB[index];
  440. }
  441.  
  442.  
  443.  
  444.  
  445. void __syscall dRealizeImages(void)
  446. /* This function should be called when the palette is changed. 
  447.    When the palette is changed, WM_REALIZEPALETTE is sent to all
  448.    PM message queues to inform of the change. */
  449. {
  450.     struct _COLOR_CHANGE_ITEM *list;
  451.     int i;
  452.  
  453.     SetupTranslationTable();            /* create translation lookup table */
  454.     list = ImageListHead.next;
  455.     while (list != NULL) {
  456.        for (i=0; i<(list->size); i++) {
  457.           list->image[i] = _TranslateRGB[list->image[i]];
  458.        }
  459.     }
  460.     for (i=0; i<VScreenSize; i++) {
  461.         VScreen[i] = _TranslateRGB[VScreen[i]];
  462.     }
  463.     dShowView();                        /* redisplay view, with new palette */
  464. }
  465.  
  466.  
  467.  
  468.  
  469. void __syscall dDistroyVirtualScreen(void)
  470. /* Free the memory held by the Virtual Screen, and close our device context */
  471. {
  472.     free(VScreen);
  473.     DirectScreenTerm();
  474. }
  475.  
  476.  
  477.  
  478.  
  479. void __syscall dEnableDoubleBuf(void)
  480. /* When called, this takes a copy of everything in the 'Virtual Screen'.
  481.    This copy can be used to restore parts of the screen when needed. */
  482. {
  483.     Dbuf = malloc(VScreenX * VScreenY);
  484.     memcpy(Dbuf, VScreen, (VScreenX * VScreenY));
  485. }
  486.  
  487.  
  488.  
  489.  
  490. void __syscall dReplaceFromDoubleBuf(int x1, int y1, int x2, int y2)
  491. /* dEnableDoubleBuf must be called before this function. This function
  492.    is used to restore store bits(backgrounds) of the screen, during 
  493.    animation. Assumes (x1,y1) is top right, (x2,y2) is bottom left */
  494. {
  495.     ULONG loc = x1 + (y1 * VScreenX);
  496.     ULONG size = x2 - x1;
  497.  
  498.     if (Dbuf == NULL)                   /* is double buffering active? */
  499.        return;
  500.     while (y1 < y2) {                   
  501.        memcpy(&VScreen[loc], &Dbuf[loc], size);
  502.        loc += VScreenX;
  503.        y1++;
  504.     }
  505. }
  506.  
  507.  
  508.  
  509.  
  510. void __syscall dDisableDoubleBuf(void)
  511. /* Frees the memory used by double buffering, and disable's restores */
  512. {
  513.     free(Dbuf);
  514.     Dbuf = NULL;
  515. }
  516.  
  517.  
  518. /*
  519. void loadpal(char *filename)
  520. {
  521.     FILE *pal;
  522.     char rgb[768];
  523.  
  524.     pal = fopen(filename,"rb");
  525.     fread(rgb,768,1,pal);
  526.     fclose(pal);
  527.     dSetVirtualPalette(rgb);
  528. }
  529.  
  530.  
  531. int main(void)
  532. {
  533.     char *scr;
  534.     PIMAGE pic1;
  535.     int i;
  536.  
  537.     scr = dCreateVirtualScreen(1024,400);
  538.     loadpal("test.pal");
  539.     pic1 = dLoadImage("bad1.vga");
  540.     dCompileSprite(pic1);
  541.     for (i=0;i<150; i++) {
  542.        dCircle(150,150,i,i);
  543.     }
  544.     for (i=0; i<400; i+=10) {
  545.        dLine(300+i,10,700,10+i,i);
  546.     }
  547.     dBox(800,10,900,100,3);
  548.     dSetViewArea(100,100,320,200);
  549.     dEnableDoubleBuf();
  550.     for (i=30; i<150; i+=5) {
  551.         dBltStretchImage(pic1,10,10,i,i);
  552.         dShowView();
  553.     }
  554.     while (!kbhit()) {
  555.         for (i=0; i<600; i++) {
  556.             dBltSprite(i,10,pic1);
  557.             dShowView();
  558.             dReplaceFromDoubleBuf(i, 10, i+pic1->xs, 10+pic1->ys);
  559.         }
  560.     }
  561.     dDisableDoubleBuf();
  562.     dDistroyVirtualScreen();
  563.     getch();
  564.     return 0;
  565. }
  566. */
  567.  
  568.