home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / 2d / ibitblt.c < prev    next >
Text File  |  1998-06-08  |  10KB  |  377 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: f:/miner/source/2d/rcs/ibitblt.c $
  15.  * $Revision: 1.6 $
  16.  * $Author: john $
  17.  * $Date: 1994/11/28 17:07:29 $
  18.  * 
  19.  * Rountines to copy a bitmap on top of another bitmap, but
  20.  * only copying to pixels that are transparent.
  21.  * 
  22.  * $Log: ibitblt.c $
  23.  * Revision 1.6  1994/11/28  17:07:29  john
  24.  * Took out some unused functions in linear.asm, moved
  25.  * gr_linear_movsd from linear.asm to bitblt.c, made sure that
  26.  * the code in ibiblt.c sets the direction flags before rep movsing.
  27.  * 
  28.  * Revision 1.5  1994/11/18  22:50:22  john
  29.  * Changed shorts to ints in parameters.
  30.  * 
  31.  * Revision 1.4  1994/11/09  16:35:16  john
  32.  * First version with working RLE bitmaps.
  33.  * 
  34.  * Revision 1.3  1994/10/03  17:18:05  john
  35.  * Fixed bug with edi not getting intialized to zero
  36.  * in create_mask.
  37.  * 
  38.  * Revision 1.2  1994/05/31  11:10:55  john
  39.  * *** empty log message ***
  40.  * 
  41.  * Revision 1.1  1994/05/30  16:08:27  john
  42.  * Initial revision
  43.  * 
  44.  * 
  45.  */
  46.  
  47.  
  48. #pragma off (unreferenced)
  49. static char rcsid[] = "$Id: ibitblt.c 1.6 1994/11/28 17:07:29 john Exp $";
  50. #pragma on (unreferenced)
  51.  
  52. #include <conio.h>
  53. #include <dos.h>
  54. #include <stdio.h>
  55. #include <stdlib.h>
  56.  
  57. #include "types.h"
  58. #include "gr.h"
  59. #include "mem.h"
  60. #include "error.h"
  61. #include "ibitblt.h"
  62.  
  63. #define MODE_NONE        0
  64. #define MODE_SKIP        1
  65. #define MODE_DRAW        2
  66.  
  67. #define OPCODE_ADD             0x81            
  68. #define OPCODE_ESI            0xC6            // Followed by a dword    (add esi, ????)
  69. #define OPCODE_EDI             0xC7            // Followed by a dword  (add edi, ????)
  70. #define OPCODE_MOV_ECX        0xB9            // Followed by a dword  (mov ecx,????)
  71. #define OPCODE_MOVSB           0xA4            // movsb
  72. #define OPCODE_16BIT         0x66            // movsw
  73. #define OPCODE_MOVSD         0xA5            // movsd
  74. #define OPCODE_REP            0xF3            // rep
  75. #define OPCODE_RET            0xC3            // ret
  76.  
  77. ubyte *Code_pointer = NULL;
  78. int Code_counter = 0;
  79.  
  80. void move_and_count( int dsource, int ddest, int ecx )
  81. {
  82.     int blocks;
  83.     if ( ecx <= 0 )    
  84.         return;
  85.  
  86.     if ( dsource > 0 )
  87.         Code_counter+=6;        // ADD ESI, dsource
  88.  
  89.     if ( ddest > 0 )
  90.         Code_counter+=6;        // ADD EDI, ddest
  91.  
  92.     while ( ecx > 0 )    {
  93.         switch(ecx)    {
  94.         case 1: Code_counter++; ecx = 0; break;    // MOVSB
  95.         case 2: Code_counter+=2; ecx = 0; break;    // MOVSW
  96.         case 3: Code_counter+=3; ecx = 0; break;    // MOVSW, MOVSB
  97.         case 4: Code_counter++; ecx = 0; break;     // MOVSD
  98.         default:
  99.             blocks = ecx / 4;
  100.             if ( blocks == 1 )
  101.                 Code_counter++;    // MOVSD
  102.             else 
  103.                 Code_counter+=7;
  104.             ecx -= blocks*4;
  105.         }
  106.     }
  107. }
  108.  
  109.  
  110. void move_and_draw( int dsource, int ddest, int ecx )
  111. {
  112.     int blocks;
  113.     int * iptr;
  114.  
  115.     if ( ecx <= 0 )
  116.         return;
  117.  
  118.     if ( dsource > 0 )    {
  119.         // ADD ESI, dsource
  120.         *Code_pointer++ = OPCODE_ADD;
  121.         *Code_pointer++ = OPCODE_ESI;
  122.         iptr = (int *)Code_pointer;
  123.         *iptr++ = dsource;
  124.         Code_pointer = (ubyte *)iptr;                        
  125.     }
  126.     if ( ddest > 0 )    {
  127.         // ADD EDI, ddest
  128.         *Code_pointer++ = OPCODE_ADD;
  129.         *Code_pointer++ = OPCODE_EDI;
  130.         iptr = (int *)Code_pointer;
  131.         *iptr++ = ddest;
  132.         Code_pointer = (ubyte *)iptr;                        
  133.     }
  134.  
  135.     while ( ecx > 0 )    {
  136.         switch( ecx )    {
  137.         case 1:
  138.             // MOVSB
  139.             *Code_pointer++ = OPCODE_MOVSB;
  140.             ecx = 0;
  141.             break;
  142.         case 2:
  143.             // MOVSW
  144.             *Code_pointer++ = OPCODE_16BIT;
  145.             *Code_pointer++ = OPCODE_MOVSD;
  146.             ecx = 0;
  147.             break;
  148.         case 3:
  149.             // MOVSW, MOVSB
  150.             *Code_pointer++ = OPCODE_16BIT;
  151.             *Code_pointer++ = OPCODE_MOVSD;
  152.             *Code_pointer++ = OPCODE_MOVSB;
  153.             ecx = 0;
  154.             break;
  155.         case 4:
  156.             // MOVSD
  157.             *Code_pointer++ = OPCODE_MOVSD;
  158.             ecx = 0;
  159.             break;
  160.         default:
  161.             blocks = ecx / 4;
  162.  
  163.             if ( blocks == 1 )    {    
  164.                 // MOVSD
  165.                 *Code_pointer++ = OPCODE_MOVSD;
  166.             } else {
  167.                 // MOV ECX, blocks
  168.                 *Code_pointer++ = OPCODE_MOV_ECX;
  169.                 iptr = (int *)Code_pointer;
  170.                 *iptr++ = blocks;
  171.                 Code_pointer = (ubyte *)iptr;                        
  172.                 // REP MOVSD
  173.                 *Code_pointer++ = OPCODE_REP;
  174.                 *Code_pointer++ = OPCODE_MOVSD;
  175.             }
  176.             ecx -= blocks*4;
  177.         }
  178.     }
  179. }
  180.  
  181. //-----------------------------------------------------------------------------------------
  182. // Given bitmap, bmp, finds the size of the code 
  183.  
  184. int gr_ibitblt_find_code_size( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
  185. {
  186.     int x,y;
  187.     ubyte pixel;
  188.     int draw_mode = MODE_NONE;
  189.     int source_offset = 0;
  190.     int dest_offset = 0;
  191.     int num_to_draw, draw_start_source, draw_start_dest;
  192.     int esi, edi;
  193.  
  194.     Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
  195.  
  196.     Code_counter = 0;
  197.  
  198.     esi = source_offset = 0;
  199.     edi = dest_offset = 0;
  200.     draw_start_source = draw_start_dest = 0;
  201.  
  202.     for ( y=sy; y<sy+sh; y++ )    {
  203.         for ( x=sx; x<sx+sw; x++ )    {
  204.             dest_offset = y*mask_bmp->bm_rowsize+x;
  205.             pixel = mask_bmp->bm_data[dest_offset];
  206.             if ( pixel!=255 )    {
  207.                 switch ( draw_mode)    {
  208.                 case MODE_DRAW:
  209.                     move_and_count( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
  210.                     esi = draw_start_source + num_to_draw;
  211.                     edi = draw_start_dest + num_to_draw;
  212.                     // fall through!!!
  213.                 case MODE_NONE:
  214.                 case MODE_SKIP:
  215.                     break;
  216.                 }
  217.                 draw_mode = MODE_SKIP;
  218.             } else {
  219.                 switch ( draw_mode)    {
  220.                 case MODE_SKIP:
  221.                 case MODE_NONE:
  222.                     draw_start_source = source_offset;
  223.                     draw_start_dest = dest_offset;
  224.                     num_to_draw = 0;
  225.                     // fall through
  226.                 case MODE_DRAW:
  227.                     num_to_draw++;
  228.                     break;
  229.                 }
  230.                 draw_mode = MODE_DRAW;
  231.             }
  232.             source_offset++;
  233.         }
  234.         if ( draw_mode == MODE_DRAW )    {
  235.             move_and_count( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
  236.             esi = draw_start_source + num_to_draw;
  237.             edi = draw_start_dest + num_to_draw;
  238.         }
  239.         draw_mode = MODE_NONE;
  240.         source_offset += (srowsize - sw);
  241.     }
  242.     Code_counter++;        // for return
  243.  
  244.     //printf( "Code will be %d bytes\n", Code_counter );
  245.  
  246.     Code_counter += 16;    // for safety
  247.  
  248.     return Code_counter;
  249. }
  250.  
  251.  
  252. //-----------------------------------------------------------------------------------------
  253. // Given bitmap, bmp, create code that transfers a bitmap of size sw*sh to position
  254. // (sx,sy) on top of bmp, only overwritting transparent pixels of the bitmap.
  255.  
  256. ubyte    *gr_ibitblt_create_mask( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
  257. {
  258.     int x,y;
  259.     ubyte pixel;
  260.     int draw_mode = MODE_NONE;
  261.     int source_offset = 0;
  262.     int dest_offset = 0;
  263.     int num_to_draw, draw_start_source, draw_start_dest;
  264.     int esi, edi;
  265.     int code_size;
  266.     ubyte *code;
  267.  
  268.     Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
  269.  
  270.     code_size = gr_ibitblt_find_code_size( mask_bmp, sx, sy, sw, sh, srowsize );
  271.  
  272.     code = malloc( code_size );
  273.     if ( code == NULL )
  274.         return NULL;
  275.  
  276.     Code_pointer = code;
  277.  
  278.     esi = source_offset = 0;
  279.     edi = dest_offset = 0;
  280.     draw_start_source = draw_start_dest = 0;
  281.  
  282.     for ( y=sy; y<sy+sh; y++ )    {
  283.         for ( x=sx; x<sx+sw; x++ )    {
  284.             dest_offset = y*mask_bmp->bm_rowsize+x;
  285.             pixel = mask_bmp->bm_data[dest_offset];
  286.             if ( pixel!=255 )    {
  287.                 switch ( draw_mode)    {
  288.                 case MODE_DRAW:
  289.                     move_and_draw( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
  290.                     esi = draw_start_source + num_to_draw;
  291.                     edi = draw_start_dest + num_to_draw;
  292.                     // fall through!!!
  293.                 case MODE_NONE:
  294.                 case MODE_SKIP:
  295.                     break;
  296.                 }
  297.                 draw_mode = MODE_SKIP;
  298.             } else {
  299.                 switch ( draw_mode)    {
  300.                 case MODE_SKIP:
  301.                 case MODE_NONE:
  302.                     draw_start_source = source_offset;
  303.                     draw_start_dest = dest_offset;
  304.                     num_to_draw = 0;
  305.                     // fall through
  306.                 case MODE_DRAW:
  307.                     num_to_draw++;
  308.                     break;
  309.                 }
  310.                 draw_mode = MODE_DRAW;
  311.             }
  312.             source_offset++;
  313.         }
  314.         if ( draw_mode == MODE_DRAW )    {
  315.             move_and_draw( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
  316.             esi = draw_start_source + num_to_draw;
  317.             edi = draw_start_dest + num_to_draw;
  318.         }
  319.         draw_mode = MODE_NONE;
  320.         source_offset += (srowsize - sw);
  321.     }
  322.     *Code_pointer++ = OPCODE_RET;
  323.  
  324.     if ( Code_pointer >= &code[code_size-1] )    
  325.         Error( "ibitblt overwrote allocated code block\n" );
  326.  
  327.     //printf( "Code is %d bytes\n", Code_pointer - code );
  328.  
  329.     return code;
  330. }
  331.  
  332.  
  333. void gr_ibitblt_do_asm(char *start_si, char *start_di, ubyte * code);
  334. #pragma aux gr_ibitblt_do_asm parm [esi] [edi] [eax] modify [ecx edi esi eax] = \
  335.     "pusha"    \
  336.     "cld"        \
  337.     "call    eax"    \
  338.     "popa"
  339.  
  340.  
  341. void gr_ibitblt(grs_bitmap * source_bmp, grs_bitmap * dest_bmp, ubyte * mask )
  342. {
  343.     if (mask != NULL )
  344.         gr_ibitblt_do_asm( source_bmp->bm_data, dest_bmp->bm_data, mask );
  345. }
  346.  
  347.  
  348. void    gr_ibitblt_find_hole_size( grs_bitmap * mask_bmp, int *minx, int *miny, int *maxx, int *maxy )
  349. {
  350.     ubyte c;
  351.     int x, y, count=0;
  352.  
  353.     Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
  354.  
  355.     *minx = mask_bmp->bm_w-1;
  356.      *maxx = 0;
  357.     *miny = mask_bmp->bm_h-1;
  358.     *maxy = 0;
  359.  
  360.     for ( y=0; y<mask_bmp->bm_h; y++ )
  361.         for ( x=0; x<mask_bmp->bm_w; x++ )    {
  362.             c = mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x];
  363.             if (c == 255 )    {
  364.                 if ( x < *minx ) *minx = x;
  365.                 if ( y < *miny ) *miny = y;
  366.                 if ( x > *maxx ) *maxx = x;
  367.                 if ( y > *maxy ) *maxy = y;
  368.                 count++;
  369.             }
  370.         }
  371.  
  372.     if ( count == 0 )    {
  373.         Error( "Bitmap for ibitblt doesn't have transparency!\n" );
  374.     }
  375. }
  376. 
  377.