cm_draw.cpp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // CDraw32 Class Implementation
  3. //
  4. // Basic drawing routines for 32-bit buffer
  5. ///////////////////////////////////////////////////////////////////////////////
  6. #include "../server/exe_headers.h"
  7. #include "cm_local.h"
  8. #include "cm_draw.h"
  9. ///////////// statics for CDraw32 //////////////////////////////////
  10. // Used by all drawing routines as the "current" drawing context
  11. CPixel32* CDraw32::buffer = NULL; // pointer to 32-bit deep pixel buffer
  12. long CDraw32::buf_width=0; // width of buffer in pixels
  13. long CDraw32::buf_height=0; // height of buffer in pixels
  14. long CDraw32::stride = 0; // stride in pixels
  15. long CDraw32::clip_min_x=0; // clip bounds
  16. long CDraw32::clip_min_y=0; // clip bounds
  17. long CDraw32::clip_max_x=0; // clip bounds
  18. long CDraw32::clip_max_y=0; // clip bounds
  19. long* CDraw32::row_off = NULL; // Table for quick Y calculations
  20. CDraw32::CDraw32()
  21. //USE: constructor
  22. {
  23. }
  24. CDraw32::~CDraw32()
  25. //USE: Destructor
  26. {
  27. }
  28. int imgKernel[5][5] =
  29. {
  30. {-1,-1,-1,-1, 0},
  31. {-1,-1,-1, 0, 1},
  32. {-1,-1, 0, 1, 1},
  33. {-1, 0, 1, 1, 1},
  34. { 0, 1, 1, 1, 1}
  35. };
  36. const int KWIDTH = 2;
  37. void CDraw32::Emboss(long dstX, long dstY, long width, long height,
  38. CPixel32* clrImage, long clrX, long clrY, long clrStride)
  39. {
  40. CPixel32 *dst;
  41. CPixel32 *clr;
  42. int x,y,i,j;
  43. int dstNextLine;
  44. int clrNextLine;
  45. assert(buffer != NULL);
  46. BlitClip(dstX, dstY, width, height, clrX, clrY);
  47. if (width < 1 || height < 1)
  48. return;
  49. dst = &buffer[PIXPOS(dstX,dstY,stride)];
  50. clr = &clrImage[PIXPOS(clrX,clrY,clrStride)];
  51. dstNextLine = (stride - width);
  52. clrNextLine = (clrStride - width);
  53. for (y = 0; y < height; y++)
  54. {
  55. for (x = 0; x < width; x++)
  56. {
  57. int accum = 0;
  58. for (j = -KWIDTH; j<=KWIDTH; j++)
  59. for (i = -KWIDTH; i<=KWIDTH; i++)
  60. {
  61. int xk = CLAMP(x + i, clrX, clrX+width-1);
  62. int yk = CLAMP(y + j, clrY, clrY+height-1);
  63. accum += clrImage[PIXPOS(xk,yk,clrStride)].a * imgKernel[j+KWIDTH][i+KWIDTH];
  64. }
  65. *dst = LIGHT_PIX(*clr, accum);
  66. dst->a = 255;
  67. ++dst;
  68. ++clr;
  69. }
  70. dst += dstNextLine;
  71. clr += clrNextLine;
  72. }
  73. }
  74. bool CDraw32::SetBufferSize(long width,long height,long stride_len)
  75. //USE: setup for a particular size drawing buffer
  76. // (do not re-setup if buffer size has not changed)
  77. //IN: width,height - size of buffer
  78. // stride_len - distance to next line
  79. //OUT: true if everything goes OK, otherwise false
  80. {
  81. long i;
  82. assert(width!=0);
  83. assert(height!=0);
  84. assert(stride_len!=0);
  85. if (buf_width != width || buf_height != height ||
  86. stride_len != stride)
  87. { // need to re-create row_off table
  88. buf_width = width;
  89. buf_height = height;
  90. stride = stride_len;
  91. if (row_off)
  92. delete [] row_off;
  93. // row offsets used for quick pixel address calcs
  94. row_off = new long[height];
  95. assert(row_off != NULL);
  96. if (row_off == NULL)
  97. return false;
  98. // table for quick pixel lookups
  99. for (i=0; i<height; i++)
  100. row_off[i] = i * stride;
  101. }
  102. // set default clip bounds
  103. SetClip(0, 0, width-1, height-1);
  104. return true;
  105. }
  106. void CDraw32::ClearLines(CPixel32 color,long start,long end)
  107. //USE: clear screen buffer to color provided for lines
  108. //IN: color - 32-bit color value
  109. // start through end - line numbers
  110. //OUT: none
  111. {
  112. CPixel32 *dest;
  113. int line,i,next_line;
  114. assert(buffer!=NULL);
  115. assert(start>=0);
  116. assert(end<buf_height);
  117. dest = &buffer[row_off[start]];
  118. next_line = stride - buf_width;
  119. line = end - start + 1;
  120. while (line-- != 0)
  121. { // very simple-minded fill loop
  122. i = buf_width;
  123. while (i--)
  124. *dest++ = color;
  125. dest += next_line;
  126. }
  127. }
  128. void CDraw32::SetAlphaLines(byte alpha,long start,long end)
  129. //USE: set the alpha value only
  130. //IN: alpha - 8-bit alpha value
  131. // start through end - line numbers
  132. //OUT: none
  133. {
  134. CPixel32 *dest;
  135. int line,i,next_line;
  136. assert(buffer!=NULL);
  137. assert(start>=0);
  138. assert(end<buf_height);
  139. dest = &buffer[row_off[start]];
  140. next_line = stride - buf_width;
  141. line = end - start + 1;
  142. while (line-- != 0)
  143. { // very simple-minded fill loop
  144. i = buf_width;
  145. while (i--)
  146. {
  147. dest->a = alpha;
  148. ++dest;
  149. }
  150. dest += next_line;
  151. }
  152. }
  153. #define LEFT 1 // code bits
  154. #define RIGHT 2
  155. #define TOP 4
  156. #define BOTTOM 8
  157. static long code(long x,long y)
  158. //USE: determines where a point is in relation to a bounding box
  159. //IN: x,y - coordinate pair
  160. //OUT: clipping code compaired to global clip context
  161. {
  162. long c;
  163. c = 0;
  164. if (x < CDraw32::clip_min_x) c |= LEFT;
  165. if (x > CDraw32::clip_max_x) c |= RIGHT;
  166. if (y < CDraw32::clip_min_y) c |= BOTTOM;
  167. if (y > CDraw32::clip_max_y) c |= TOP;
  168. return c;
  169. }
  170. bool CDraw32::ClipLine(long& x1, long& y1, long& x2, long& y2)
  171. //USE: clip a line from (x1,y1) to (x2,y2) to clip bounds
  172. //IN: (x1,y1)-(x2,y2) line
  173. //OUT: return true if something left to draw, otherwise false
  174. {
  175. long c1,c2,c,x,y,f;
  176. x = x1;
  177. y = y1;
  178. c1 = code(x1,y1); // find where first pt. is
  179. c2 = code(x2,y2); // find where second pt. is
  180. if ((c1 & c2) == 0)
  181. { // the line may be visible
  182. while (c1 | c2)
  183. { // where there is 2D clipping to be done
  184. if (c1 & c2)
  185. {
  186. return false; // if both on same side, quit
  187. }
  188. c = c1;
  189. if (c==0)
  190. {
  191. c = c2; // pick a point
  192. }
  193. if (c & TOP)
  194. {
  195. f = ((clip_max_y-y1) << 15)/(y2-y1);
  196. x = x1 + (((x2-x1)*f + 16384) >> 15);
  197. y = clip_max_y;
  198. }
  199. else if (c & BOTTOM)
  200. {
  201. f = ((clip_min_y-y1) << 15)/(y2-y1);
  202. x = x1 + (((x2-x1)*f + 16384) >> 15);
  203. y = clip_min_y;
  204. }
  205. else if (c & LEFT)
  206. {
  207. f = ((clip_min_x-x1) << 15)/(x2-x1);
  208. y = y1 + (((y2-y1)*f + 16384) >> 15);
  209. x = clip_min_x;
  210. }
  211. else if (c & RIGHT)
  212. {
  213. f = ((clip_max_x-x1) << 15)/(x2-x1);
  214. y = y1 + (((y2-y1)*f + 16384) >> 15);
  215. x = clip_max_x;
  216. }
  217. if (c==c1)
  218. {
  219. x1=x; y1=y; c1=code(x1,y1);
  220. }
  221. else
  222. {
  223. x2=x; y2=y; c2=code(x2,y2);
  224. }
  225. } // while still needs clipping
  226. }
  227. else
  228. { // line not visible
  229. return false;
  230. }
  231. return true;
  232. }
  233. void CDraw32::DrawLineNC(long x1, long y1, long x2, long y2, CPixel32 color)
  234. //USE: draw a line from (x1,y1) to (x2,y2) in color (no clip)
  235. //IN: (x1,y1) - starting coordinate
  236. // (x2,y2) - ending coordinate
  237. // color - 32-bit color value
  238. //OUT: none
  239. {
  240. long d, ax, ay, sx, sy, dx, dy;
  241. CPixel32* dest;
  242. assert(buffer != NULL);
  243. dx = x2-x1;
  244. ax = ABS(dx) << 1;
  245. sx = SIGN(dx);
  246. dy = y2-y1;
  247. ay = ABS(dy) << 1;
  248. sy = SIGN(dy);
  249. if (255 == color.a)
  250. {
  251. if (dy == 0)
  252. { // horz line
  253. if (dx >= 0)
  254. {
  255. dest = &buffer[row_off[y1] + x1];
  256. int i = dx+1;
  257. while (i--)
  258. *dest++ = color;
  259. }
  260. else
  261. {
  262. dest = &buffer[row_off[y1] + x1 + dx];
  263. int i = -dx+1;
  264. while (i--)
  265. *dest++ = color;
  266. }
  267. return;
  268. }
  269. if (dx == 0)
  270. { // vert line
  271. if (dy >= 0)
  272. {
  273. dest = &buffer[row_off[y1] + x1];
  274. dy++;
  275. }
  276. else
  277. {
  278. dest = &buffer[row_off[y2] + x1];
  279. dy = -dy + 1;
  280. }
  281. while (dy-- != 0)
  282. {
  283. *dest = color;
  284. dest += stride;
  285. }
  286. return;
  287. }
  288. }
  289. // bressenham's algorithm
  290. if (ax > ay)
  291. {
  292. d = ay - (ax >> 1);
  293. while(x1 != x2)
  294. {
  295. PutPixAlphaNC(x1,y1,color);
  296. if (d >= 0)
  297. {
  298. y1 += sy;
  299. d -= ax;
  300. }
  301. x1 += sx;
  302. d += ay;
  303. }
  304. }
  305. else
  306. {
  307. d = ax - (ay >> 1);
  308. while(y1 != y2)
  309. {
  310. PutPixAlphaNC(x1,y1,color);
  311. if (d >= 0)
  312. {
  313. x1 += sx;
  314. d -= ay;
  315. }
  316. y1 += sy;
  317. d += ax;
  318. }
  319. }
  320. PutPixAlphaNC(x1,y1,color);
  321. }
  322. void CDraw32::DrawLineAveNC(long x1, long y1, long x2, long y2, CPixel32 color)
  323. //USE: draw a translucent line from (x1,y1) to (x2,y2) in color (no clip)
  324. //IN: (x1,y1) - starting coordinate
  325. // (x2,y2) - ending coordinate
  326. // color - 32-bit color value
  327. //OUT: none
  328. {
  329. long d, ax, ay, sx, sy, dx, dy;
  330. CPixel32* dest;
  331. assert(buffer != NULL);
  332. dx = x2-x1;
  333. ax = ABS(dx) << 1;
  334. sx = SIGN(dx);
  335. dy = y2-y1;
  336. ay = ABS(dy) << 1;
  337. sy = SIGN(dy);
  338. if (dy == 0)
  339. { // horz line
  340. if (dx >= 0)
  341. {
  342. dest = &buffer[row_off[y1] + x1];
  343. int i = dx+1;
  344. while (i--)
  345. *dest++ = AVE_PIX(*dest, color);
  346. }
  347. else
  348. {
  349. dest = &buffer[row_off[y1] + x1 + dx];
  350. int i = -dx+1;
  351. while (i--)
  352. *dest++ = AVE_PIX(*dest, color);
  353. }
  354. return;
  355. }
  356. if (dx == 0)
  357. { // vert line
  358. if (dy >= 0)
  359. {
  360. dest = &buffer[row_off[y1] + x1];
  361. dy++;
  362. }
  363. else
  364. {
  365. dest = &buffer[row_off[y2] + x1];
  366. dy = -dy + 1;
  367. }
  368. while (dy-- != 0)
  369. {
  370. *dest = AVE_PIX(*dest, color);
  371. dest += stride;
  372. }
  373. return;
  374. }
  375. // bressenham's algorithm
  376. if (ax > ay)
  377. {
  378. d = ay - (ax >> 1);
  379. while(x1 != x2)
  380. {
  381. PutPixAveNC(x1,y1,color);
  382. if (d >= 0)
  383. {
  384. y1 += sy;
  385. d -= ax;
  386. }
  387. x1 += sx;
  388. d += ay;
  389. }
  390. }
  391. else
  392. {
  393. d = ax - (ay >> 1);
  394. while(y1 != y2)
  395. {
  396. PutPixAveNC(x1,y1,color);
  397. if (d >= 0)
  398. {
  399. x1 += sx;
  400. d -= ay;
  401. }
  402. y1 += sy;
  403. d += ax;
  404. }
  405. }
  406. PutPixAveNC(x1,y1,color);
  407. }
  408. void CDraw32::DrawLineAANC(long x0, long y0, long x1, long y1, CPixel32 color)
  409. // Wu antialiased line drawer.
  410. //USE: Function to draw an antialiased line from (x0,y0) to (x1,y1), using an
  411. // antialiasing approach published by Xiaolin Wu in the July 1991 issue of
  412. // Computer Graphics (SIGGRAPH proceedings).
  413. //
  414. //IN: (x0,y0),(x1,y1) = line to draw
  415. // color = 32-bit color
  416. //OUT: none
  417. {
  418. assert(buffer != NULL);
  419. // Make sure the line runs top to bottom
  420. if (y0 > y1)
  421. {
  422. SWAP(y0,y1);
  423. SWAP(x0,x1);
  424. }
  425. long DeltaX = x1 - x0;
  426. long DeltaY = y1 - y0;
  427. long XDir;
  428. // Draw the initial pixel, which is always exactly intersected by
  429. // the line and so needs no Alpha
  430. PutPixAlphaNC(x0, y0, color);
  431. if (DeltaX >= 0)
  432. {
  433. XDir = 1;
  434. }
  435. else
  436. {
  437. XDir = -1;
  438. DeltaX = -DeltaX; // make DeltaX positive
  439. }
  440. // Special-case horizontal, vertical, and diagonal lines, which
  441. // require no Alpha because they go right through the center of
  442. // every pixel
  443. if (DeltaY == 0)
  444. { // Horizontal line
  445. while (DeltaX-- != 0)
  446. {
  447. x0 += XDir;
  448. PutPixAlphaNC(x0, y0, color);
  449. }
  450. return;
  451. }
  452. if (DeltaX == 0)
  453. { // Vertical line
  454. do
  455. {
  456. y0++;
  457. PutPixAlphaNC(x0, y0, color);
  458. }
  459. while (--DeltaY != 0);
  460. return;
  461. }
  462. if (DeltaX == DeltaY)
  463. { // Diagonal line
  464. do
  465. {
  466. x0 += XDir;
  467. y0++;
  468. PutPixAlphaNC(x0, y0, color);
  469. }
  470. while (--DeltaY != 0);
  471. return;
  472. }
  473. // Line is not horizontal, diagonal, or vertical
  474. unsigned short ErrorAcc = 0; // initialize the line error accumulator to 0
  475. // # of bits by which to shift ErrorAcc to get intensity level
  476. const unsigned long IntensityShift = 16 - 8;
  477. // Is this an X-major or Y-major line?
  478. if (DeltaY > DeltaX)
  479. {
  480. // Y-major line; calculate 16-bit fixed-point fractional part of a
  481. // pixel that X advances each time Y advances 1 pixel, truncating the
  482. // result so that we won't overrun the endpoint along the X axis
  483. unsigned short ErrorAdj = unsigned short
  484. (((unsigned long) DeltaX << 16) / (unsigned long) DeltaY);
  485. // Draw all pixels other than the first and last
  486. while (--DeltaY)
  487. {
  488. unsigned short ErrorAccTemp = ErrorAcc; // remember currrent accumulated error
  489. ErrorAcc += ErrorAdj; // calculate error for next pixel
  490. if (ErrorAcc <= ErrorAccTemp)
  491. { // The error accumulator turned over, so advance the X coord
  492. x0 += XDir;
  493. }
  494. y0++; // Y-major, so always advance Y
  495. // The IntensityBits most significant bits of ErrorAcc give us the
  496. // intensity Alpha for this pixel, and the complement of the
  497. // Alpha for the paired pixel
  498. unsigned long Alpha = ErrorAcc >> IntensityShift;
  499. unsigned long InvAlpha = 256-Alpha;
  500. PutPixAlphaNC(x0, y0,
  501. ALPHA_PIX(GetPix(x0, y0), color, Alpha, InvAlpha));
  502. PutPixAlphaNC(x0+XDir, y0,
  503. ALPHA_PIX(GetPix(x0+XDir, y0), color, InvAlpha, Alpha));
  504. }
  505. // Draw the final pixel, which is always exactly intersected by the line
  506. // and so needs no Alpha
  507. PutPixAlphaNC(x1, y1, color);
  508. return;
  509. }
  510. // It's an X-major line; calculate 16-bit fixed-point fractional part of a
  511. // pixel that Y advances each time X advances 1 pixel, truncating the
  512. // result to avoid overrunning the endpoint along the X axis
  513. unsigned short ErrorAdj = unsigned short
  514. (((unsigned long) DeltaY << 16) / (unsigned long) DeltaX);
  515. // Draw all pixels other than the first and last
  516. while (--DeltaX)
  517. {
  518. unsigned short ErrorAccTemp = ErrorAcc; // remember currrent accumulated error
  519. ErrorAcc += ErrorAdj; // calculate error for next pixel
  520. if (ErrorAcc <= ErrorAccTemp)
  521. { // The error accumulator turned over, so advance the Y coord
  522. y0++;
  523. }
  524. x0 += XDir; // X-major, so always advance X
  525. // The IntensityBits most significant bits of ErrorAcc give us the
  526. // intensity Alpha for this pixel, and the complement of the
  527. // Alpha for the paired pixel
  528. unsigned long Alpha = ErrorAcc >> IntensityShift;
  529. unsigned long InvAlpha = 256-Alpha;
  530. PutPixAlphaNC(x0, y0,
  531. ALPHA_PIX(GetPix(x0, y0), color, Alpha, InvAlpha));
  532. PutPixAlphaNC(x0, y0+1,
  533. ALPHA_PIX(GetPix(x0, y0+1), color, InvAlpha, Alpha));
  534. }
  535. // Draw the final pixel, which is always exactly intersected by the line
  536. // and so needs no Alpha
  537. PutPixAlphaNC(x1, y1, color);
  538. }
  539. void CDraw32::DrawRectNC(long ulx, long uly, long width, long height, CPixel32 color)
  540. //USE: draw rectangle in solid color, no clipping
  541. //IN: (ulx,uly) - coordinates of upper-left corner of rect
  542. // width, height - dimensions of rectangle
  543. // color - color value
  544. //OUT: none
  545. {
  546. assert(buffer != NULL);
  547. assert(ulx>=0);
  548. assert(uly>=0);
  549. assert(ulx+width<buf_width);
  550. assert(uly+height<buf_height);
  551. if (height < 1 || width < 1)
  552. return;
  553. while (height-- != 0)
  554. {
  555. DrawLineNC(ulx, uly, ulx+width-1, uly, color);
  556. uly++;
  557. }
  558. }
  559. void CDraw32::DrawRect(long ulx, long uly, long width, long height, CPixel32 color)
  560. //USE: draw rectangle in solid color
  561. //IN: (ulx,uly) - coordinates of upper-left corner of rect
  562. // width, height - dimensions of rectangle
  563. // color - color value
  564. //OUT: none
  565. {
  566. assert(buffer != NULL);
  567. if (height < 1 || width < 1)
  568. return;
  569. while (height-- != 0)
  570. {
  571. DrawLine(ulx, uly, ulx+width-1, uly, color);
  572. uly++;
  573. }
  574. }
  575. void CDraw32::DrawRectAve(long ulx, long uly, long width, long height, CPixel32 color)
  576. //USE: draw rectangle in solid color, translucent
  577. //IN: (ulx,uly) - coordinates of upper-left corner of rect
  578. // width, height - dimensions of rectangle
  579. // color - color value
  580. //OUT: none
  581. {
  582. assert(buffer != NULL);
  583. if (height < 1 || width < 1)
  584. return;
  585. while (height-- != 0)
  586. {
  587. DrawLineAve(ulx, uly, ulx+width-1, uly, color);
  588. uly++;
  589. }
  590. }
  591. void CDraw32::DrawBoxNC(long ulx, long uly, long width, long height, CPixel32 color)
  592. //USE: Draw an empty box, no clipping
  593. //IN: (ulx,uly) - coordinates of upper-left corner of box
  594. // width, height - dimensions of box
  595. // color - color value
  596. //OUT: none
  597. {
  598. assert(buffer != NULL);
  599. if (height < 1 || width < 1)
  600. return;
  601. DrawLineNC(ulx, uly, ulx+width-1, uly, color);
  602. DrawLineNC(ulx, uly+height-1, ulx+width-1, uly+height-1, color);
  603. DrawLineNC(ulx, uly, ulx, uly+height-1, color);
  604. DrawLineNC(ulx+width-1, uly, ulx+width-1, uly+height-1, color);
  605. }
  606. void CDraw32::DrawBox(long ulx, long uly, long width, long height, CPixel32 color)
  607. //USE: Draw an empty box
  608. //IN: (ulx,uly) - coordinates of upper-left corner of rect
  609. // width, height - dimensions of rectangle
  610. // color - color value
  611. //OUT: none
  612. {
  613. assert(buffer != NULL);
  614. if (height < 1 || width < 1)
  615. return;
  616. DrawLine(ulx, uly, ulx+width-1, uly, color);
  617. DrawLine(ulx, uly+height-1, ulx+width-1, uly+height-1, color);
  618. DrawLine(ulx, uly, ulx, uly+height-1, color);
  619. DrawLine(ulx+width-1, uly, ulx+width-1, uly+height-1, color);
  620. }
  621. void CDraw32::DrawBoxAve(long ulx, long uly, long width, long height, CPixel32 color)
  622. //USE: Draw an empty box, translucent
  623. //IN: (ulx,uly) - coordinates of upper-left corner of rect
  624. // width, height - dimensions of rectangle
  625. // color - color value
  626. //OUT: none
  627. {
  628. assert(buffer!=NULL);
  629. if (height < 1 || width < 1)
  630. return;
  631. DrawLineAve(ulx, uly, ulx+width-1, uly, color);
  632. DrawLineAve(ulx, uly+height-1, ulx+width-1, uly+height-1, color);
  633. DrawLineAve(ulx, uly, ulx, uly+height-1, color);
  634. DrawLineAve(ulx+width-1, uly, ulx+width-1, uly+height-1, color);
  635. }
  636. void CDraw32::DrawCircle(long xc, long yc, long r, CPixel32 edge, CPixel32 fill)
  637. //USE: Draw a simple circle in current color with Bresenham's
  638. // circle algorithm.
  639. // See PROCEDURAL ELEMENTS FOR COMPUTER GRAPHICS
  640. // David F. Rogers Pg. 48.
  641. //
  642. //IN: xc,yc - center
  643. // r - radius
  644. // edge - edge color
  645. // fill - fill color
  646. //
  647. //OUT: NONE (a circle drawn in the off-screen buffer)
  648. {
  649. long x,y;
  650. long limit,di,delta;
  651. long last_x,last_y;
  652. assert(buffer != NULL);
  653. if (r < 1)
  654. return;
  655. // draw fill
  656. if (fill.a != 0)
  657. {
  658. x = 0; last_x = x;
  659. y = r; last_y = y;
  660. di = 2*(1-r);
  661. limit = 0;
  662. do
  663. {
  664. if (y >= limit)
  665. {
  666. if (di < 0)
  667. {
  668. delta = 2*di + 2*y - 1;
  669. if (delta <= 0)
  670. { // move horizontal
  671. last_x = x;
  672. x++;
  673. di += (2*x + 1);
  674. }
  675. else
  676. { // move diagonal
  677. last_x = x;
  678. x++;
  679. y--;
  680. di += (2*x - 2*y + 2);
  681. }
  682. }
  683. else
  684. {
  685. if (di > 0)
  686. {
  687. delta = 2*di - 2*x -1;
  688. if (delta <= 0)
  689. { // move diagonal
  690. last_x = x;
  691. x++;
  692. y--;
  693. di += (2*x - 2*y + 2);
  694. }
  695. else
  696. { // move vertical
  697. y--;
  698. di += (1 - 2*y);
  699. }
  700. }
  701. else /* di = 0 */
  702. { // move diagonal
  703. last_x = x;
  704. x++;
  705. y--;
  706. di += (2*x - 2*y + 2);
  707. }
  708. }
  709. }
  710. if (y != last_y)
  711. { // circle fill
  712. DrawLine(xc-last_x,yc+last_y,xc+last_x,yc+last_y,fill);
  713. if (last_y > limit)
  714. {
  715. DrawLine(xc-last_x,yc-last_y,xc+last_x,yc-last_y,fill);
  716. }
  717. last_y = y;
  718. }
  719. } while (y >= limit);
  720. }
  721. // draw edge
  722. if (edge.a != 0)
  723. {
  724. x = 0;
  725. y = r;
  726. limit = 0;
  727. di = 2*(1-r);
  728. do
  729. {
  730. // circle edge
  731. PutPix(xc+x, yc+y, edge);
  732. PutPix(xc-x, yc+y, edge);
  733. if (y > limit)
  734. {
  735. PutPix(xc+x, yc-y, edge);
  736. PutPix(xc-x, yc-y, edge);
  737. }
  738. if (y >= limit)
  739. {
  740. if (di < 0)
  741. {
  742. delta = 2*di + 2*y - 1;
  743. if (delta <= 0)
  744. { // move horizontal
  745. x++;
  746. di += (2*x + 1);
  747. }
  748. else
  749. { // move diagonal
  750. x++;
  751. y--;
  752. di += (2*x - 2*y + 2);
  753. }
  754. }
  755. else
  756. {
  757. if (di > 0)
  758. {
  759. delta = 2*di - 2*x -1;
  760. if (delta <= 0)
  761. { // move diagonal
  762. x++;
  763. y--;
  764. di += (2*x - 2*y + 2);
  765. }
  766. else
  767. { // move vertical
  768. y--;
  769. di += (1 - 2*y);
  770. }
  771. }
  772. else /* di = 0 */
  773. { // move diagonal
  774. x++;
  775. y--;
  776. di += (2*x - 2*y + 2);
  777. }
  778. }
  779. }
  780. } while (y >= limit);
  781. }
  782. } // DrawCircle
  783. void CDraw32::DrawCircleAve(long xc, long yc, long r, CPixel32 edge, CPixel32 fill)
  784. //USE: Draw a simple circle in current color with Bresenham's
  785. // circle algorithm.
  786. // a circle with fill and edge colors averaged with dest (-1 = no color)
  787. // See PROCEDURAL ELEMENTS FOR COMPUTER GRAPHICS
  788. // David F. Rogers Pg. 48.
  789. //
  790. //IN: xc,yc - center
  791. // r - radius
  792. // edge - edge color
  793. // fill - fill color
  794. //
  795. //OUT: none (a circle on in the off-screen buffer)
  796. {
  797. long x,y;
  798. long limit,di,delta;
  799. long last_x,last_y;
  800. long f;
  801. assert(buffer != NULL);
  802. if (r < 1)
  803. return;
  804. // draw fill
  805. if (fill.a != 0)
  806. {
  807. x = 0; last_x = x;
  808. y = r; last_y = y;
  809. di = 2*(1-r);
  810. limit = 0;
  811. do
  812. {
  813. if (y >= limit)
  814. {
  815. if (di < 0)
  816. {
  817. delta = 2*di + 2*y - 1;
  818. if (delta <= 0)
  819. { // move horizontal
  820. last_x = x;
  821. x++;
  822. di += (2*x + 1);
  823. }
  824. else
  825. { // move diagonal
  826. last_x = x;
  827. x++;
  828. y--;
  829. di += (2*x - 2*y + 2);
  830. }
  831. }
  832. else
  833. {
  834. if (di > 0)
  835. {
  836. delta = 2*di - 2*x -1;
  837. if (delta <= 0)
  838. { // move diagonal
  839. last_x = x;
  840. x++;
  841. y--;
  842. di += (2*x - 2*y + 2);
  843. }
  844. else
  845. { // move vertical
  846. y--;
  847. di += (1 - 2*y);
  848. }
  849. }
  850. else /* di = 0 */
  851. { // move diagonal
  852. last_x = x;
  853. x++;
  854. y--;
  855. di += (2*x - 2*y + 2);
  856. }
  857. }
  858. }
  859. if (y != last_y)
  860. { // circle fill
  861. for (f=xc-last_x; f<=xc+last_x; f++)
  862. PutPixAve(f, yc+last_y, fill);
  863. if (last_y > limit)
  864. {
  865. for (f=xc-last_x; f<=xc+last_x; f++)
  866. PutPixAve(f, yc-last_y, fill);
  867. }
  868. last_y = y;
  869. }
  870. } while (y >= limit);
  871. }
  872. // draw edge
  873. if (edge.a != 0)
  874. {
  875. x = 0;
  876. y = r;
  877. limit = 0;
  878. di = 2*(1-r);
  879. do
  880. {
  881. // circle edge
  882. PutPixAve(xc+x, yc+y, edge);
  883. PutPixAve(xc-x, yc+y, edge);
  884. if (y > limit)
  885. {
  886. PutPixAve(xc+x, yc-y, edge);
  887. PutPixAve(xc-x, yc-y, edge);
  888. }
  889. if (y >= limit)
  890. {
  891. if (di < 0)
  892. {
  893. delta = 2*di + 2*y - 1;
  894. if (delta <= 0)
  895. { // move horizontal
  896. x++;
  897. di += (2*x + 1);
  898. }
  899. else
  900. { // move diagonal
  901. x++;
  902. y--;
  903. di += (2*x - 2*y + 2);
  904. }
  905. }
  906. else
  907. {
  908. if (di > 0)
  909. {
  910. delta = 2*di - 2*x -1;
  911. if (delta <= 0)
  912. { // move diagonal
  913. x++;
  914. y--;
  915. di += (2*x - 2*y + 2);
  916. }
  917. else
  918. { // move vertical
  919. y--;
  920. di += (1 - 2*y);
  921. }
  922. }
  923. else /* di = 0 */
  924. { // move diagonal
  925. x++;
  926. y--;
  927. di += (2*x - 2*y + 2);
  928. }
  929. }
  930. }
  931. } while (y >= limit);
  932. }
  933. } // DrawCircleAve
  934. ////////////////////////////////////////////////////////////////////////////
  935. //Concave Polygon Scan Conversion
  936. ////////////////////////////////////////////////////////////////////////////
  937. // concave: scan convert nvert-sided concave non-simple polygon
  938. // with vertices at (point[i].x, point[i].y) for i in
  939. // [0..nvert-1] within the window win by
  940. // calling spanproc for each visible span of pixels.
  941. //
  942. // Polygon can be clockwise or counterclockwise.
  943. //
  944. // Algorithm does uniform point sampling at pixel centers.
  945. // Inside-outside test done by even-odd rule: a point is
  946. // considered inside if an emanating ray intersects the polygon
  947. // an odd number of times.
  948. //
  949. // spanproc should fill in pixels from xl to xr inclusive on scanline y,
  950. //
  951. // e.g:
  952. // spanproc(short y, short xl, short xr)
  953. // {
  954. // short x;
  955. // for (x=xl; x<=xr; x++)
  956. // pixel_write(x, y, pixelvalue);
  957. // }
  958. typedef struct
  959. { // a polygon edge
  960. // these are fixed point long ints for some accuracy & speed
  961. long x; // x coordinate of edge's intersection with current scanline
  962. long dx; // change in x with respect to y
  963. long i; // edge number: edge i goes from pt[i] to
  964. // pt[i+1]
  965. } POLYEDGE;
  966. #define INT_SHIFT 13
  967. // global for speed
  968. static long n; // number of vertices
  969. static POINT *pt; // vertices
  970. static long nact; // number of active edges
  971. static POLYEDGE active[256]; // active edge list:edges crossing scanline y
  972. static long ind[256]; // list of vertex indices, sorted by
  973. // pt[ind[j]].y
  974. static void del_edge(long i)
  975. // remove edge i from active list
  976. {
  977. int j;
  978. for (j = 0; j < nact && active[j].i != i; j++)
  979. ;
  980. // edge not in active list; happens at cliprect->top
  981. if (j >= nact)
  982. {
  983. return;
  984. }
  985. nact--;
  986. memcpy(&active[j], &active[j + 1], (nact - j) * sizeof(active[0]));
  987. }
  988. static void ins_edge(long i, long y)
  989. // append edge i to end of active list
  990. {
  991. int j;
  992. long dx;
  993. POINT *p;
  994. POINT *q;
  995. j = i < n - 1 ? i + 1 : 0;
  996. if (pt[i].y < pt[j].y)
  997. {
  998. p = &pt[i];
  999. q = &pt[j];
  1000. }
  1001. else
  1002. {
  1003. p = &pt[j];
  1004. q = &pt[i];
  1005. }
  1006. // initialize x position at intersection of edge with scanline y
  1007. if ((q->y - p->y) != 0)
  1008. {
  1009. dx = (((long)q->x - (long)p->x) * (long)(1<<INT_SHIFT));
  1010. dx /= (((long)q->y - (long)p->y));
  1011. }
  1012. else
  1013. {
  1014. // horizontal line
  1015. dx = 0;
  1016. }
  1017. active[nact].dx = dx;
  1018. active[nact].x = (dx * (long)(y - p->y)) + ((long)p->x << INT_SHIFT);
  1019. active[nact].i = i;
  1020. nact++;
  1021. }
  1022. // comparison routines for shellsort
  1023. int compare_ind(long *u, long *v)
  1024. {
  1025. return (pt[*u].y <= pt[*v].y ? -1 : 1);
  1026. }
  1027. int compare_active(POLYEDGE *u, POLYEDGE *v)
  1028. {
  1029. return (u->x <= v->x ? -1 : 1);
  1030. }
  1031. void shell_sort(void *vec, long n, long siz,
  1032. int (*compare)(void*,void*))
  1033. // USE: shell sort aka heap sort. Best sort algorithm for almost sorted list.
  1034. {
  1035. byte *a;
  1036. byte v[128]; // temp object
  1037. long i,j,h;
  1038. a = (byte *)vec;
  1039. // choose size of "heap"
  1040. for (h = 1; h <= n/9; h = 3*h+1)
  1041. ;
  1042. // divide and conq.
  1043. for ( ; h > 0; h /= 3)
  1044. {
  1045. for (i = h; i < n; i++)
  1046. {
  1047. // v = a[i];
  1048. memcpy(v,(a+i*siz),siz);
  1049. j = i;
  1050. // j >= h && a[j-h] > v
  1051. while ((j >= h) && compare((void*)(a+(j-h)*siz),(void*)v) > 0)
  1052. {
  1053. // a[j] = a[j-h]
  1054. memcpy((a+j*siz),(a+(j-h)*siz),siz);
  1055. j -= h;
  1056. }
  1057. // a[j] = v;
  1058. memcpy((a+j*siz),v,siz);
  1059. }
  1060. }
  1061. }
  1062. void CDraw32::DrawPolygon(long nvert, POINT *point, CPixel32 edge, CPixel32 fill)
  1063. //USE: Scan convert a polygon
  1064. //IN: nvert: Number of vertices
  1065. // point: Vertices of polygon
  1066. // edge: edge color
  1067. // fill: fill color
  1068. //OUT: none
  1069. {
  1070. long k,
  1071. y0,
  1072. y1,
  1073. y,
  1074. i,
  1075. j,
  1076. xl,
  1077. xr;
  1078. assert(buffer != NULL);
  1079. n = nvert;
  1080. if (n <= 0)
  1081. { // nothing to do
  1082. return;
  1083. }
  1084. pt = point;
  1085. if (fill.a != 0)
  1086. { // draw fill
  1087. // create y-sorted array of indices ind[k] into vertex list
  1088. for (k = 0; k < n; k++)
  1089. {
  1090. ind[k] = k;
  1091. }
  1092. // sort ind by pt[ind[k]].y
  1093. shell_sort(ind, n, sizeof(long), (int (*)(void*,void*)) compare_ind);
  1094. nact = 0; // start with empty active list
  1095. k = 0; // ind[k] is next vertex to process
  1096. // ymin of polygon
  1097. y0 = MAX(clip_min_y-1, pt[ind[0]].y);
  1098. // ymax of polygon
  1099. y1 = MIN(clip_max_y+1, pt[ind[n-1]].y);
  1100. // step through scanlines
  1101. for (y = y0; y < y1; y++)
  1102. {
  1103. // Check vertices between previous scanline
  1104. // and current one, if any
  1105. for (; (k < n) && (pt[ind[k]].y <= y); k++)
  1106. {
  1107. i = ind[k];
  1108. // insert or delete edges before and after vertex i
  1109. // (i-1 to i, and i to i+1)
  1110. // from active list if they cross scanline y
  1111. j = i > 0 ? i - 1 : n - 1; // vertex previous to i
  1112. if (pt[j].y < y)
  1113. {
  1114. // old edge, remove from active list
  1115. del_edge(j);
  1116. }
  1117. else
  1118. {
  1119. if (pt[j].y > y)
  1120. {
  1121. // new edge, add to active list
  1122. ins_edge(j, y);
  1123. }
  1124. }
  1125. j = i < n - 1 ? i + 1 : 0; // vertex next after i
  1126. if (pt[j].y < y)
  1127. {
  1128. // old edge, remove from active list
  1129. del_edge(i);
  1130. }
  1131. else
  1132. {
  1133. if (pt[j].y > y)
  1134. {
  1135. // new edge, add to active list
  1136. ins_edge(i, y);
  1137. }
  1138. }
  1139. }
  1140. // sort active edge list by active[j].x
  1141. shell_sort(active, nact, sizeof(POLYEDGE), (int (*)(void*,void*))compare_active);
  1142. // draw horizontal segments for scanline y
  1143. for (j = 0; j < nact; j += 2)
  1144. { // draw horizontal segments
  1145. // span 'tween j & j+1 is inside, span tween
  1146. // j+1 & j+2 is outside
  1147. // left end of span
  1148. // convert back from fixed point - round down
  1149. xl = (long) (active[j].x >> INT_SHIFT);
  1150. if (xl < clip_min_x-1)
  1151. {
  1152. xl = clip_min_x-1;
  1153. }
  1154. // right end of span
  1155. // convert back from fixed point - round down
  1156. xr = (long) (active[j + 1].x >> INT_SHIFT);
  1157. if (xr > clip_max_x)
  1158. {
  1159. xr = clip_max_x;
  1160. }
  1161. if (xl < xr)
  1162. {
  1163. // draw pixels in span
  1164. DrawLine(xl+1,y,xr,y,fill);
  1165. }
  1166. // increment edge coords
  1167. active[j].x += active[j].dx;
  1168. active[j + 1].x += active[j + 1].dx;
  1169. }
  1170. }
  1171. // sort active edge list by active[j].x
  1172. shell_sort(active, nact, sizeof(POLYEDGE), (int (*)(void*,void*))compare_active);
  1173. // draw horizontal segments for scanline y
  1174. for (j = 0; j < nact; j += 2)
  1175. { // draw horizontal segments
  1176. // span 'tween j & j+1 is inside, span tween
  1177. // j+1 & j+2 is outside
  1178. // left end of span
  1179. // convert back from fixed point - round down
  1180. xl = (long) (active[j].x >> INT_SHIFT);
  1181. if (xl < clip_min_x-1)
  1182. {
  1183. xl = clip_min_x-1;
  1184. }
  1185. // right end of span
  1186. // convert back from fixed point - round up
  1187. xr = (long) (active[j + 1].x >> INT_SHIFT);
  1188. if (xr > clip_max_x)
  1189. {
  1190. xr = clip_max_x;
  1191. }
  1192. if (xl < xr)
  1193. {
  1194. // draw pixels in span
  1195. DrawLine(xl+1,y,xr,y,fill);
  1196. }
  1197. // increment edge coords
  1198. active[j].x += active[j].dx;
  1199. active[j + 1].x += active[j + 1].dx;
  1200. }
  1201. }
  1202. if (edge.a != 0)
  1203. { // draw edges
  1204. for (k = 0; k < n-1; k++)
  1205. {
  1206. DrawLineAA(pt[k].x,pt[k].y,pt[k+1].x,pt[k+1].y,edge);
  1207. }
  1208. DrawLineAA(pt[n-1].x,pt[n-1].y,pt[0].x,pt[0].y,edge);
  1209. }
  1210. return;
  1211. }
  1212. void CDraw32::Blit(long dstX, long dstY, long width, long height,
  1213. CPixel32* srcImage, long srcX, long srcY, long srcStride)
  1214. //USE: simple blit
  1215. //IN: dstX, dstY - upper left corner of where image will land in buffer
  1216. // width, height - width and height of image
  1217. // srcImage - src image buffer
  1218. // srcX, srcY - upper left corner in src image
  1219. // srcStride - number of pixels per line in src image
  1220. //OUT: none
  1221. {
  1222. CPixel32 *dst;
  1223. CPixel32 *src;
  1224. int x,y;
  1225. assert(buffer != NULL);
  1226. BlitClip(dstX, dstY, width, height, srcX, srcY);
  1227. if (width < 1 || height < 1)
  1228. return;
  1229. dst = &buffer[PIXPOS(dstX,dstY,stride)];
  1230. src = &srcImage[PIXPOS(srcX,srcY,srcStride)];
  1231. for (y = 0; y < height; y++)
  1232. {
  1233. for (x = 0; x < width; x++)
  1234. {
  1235. // *dst++ = *src++;
  1236. byte alpha = src->a;
  1237. byte dst_alpha = dst->a;
  1238. *dst = ALPHA_PIX(*src, *dst, alpha, 256-alpha);
  1239. dst->a = dst_alpha;
  1240. ++dst;
  1241. ++src;
  1242. }
  1243. dst += (stride - width);
  1244. src += (srcStride - width);
  1245. }
  1246. }
  1247. void CDraw32::BlitClip(long& dstX, long& dstY,
  1248. long& width, long& height,
  1249. long& srcX, long& srcY)
  1250. //USE: simple blit clip
  1251. //IN: dstX, dstY - upper left corner of where image will land in buffer
  1252. // width, height - width and height of image
  1253. // srcX, srcY - upper left corner in src image
  1254. //OUT: none
  1255. {
  1256. // clip to our buffer size
  1257. if (dstX < clip_min_x)
  1258. {
  1259. int dif = (clip_min_x - dstX);
  1260. dstX += dif;
  1261. srcX += dif;
  1262. width -= dif;
  1263. }
  1264. if (dstY < clip_min_y)
  1265. {
  1266. int dif = (clip_min_y - dstY);
  1267. dstY += dif;
  1268. srcY += dif;
  1269. height -= dif;
  1270. }
  1271. if (dstX+width-1 > clip_max_x)
  1272. {
  1273. width -= (dstX+width-1 - clip_max_x);
  1274. }
  1275. if (dstY+height-1 > clip_max_y)
  1276. {
  1277. height -= (dstY+height-1 - clip_max_y);
  1278. }
  1279. }
  1280. void CDraw32::BlitColor(long dstX, long dstY, long width, long height,
  1281. CPixel32* srcImage, long srcX, long srcY, long srcStride, CPixel32 color)
  1282. //USE: blit using image alpha as mask
  1283. //IN: dstX, dstY - upper left corner of where image will land in buffer
  1284. // width, height - width and height of image
  1285. // srcImage - src image buffer
  1286. // srcX, srcY - upper left corner in src image
  1287. // srcStride - number of pixels per line in src image
  1288. // color - color to apply to srcImage
  1289. //OUT: none
  1290. {
  1291. CPixel32 *dst;
  1292. CPixel32 *src;
  1293. int x,y;
  1294. int dstNextLine;
  1295. int srcNextLine;
  1296. assert(buffer != NULL);
  1297. BlitClip(dstX, dstY, width, height, srcX, srcY);
  1298. if (width < 1 || height < 1)
  1299. return;
  1300. dst = &buffer[PIXPOS(dstX,dstY,stride)];
  1301. src = &srcImage[PIXPOS(srcX,srcY,srcStride)];
  1302. dstNextLine = (stride - width);
  1303. srcNextLine = (srcStride - width);
  1304. for (y = 0; y < height; y++)
  1305. {
  1306. for (x = 0; x < width; x++)
  1307. {
  1308. byte alpha = src->a;
  1309. *dst = ALPHA_PIX(color, *dst, alpha, 256-alpha);
  1310. ++dst;
  1311. ++src;
  1312. }
  1313. dst += dstNextLine;
  1314. src += srcNextLine;
  1315. }
  1316. }