IBITBLT.C 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  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. #pragma off (unreferenced)
  47. static char rcsid[] = "$Id: ibitblt.c 1.6 1994/11/28 17:07:29 john Exp $";
  48. #pragma on (unreferenced)
  49. #include <conio.h>
  50. #include <dos.h>
  51. #include <stdio.h>
  52. #include <stdlib.h>
  53. #include "types.h"
  54. #include "gr.h"
  55. #include "mem.h"
  56. #include "error.h"
  57. #include "ibitblt.h"
  58. #define MODE_NONE 0
  59. #define MODE_SKIP 1
  60. #define MODE_DRAW 2
  61. #define OPCODE_ADD 0x81
  62. #define OPCODE_ESI 0xC6 // Followed by a dword (add esi, ????)
  63. #define OPCODE_EDI 0xC7 // Followed by a dword (add edi, ????)
  64. #define OPCODE_MOV_ECX 0xB9 // Followed by a dword (mov ecx,????)
  65. #define OPCODE_MOVSB 0xA4 // movsb
  66. #define OPCODE_16BIT 0x66 // movsw
  67. #define OPCODE_MOVSD 0xA5 // movsd
  68. #define OPCODE_REP 0xF3 // rep
  69. #define OPCODE_RET 0xC3 // ret
  70. ubyte *Code_pointer = NULL;
  71. int Code_counter = 0;
  72. void move_and_count( int dsource, int ddest, int ecx )
  73. {
  74. int blocks;
  75. if ( ecx <= 0 )
  76. return;
  77. if ( dsource > 0 )
  78. Code_counter+=6; // ADD ESI, dsource
  79. if ( ddest > 0 )
  80. Code_counter+=6; // ADD EDI, ddest
  81. while ( ecx > 0 ) {
  82. switch(ecx) {
  83. case 1: Code_counter++; ecx = 0; break; // MOVSB
  84. case 2: Code_counter+=2; ecx = 0; break; // MOVSW
  85. case 3: Code_counter+=3; ecx = 0; break; // MOVSW, MOVSB
  86. case 4: Code_counter++; ecx = 0; break; // MOVSD
  87. default:
  88. blocks = ecx / 4;
  89. if ( blocks == 1 )
  90. Code_counter++; // MOVSD
  91. else
  92. Code_counter+=7;
  93. ecx -= blocks*4;
  94. }
  95. }
  96. }
  97. void move_and_draw( int dsource, int ddest, int ecx )
  98. {
  99. int blocks;
  100. int * iptr;
  101. if ( ecx <= 0 )
  102. return;
  103. if ( dsource > 0 ) {
  104. // ADD ESI, dsource
  105. *Code_pointer++ = OPCODE_ADD;
  106. *Code_pointer++ = OPCODE_ESI;
  107. iptr = (int *)Code_pointer;
  108. *iptr++ = dsource;
  109. Code_pointer = (ubyte *)iptr;
  110. }
  111. if ( ddest > 0 ) {
  112. // ADD EDI, ddest
  113. *Code_pointer++ = OPCODE_ADD;
  114. *Code_pointer++ = OPCODE_EDI;
  115. iptr = (int *)Code_pointer;
  116. *iptr++ = ddest;
  117. Code_pointer = (ubyte *)iptr;
  118. }
  119. while ( ecx > 0 ) {
  120. switch( ecx ) {
  121. case 1:
  122. // MOVSB
  123. *Code_pointer++ = OPCODE_MOVSB;
  124. ecx = 0;
  125. break;
  126. case 2:
  127. // MOVSW
  128. *Code_pointer++ = OPCODE_16BIT;
  129. *Code_pointer++ = OPCODE_MOVSD;
  130. ecx = 0;
  131. break;
  132. case 3:
  133. // MOVSW, MOVSB
  134. *Code_pointer++ = OPCODE_16BIT;
  135. *Code_pointer++ = OPCODE_MOVSD;
  136. *Code_pointer++ = OPCODE_MOVSB;
  137. ecx = 0;
  138. break;
  139. case 4:
  140. // MOVSD
  141. *Code_pointer++ = OPCODE_MOVSD;
  142. ecx = 0;
  143. break;
  144. default:
  145. blocks = ecx / 4;
  146. if ( blocks == 1 ) {
  147. // MOVSD
  148. *Code_pointer++ = OPCODE_MOVSD;
  149. } else {
  150. // MOV ECX, blocks
  151. *Code_pointer++ = OPCODE_MOV_ECX;
  152. iptr = (int *)Code_pointer;
  153. *iptr++ = blocks;
  154. Code_pointer = (ubyte *)iptr;
  155. // REP MOVSD
  156. *Code_pointer++ = OPCODE_REP;
  157. *Code_pointer++ = OPCODE_MOVSD;
  158. }
  159. ecx -= blocks*4;
  160. }
  161. }
  162. }
  163. //-----------------------------------------------------------------------------------------
  164. // Given bitmap, bmp, finds the size of the code
  165. int gr_ibitblt_find_code_size( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
  166. {
  167. int x,y;
  168. ubyte pixel;
  169. int draw_mode = MODE_NONE;
  170. int source_offset = 0;
  171. int dest_offset = 0;
  172. int num_to_draw, draw_start_source, draw_start_dest;
  173. int esi, edi;
  174. Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
  175. Code_counter = 0;
  176. esi = source_offset = 0;
  177. edi = dest_offset = 0;
  178. draw_start_source = draw_start_dest = 0;
  179. for ( y=sy; y<sy+sh; y++ ) {
  180. for ( x=sx; x<sx+sw; x++ ) {
  181. dest_offset = y*mask_bmp->bm_rowsize+x;
  182. pixel = mask_bmp->bm_data[dest_offset];
  183. if ( pixel!=255 ) {
  184. switch ( draw_mode) {
  185. case MODE_DRAW:
  186. move_and_count( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
  187. esi = draw_start_source + num_to_draw;
  188. edi = draw_start_dest + num_to_draw;
  189. // fall through!!!
  190. case MODE_NONE:
  191. case MODE_SKIP:
  192. break;
  193. }
  194. draw_mode = MODE_SKIP;
  195. } else {
  196. switch ( draw_mode) {
  197. case MODE_SKIP:
  198. case MODE_NONE:
  199. draw_start_source = source_offset;
  200. draw_start_dest = dest_offset;
  201. num_to_draw = 0;
  202. // fall through
  203. case MODE_DRAW:
  204. num_to_draw++;
  205. break;
  206. }
  207. draw_mode = MODE_DRAW;
  208. }
  209. source_offset++;
  210. }
  211. if ( draw_mode == MODE_DRAW ) {
  212. move_and_count( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
  213. esi = draw_start_source + num_to_draw;
  214. edi = draw_start_dest + num_to_draw;
  215. }
  216. draw_mode = MODE_NONE;
  217. source_offset += (srowsize - sw);
  218. }
  219. Code_counter++; // for return
  220. //printf( "Code will be %d bytes\n", Code_counter );
  221. Code_counter += 16; // for safety
  222. return Code_counter;
  223. }
  224. //-----------------------------------------------------------------------------------------
  225. // Given bitmap, bmp, create code that transfers a bitmap of size sw*sh to position
  226. // (sx,sy) on top of bmp, only overwritting transparent pixels of the bitmap.
  227. ubyte *gr_ibitblt_create_mask( grs_bitmap * mask_bmp, int sx, int sy, int sw, int sh, int srowsize )
  228. {
  229. int x,y;
  230. ubyte pixel;
  231. int draw_mode = MODE_NONE;
  232. int source_offset = 0;
  233. int dest_offset = 0;
  234. int num_to_draw, draw_start_source, draw_start_dest;
  235. int esi, edi;
  236. int code_size;
  237. ubyte *code;
  238. Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
  239. code_size = gr_ibitblt_find_code_size( mask_bmp, sx, sy, sw, sh, srowsize );
  240. code = malloc( code_size );
  241. if ( code == NULL )
  242. return NULL;
  243. Code_pointer = code;
  244. esi = source_offset = 0;
  245. edi = dest_offset = 0;
  246. draw_start_source = draw_start_dest = 0;
  247. for ( y=sy; y<sy+sh; y++ ) {
  248. for ( x=sx; x<sx+sw; x++ ) {
  249. dest_offset = y*mask_bmp->bm_rowsize+x;
  250. pixel = mask_bmp->bm_data[dest_offset];
  251. if ( pixel!=255 ) {
  252. switch ( draw_mode) {
  253. case MODE_DRAW:
  254. move_and_draw( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
  255. esi = draw_start_source + num_to_draw;
  256. edi = draw_start_dest + num_to_draw;
  257. // fall through!!!
  258. case MODE_NONE:
  259. case MODE_SKIP:
  260. break;
  261. }
  262. draw_mode = MODE_SKIP;
  263. } else {
  264. switch ( draw_mode) {
  265. case MODE_SKIP:
  266. case MODE_NONE:
  267. draw_start_source = source_offset;
  268. draw_start_dest = dest_offset;
  269. num_to_draw = 0;
  270. // fall through
  271. case MODE_DRAW:
  272. num_to_draw++;
  273. break;
  274. }
  275. draw_mode = MODE_DRAW;
  276. }
  277. source_offset++;
  278. }
  279. if ( draw_mode == MODE_DRAW ) {
  280. move_and_draw( draw_start_source-esi, draw_start_dest-edi, num_to_draw );
  281. esi = draw_start_source + num_to_draw;
  282. edi = draw_start_dest + num_to_draw;
  283. }
  284. draw_mode = MODE_NONE;
  285. source_offset += (srowsize - sw);
  286. }
  287. *Code_pointer++ = OPCODE_RET;
  288. if ( Code_pointer >= &code[code_size-1] )
  289. Error( "ibitblt overwrote allocated code block\n" );
  290. //printf( "Code is %d bytes\n", Code_pointer - code );
  291. return code;
  292. }
  293. void gr_ibitblt_do_asm(char *start_si, char *start_di, ubyte * code);
  294. #pragma aux gr_ibitblt_do_asm parm [esi] [edi] [eax] modify [ecx edi esi eax] = \
  295. "pusha" \
  296. "cld" \
  297. "call eax" \
  298. "popa"
  299. void gr_ibitblt(grs_bitmap * source_bmp, grs_bitmap * dest_bmp, ubyte * mask )
  300. {
  301. if (mask != NULL )
  302. gr_ibitblt_do_asm( source_bmp->bm_data, dest_bmp->bm_data, mask );
  303. }
  304. void gr_ibitblt_find_hole_size( grs_bitmap * mask_bmp, int *minx, int *miny, int *maxx, int *maxy )
  305. {
  306. ubyte c;
  307. int x, y, count=0;
  308. Assert( (!(mask_bmp->bm_flags&BM_FLAG_RLE)) );
  309. *minx = mask_bmp->bm_w-1;
  310. *maxx = 0;
  311. *miny = mask_bmp->bm_h-1;
  312. *maxy = 0;
  313. for ( y=0; y<mask_bmp->bm_h; y++ )
  314. for ( x=0; x<mask_bmp->bm_w; x++ ) {
  315. c = mask_bmp->bm_data[mask_bmp->bm_rowsize*y+x];
  316. if (c == 255 ) {
  317. if ( x < *minx ) *minx = x;
  318. if ( y < *miny ) *miny = y;
  319. if ( x > *maxx ) *maxx = x;
  320. if ( y > *maxy ) *maxy = y;
  321. count++;
  322. }
  323. }
  324. if ( count == 0 ) {
  325. Error( "Bitmap for ibitblt doesn't have transparency!\n" );
  326. }
  327. }
  328.