gxcanvas.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. #include "std.h"
  2. #include "gxcanvas.h"
  3. #include "gxgraphics.h"
  4. #include "gxruntime.h"
  5. #include "asmcoder.h"
  6. #define DEBUG_BITMASK
  7. static int canvas_cnt;
  8. static DDBLTFX bltfx={sizeof(DDBLTFX)};
  9. extern gxRuntime *gx_runtime;
  10. static unsigned FWMS[]={
  11. 0xffffffff,0x7fffffff,0x3fffffff,0x1fffffff,
  12. 0x0fffffff,0x07ffffff,0x03ffffff,0x01ffffff,
  13. 0x00ffffff,0x007fffff,0x003fffff,0x001fffff,
  14. 0x000fffff,0x0007ffff,0x0003ffff,0x0001ffff,
  15. 0x0000ffff,0x00007fff,0x00003fff,0x00001fff,
  16. 0x00000fff,0x000007ff,0x000003ff,0x000001ff,
  17. 0x000000ff,0x0000007f,0x0000003f,0x0000001f,
  18. 0x0000000f,0x00000007,0x00000003,0x00000001};
  19. static unsigned LWMS[]={
  20. 0x80000000,0xc0000000,0xe0000000,0xf0000000,
  21. 0xf8000000,0xfc000000,0xfe000000,0xff000000,
  22. 0xff800000,0xffc00000,0xffe00000,0xfff00000,
  23. 0xfff80000,0xfffc0000,0xfffe0000,0xffff0000,
  24. 0xffff8000,0xffffc000,0xffffe000,0xfffff000,
  25. 0xfffff800,0xfffffc00,0xfffffe00,0xffffff00,
  26. 0xffffff80,0xffffffc0,0xffffffe0,0xfffffff0,
  27. 0xfffffff8,0xfffffffc,0xfffffffe,0xffffffff};
  28. static void calcShifts( unsigned mask,unsigned char *shr,unsigned char *shl ){
  29. if( mask ){
  30. for( *shl=0;!(mask&1);++*shl,mask>>=1 ){}
  31. for( *shr=8;mask&1;--*shr,mask>>=1 ){}
  32. }else *shr=*shl=0;
  33. }
  34. struct Rect : public RECT{
  35. Rect(){
  36. }
  37. Rect( int x,int y,int w,int h ){
  38. left=x;top=y;right=x+w;bottom=y+h;
  39. }
  40. };
  41. static bool clip( const RECT &viewport,RECT *d ){
  42. if( d->right<=d->left ||
  43. d->bottom<=d->top ||
  44. d->left>=viewport.right ||
  45. d->right<=viewport.left ||
  46. d->top>=viewport.bottom ||
  47. d->bottom<=viewport.top ) return false;
  48. if( d->left<viewport.left ) d->left=viewport.left;
  49. if( d->right>viewport.right ) d->right=viewport.right;
  50. if( d->top<viewport.top ) d->top=viewport.top;
  51. if( d->bottom>viewport.bottom ) d->bottom=viewport.bottom;
  52. return true;
  53. }
  54. static bool clip( const RECT &viewport,RECT *d,RECT *s ){
  55. if( d->right<=d->left ||
  56. d->bottom<=d->top ||
  57. d->left>=viewport.right ||
  58. d->right<=viewport.left ||
  59. d->top>=viewport.bottom ||
  60. d->bottom<=viewport.top ) return false;
  61. int dx,dy;
  62. if( (dx=viewport.left-d->left)>0 ){ d->left+=dx;s->left+=dx; }
  63. if( (dx=viewport.right-d->right)<0 ){ d->right+=dx;s->right+=dx; }
  64. if( (dy=viewport.top-d->top)>0 ){ d->top+=dy;s->top+=dy; }
  65. if( (dy=viewport.bottom-d->bottom)<0 ){ d->bottom+=dy;s->bottom+=dy; }
  66. return true;
  67. }
  68. gxCanvas::gxCanvas( gxGraphics *g,IDirectDrawSurface7 *s,int f ):
  69. graphics(g),main_surf(s),surf(0),z_surf(0),flags(f),cube_mode(CUBEMODE_REFLECTION|CUBESPACE_WORLD),
  70. t_surf(0),cm_mask(0),locked_cnt(0),mod_cnt(0),remip_cnt(0){
  71. if( flags & CANVAS_TEX_CUBE ){
  72. cube_surfs[2]=main_surf;
  73. for( int k=0;k<6;++k ){
  74. if( k==2 ) continue;
  75. DWORD n;
  76. switch( k ){
  77. case 0:n=DDSCAPS2_CUBEMAP_NEGATIVEX;break;
  78. case 1:n=DDSCAPS2_CUBEMAP_POSITIVEZ;break;
  79. case 2:n=DDSCAPS2_CUBEMAP_POSITIVEX;break;
  80. case 3:n=DDSCAPS2_CUBEMAP_NEGATIVEZ;break;
  81. case 4:n=DDSCAPS2_CUBEMAP_POSITIVEY;break;
  82. case 5:n=DDSCAPS2_CUBEMAP_NEGATIVEY;break;
  83. default:return;
  84. }
  85. DDSCAPS2 caps={0};
  86. caps.dwCaps2=DDSCAPS2_CUBEMAP|n;
  87. main_surf->GetAttachedSurface( &caps,&cube_surfs[k] );
  88. }
  89. surf=cube_surfs[1];
  90. }else{
  91. surf=main_surf;
  92. memset( cube_surfs,0,sizeof(cube_surfs) );
  93. }
  94. DDSURFACEDESC2 desc={sizeof(desc)};
  95. surf->GetSurfaceDesc( &desc );
  96. format.setFormat( desc.ddpfPixelFormat );
  97. clip_rect.left=clip_rect.top=0;
  98. clip_rect.right=desc.dwWidth;
  99. clip_rect.bottom=desc.dwHeight;
  100. cm_pitch=(clip_rect.right+31)/32+1;
  101. setMask( 0 );
  102. setColor( ~0 );
  103. setClsColor( 0 );
  104. setOrigin( 0,0 );
  105. setHandle( 0,0 );
  106. setFont( graphics->getDefaultFont() );
  107. setViewport( 0,0,getWidth(),getHeight() );
  108. if( flags & gxCanvas::CANVAS_TEXTURE ) ddUtil::buildMipMaps( surf );
  109. }
  110. gxCanvas::~gxCanvas(){
  111. delete[] cm_mask;
  112. if( locked_cnt ) surf->Unlock( 0 );
  113. if( t_surf ) t_surf->Release();
  114. releaseZBuffer();
  115. main_surf->Release();
  116. }
  117. void gxCanvas::backup()const{
  118. if( flags & CANVAS_TEX_CUBE ) return;
  119. if( !t_surf ){
  120. DDSURFACEDESC2 desc={sizeof(desc)};
  121. if( surf->GetSurfaceDesc(&desc)<0 ) return;
  122. if( desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) return;
  123. DDSURFACEDESC2 t_desc={sizeof(t_desc)};
  124. t_desc.dwFlags=DDSD_CAPS|DDSD_PIXELFORMAT|DDSD_WIDTH|DDSD_HEIGHT;
  125. t_desc.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY;
  126. t_desc.dwWidth=desc.dwWidth;t_desc.dwHeight=desc.dwHeight;
  127. t_desc.ddpfPixelFormat=desc.ddpfPixelFormat;
  128. if( graphics->dirDraw->CreateSurface( &t_desc,&t_surf,0 )<0 ){
  129. t_surf=0;
  130. return;
  131. }
  132. }
  133. if( t_surf->Blt( 0,surf,0,DDBLT_WAIT,0 )<0 ) return;
  134. }
  135. void gxCanvas::restore()const{
  136. if( !t_surf ) return;
  137. if( surf->Blt( 0,t_surf,0,DDBLT_WAIT,0 )<0 ) return;
  138. }
  139. ddSurf *gxCanvas::getSurface()const{
  140. return surf;
  141. }
  142. ddSurf *gxCanvas::getTexSurface()const{
  143. if( mod_cnt==remip_cnt ) return main_surf;
  144. ddUtil::buildMipMaps( surf );
  145. remip_cnt=mod_cnt;
  146. return main_surf;
  147. }
  148. bool gxCanvas::clip( RECT *d )const{
  149. return ::clip( viewport,d );
  150. }
  151. bool gxCanvas::clip( RECT *d,RECT *s )const{
  152. return ::clip( viewport,d,s );
  153. }
  154. void gxCanvas::updateBitMask( const RECT &r )const{
  155. int w=r.right-r.left;if( w<=0 ) return;
  156. int h=r.bottom-r.top;if( h<=0 ) return;
  157. lock();
  158. RECT t=r;
  159. t.left&=~31;
  160. t.right=(t.right+31)&~31;
  161. w=(t.right-t.left)/32;
  162. unsigned char *src_row=locked_surf+t.top*locked_pitch+t.left*format.getPitch();
  163. unsigned *dest_row=cm_mask+t.top*cm_pitch+t.left/32;
  164. unsigned mask_argb=format.toARGB( mask_surf ) & 0xffffff;
  165. #ifdef DEBUG_BITMASK
  166. unsigned *cm_mask_end=cm_mask+cm_pitch*clip_rect.bottom;
  167. #endif
  168. while( h-- ){
  169. unsigned *dest=dest_row;
  170. unsigned char *src=src_row;
  171. for( int c=0;c<w;++c ){
  172. unsigned mask=0;
  173. for( int x=0;x<32;++x ){
  174. unsigned pix=format.getPixel(src) & 0xffffff;
  175. mask=(mask<<1)|(pix!=mask_argb);
  176. src+=format.getPitch();
  177. }
  178. #ifdef DEBUG_BITMASK
  179. if( dest<cm_mask || dest>=cm_mask_end ){
  180. gx_runtime->debugError( "gxCanvas::updateBitMask dest out of range" );
  181. }
  182. #endif
  183. *dest++=mask;
  184. }
  185. dest_row+=cm_pitch;
  186. src_row+=locked_pitch;
  187. }
  188. unlock();
  189. }
  190. void gxCanvas::setModify( int n ){
  191. mod_cnt=n;
  192. }
  193. int gxCanvas::getModify()const{
  194. return mod_cnt;
  195. }
  196. bool gxCanvas::attachZBuffer(){
  197. if( z_surf ) return true;
  198. DDSURFACEDESC2 desc={sizeof(desc)};
  199. desc.dwFlags=DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_PIXELFORMAT;
  200. desc.dwWidth=getWidth();
  201. desc.dwHeight=getHeight();
  202. desc.ddsCaps.dwCaps=DDSCAPS_ZBUFFER|DDSCAPS_VIDEOMEMORY;
  203. desc.ddpfPixelFormat=graphics->zbuffFmt;
  204. if( graphics->dirDraw->CreateSurface( &desc,&z_surf,0 )<0 ) return false;
  205. surf->AddAttachedSurface( z_surf );
  206. return true;
  207. }
  208. void gxCanvas::releaseZBuffer(){
  209. if( !z_surf ) return;
  210. surf->DeleteAttachedSurface( 0,z_surf );
  211. z_surf->Release();
  212. z_surf=0;
  213. }
  214. void gxCanvas::damage( const RECT &r )const{
  215. ++mod_cnt;if( cm_mask ) updateBitMask( r );
  216. }
  217. void gxCanvas::setFont( gxFont *f ){
  218. font=f;
  219. }
  220. void gxCanvas::setMask( unsigned argb ){
  221. mask_surf=format.fromARGB( argb );
  222. }
  223. void gxCanvas::setColor( unsigned argb ){
  224. argb|=0xff000000;
  225. color_argb=argb;
  226. color_surf=format.fromARGB( argb );
  227. }
  228. void gxCanvas::setClsColor( unsigned argb ){
  229. argb|=0xff000000;
  230. clsColor_surf=format.fromARGB( argb );
  231. }
  232. void gxCanvas::setOrigin( int x,int y ){
  233. origin_x=x;origin_y=y;
  234. }
  235. void gxCanvas::setHandle( int x,int y ){
  236. handle_x=x;handle_y=y;
  237. }
  238. void gxCanvas::setViewport( int x,int y,int w,int h ){
  239. Rect r( x,y,w,h );
  240. if( !::clip( clip_rect,&r ) ) r=Rect(0,0,0,0);
  241. viewport=r;
  242. }
  243. //renderering primitives
  244. void gxCanvas::cls(){
  245. bltfx.dwFillColor=clsColor_surf;
  246. surf->Blt( &viewport,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
  247. damage( viewport );
  248. }
  249. void gxCanvas::plot( int x,int y ){
  250. x+=origin_x;if( x<viewport.left || x>=viewport.right ) return;
  251. y+=origin_y;if( y<viewport.top || y>=viewport.bottom ) return;
  252. bltfx.dwFillColor=color_surf;
  253. Rect dest( x,y,1,1 );
  254. surf->Blt( &dest,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
  255. damage( dest );
  256. }
  257. void gxCanvas::line( int x0,int y0,int x1,int y1 ){
  258. int ddf,padj,sadj;
  259. int dx,dy,sx,sy,ax,ay;
  260. x0+=origin_x;y0+=origin_y;
  261. x1+=origin_x;y1+=origin_y;
  262. int cx0,cx1,cy0,cy1,clip0,clip1;
  263. cx0=viewport.left;
  264. cx1=viewport.right-1;
  265. cy0=viewport.top;
  266. cy1=viewport.bottom-1;
  267. while( true ){
  268. clip0=0;clip1=0;
  269. if(y0>cy1)clip0|=1;else if(y0<cy0)clip0|=2;
  270. if(x0>cx1)clip0|=4;else if(x0<cx0)clip0|=8;
  271. if(y1>cy1)clip1|=1;else if(y1<cy0)clip1|=2;
  272. if(x1>cx1)clip1|=4;else if(x1<cx0)clip1|=8;
  273. if((clip0|clip1)==0) break; //draw line
  274. if((clip0&clip1)!=0) return; //outside
  275. if((clip0&1)==1) {x0=x0+((x1-x0)*(cy1-y0))/(y1-y0);y0=cy1;continue;}
  276. if((clip0&2)==2) {x0=x0+((x1-x0)*(cy0-y0))/(y1-y0);y0=cy0;continue;}
  277. if((clip0&4)==4) {y0=y0+((y1-y0)*(cx1-x0))/(x1-x0);x0=cx1;continue;}
  278. if((clip0&8)==8) {y0=y0+((y1-y0)*(cx0-x0))/(x1-x0);x0=cx0;continue;}
  279. if((clip1&1)==1) {x1=x0+((x1-x0)*(cy1-y0))/(y1-y0);y1=cy1;continue;}
  280. if((clip1&2)==2) {x1=x0+((x1-x0)*(cy0-y0))/(y1-y0);y1=cy0;continue;}
  281. if((clip1&4)==4) {y1=y0+((y1-y0)*(cx1-x0))/(x1-x0);x1=cx1;continue;}
  282. if((clip1&8)==8) {y1=y0+((y1-y0)*(cx0-x0))/(x1-x0);x1=cx0;continue;}
  283. }
  284. dx=x1-x0;dy=y1-y0;
  285. if( (dx|dy)==0 ){
  286. setPixel( x0,y0,color_argb );
  287. return;
  288. }
  289. if (dx>=0) {sx=1;ax=dx;} else {sx=-1;ax=-dx;}
  290. if (dy>=0) {sy=1;ay=dy;} else {sy=-1;ay=-dy;}
  291. lock();
  292. if( ax>ay ){
  293. ddf=-ax;sadj=ax+ax;padj=ay+ay;
  294. while( ax-->=0 ){
  295. setPixelFast( x0,y0,color_argb );
  296. x0+=sx;ddf+=padj;if( ddf>=0 ){ y0+=sy;ddf-=sadj; }
  297. }
  298. }else{
  299. ddf=-ay;sadj=ay+ay;padj=ax+ax;
  300. while( ay-->=0 ){
  301. setPixelFast( x0,y0,color_argb );
  302. y0+=sy;ddf+=padj;if( ddf>=0 ){ x0+=sx;ddf-=sadj; }
  303. }
  304. }
  305. unlock();
  306. }
  307. void gxCanvas::rect( int x,int y,int w,int h,bool solid ){
  308. x+=origin_x;y+=origin_y;
  309. Rect dest( x,y,w,h );
  310. if( !clip( &dest ) ) return;
  311. bltfx.dwFillColor=color_surf;
  312. if( solid ){
  313. surf->Blt( &dest,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
  314. damage( dest );
  315. return;
  316. }
  317. Rect r1( x,y,w,1 );if( clip( &r1 ) ){
  318. surf->Blt( &r1,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
  319. }
  320. Rect r2( x,y,1,h );if( clip( &r2 ) ){
  321. surf->Blt( &r2,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
  322. }
  323. Rect r3( x+w-1,y,1,h );if( clip( &r3 ) ){
  324. surf->Blt( &r3,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
  325. }
  326. Rect r4( x,y+h-1,w,1 );if( clip( &r4 ) ){
  327. surf->Blt( &r4,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
  328. }
  329. damage( dest );
  330. }
  331. void gxCanvas::oval( int x1,int y1,int w,int h,bool solid ){
  332. x1+=origin_x;y1+=origin_y;
  333. Rect dest( x1,y1,w,h );
  334. if( !clip( &dest ) ) return;
  335. bltfx.dwFillColor=color_surf;
  336. float xr=w*.5f,yr=h*.5f,ar=(float)w/(float)h;
  337. float cx=x1+xr+.5f,cy=y1+yr-.5f,rsq=yr*yr,y;
  338. if( solid ){
  339. y=dest.top-cy;
  340. for( int t=dest.top;t<dest.bottom;++y,++t ){
  341. float x=sqrt( rsq-y*y )*ar;
  342. int xa=floor( cx-x ),xb=floor( cx+x );
  343. if( xb<=xa || xa>=viewport.right || xb<=viewport.left ) continue;
  344. Rect dr;dr.top=t;dr.bottom=t+1;
  345. dr.left=xa<viewport.left ? viewport.left : xa;
  346. dr.right=xb>viewport.right ? viewport.right : xb;
  347. surf->Blt( &dr,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
  348. }
  349. damage( dest );
  350. return;
  351. }
  352. int p_xa,p_xb,t,hh=floor(cy);
  353. p_xa=p_xb=cx;
  354. t=dest.top;y=t-cy;
  355. if( dest.top>y1 ){ --t;--y; }
  356. for( ;t<=hh;++y,++t ){
  357. float x=sqrt( rsq-y*y )*ar;
  358. int xa=floor( cx-x ),xb=floor( cx+x );
  359. Rect r1( xa,t,p_xa-xa,1 );if( r1.right<=r1.left ) r1.right=r1.left+1;
  360. if( clip( &r1 ) ) surf->Blt( &r1,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
  361. Rect r2( p_xb,t,xb-p_xb,1 );if( r2.left>=r2.right ) r2.left=r2.right-1;
  362. if( clip( &r2 ) ) surf->Blt( &r2,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
  363. p_xa=xa;p_xb=xb;
  364. }
  365. p_xa=p_xb=cx;
  366. t=dest.bottom-1;y=t-cy;
  367. if( dest.bottom<y1+h ){ ++t;++y; }
  368. for( ;t>hh;--y,--t ){
  369. float x=sqrt( rsq-y*y )*ar;
  370. int xa=floor( cx-x ),xb=floor( cx+x );
  371. Rect r1( xa,t,p_xa-xa,1 );if( r1.right<=r1.left ) r1.right=r1.left+1;
  372. if( clip( &r1 ) ) surf->Blt( &r1,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
  373. Rect r2( p_xb,t,xb-p_xb,1 );if( r2.left>=r2.right ) r2.left=r2.right-1;
  374. if( clip( &r2 ) ) surf->Blt( &r2,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
  375. p_xa=xa;p_xb=xb;
  376. }
  377. damage( dest );
  378. }
  379. void gxCanvas::blit( int x,int y,gxCanvas *src,int src_x,int src_y,int src_w,int src_h,bool solid ){
  380. x+=origin_x-src->handle_x;
  381. y+=origin_y-src->handle_y;
  382. Rect dest_r( x,y,src_w,src_h ),src_r( src_x,src_y,src_w,src_h );
  383. if( !clip( &dest_r,&src_r ) ) return;
  384. if( !::clip( src->clip_rect,&src_r,&dest_r ) ) return;
  385. if( solid ){
  386. surf->Blt( &dest_r,src->surf,&src_r,DDBLT_WAIT,0 );
  387. }else{
  388. bltfx.ddckSrcColorkey.dwColorSpaceLowValue=
  389. bltfx.ddckSrcColorkey.dwColorSpaceHighValue=src->mask_surf;
  390. surf->Blt( &dest_r,src->surf,&src_r,DDBLT_WAIT|DDBLT_KEYSRCOVERRIDE,&bltfx );
  391. }
  392. damage( dest_r );
  393. }
  394. void gxCanvas::text( int x,int y,const string &t ){
  395. int ty=y+origin_y;
  396. if( ty>=viewport.bottom ) return;
  397. if( ty+font->getHeight()<=viewport.top ) return;
  398. int tx=x+origin_x;
  399. if( tx>=viewport.right ) return;
  400. int b=0,w;
  401. while( b<t.size() && tx+(w=font->charWidth( t[b] ))<=viewport.left ){
  402. tx+=w;x+=w;++b;
  403. }
  404. int e=b;
  405. while( e<t.size() && tx<viewport.right ){
  406. tx+=font->charWidth( t[e] );++e;
  407. }
  408. if( e>b ) font->render( this,format.toARGB( color_surf ),x,y,t.substr( b,e-b ) );
  409. }
  410. int gxCanvas::getWidth()const{
  411. return clip_rect.right;
  412. }
  413. int gxCanvas::getHeight()const{
  414. return clip_rect.bottom;
  415. }
  416. int gxCanvas::getDepth()const{
  417. return format.getDepth();
  418. }
  419. void gxCanvas::getOrigin( int *x,int *y )const{
  420. *x=origin_x;*y=origin_y;
  421. }
  422. void gxCanvas::getHandle( int *x,int *y )const{
  423. *x=handle_x;*y=handle_y;
  424. }
  425. void gxCanvas::getViewport( int *x,int *y,int *w,int *h )const{
  426. *x=viewport.left;*y=viewport.top;
  427. *w=viewport.right-viewport.left;*h=viewport.bottom-viewport.top;
  428. }
  429. unsigned gxCanvas::getMask()const{
  430. return format.toARGB( mask_surf );
  431. }
  432. unsigned gxCanvas::getColor()const{
  433. return format.toARGB( color_surf );
  434. }
  435. unsigned gxCanvas::getClsColor()const{
  436. return format.toARGB( clsColor_surf );
  437. }
  438. bool gxCanvas::collide( int x1,int y1,const gxCanvas *i2,int x2,int y2,bool solid )const{
  439. x1-=handle_x;x2-=i2->handle_x;
  440. if( x1+clip_rect.right<=x2 || x1>=x2+i2->clip_rect.right ) return false;
  441. y1-=handle_y;y2-=i2->handle_y;
  442. if( y1+clip_rect.bottom<=y2 || y1>=y2+i2->clip_rect.bottom ) return false;
  443. if( solid ) return true;
  444. if( !cm_mask ){
  445. cm_mask=d_new unsigned[cm_pitch*clip_rect.bottom];
  446. updateBitMask( clip_rect );
  447. }
  448. if( !i2->cm_mask ){
  449. i2->cm_mask=d_new unsigned[i2->cm_pitch*i2->clip_rect.bottom];
  450. i2->updateBitMask( i2->clip_rect );
  451. }
  452. const gxCanvas *i1=this;
  453. //to keep me sane!
  454. if( x1>x2 ){
  455. std::swap( x1,x2 );
  456. std::swap( y1,y2 );
  457. std::swap( i1,i2 );
  458. }
  459. Rect r1,r2,ir;
  460. r1.left=x1;r1.top=y1;r1.right=x1+i1->clip_rect.right;r1.bottom=y1+i1->clip_rect.bottom;
  461. r2.left=x2;r2.top=y2;r2.right=x2+i2->clip_rect.right;r2.bottom=y2+i2->clip_rect.bottom;
  462. ir.left=r1.left>r2.left ? r1.left : r2.left;
  463. ir.right=r1.right<r2.right ? r1.right : r2.right;
  464. ir.top=r1.top>r2.top ? r1.top : r2.top;
  465. ir.bottom=r1.bottom<r2.bottom ? r1.bottom : r2.bottom;
  466. unsigned *s1=i1->cm_mask,*s2=i2->cm_mask;
  467. int i1_pitch=i1->cm_pitch,i2_pitch=i2->cm_pitch;
  468. s1+=(ir.top-r1.top)*i1_pitch;
  469. s2+=(ir.top-r2.top)*i2_pitch;
  470. int startx=ir.left-r1.left;
  471. int stopx=ir.right-r1.left-1;
  472. int shr=startx&31;
  473. int shl=32-shr;
  474. int cnt=stopx/32-startx/32;
  475. unsigned lwm=LWMS[stopx&31];
  476. #ifdef DEBUG_BITMASK
  477. unsigned *cm_mask_end1=i1->cm_mask + i1_pitch*i1->clip_rect.bottom;
  478. unsigned *cm_mask_end2=i2->cm_mask + i2_pitch*i2->clip_rect.bottom;
  479. #endif
  480. s1+=startx/32;
  481. for( int y=ir.top;y<ir.bottom;++y ){
  482. unsigned p=0;
  483. unsigned *row1=s1,*row2=s2;
  484. for( int x=0;x<cnt;++x ){
  485. #ifdef DEBUG_BITMASK
  486. if( row1<i1->cm_mask || row2<i2->cm_mask ){
  487. gx_runtime->debugError( "gxCanvas::collide row underflow" );
  488. }
  489. if( row1>=cm_mask_end1 || row2>=cm_mask_end2 ){
  490. gx_runtime->debugError( "gxCanvas::collide row overflow" );
  491. }
  492. #endif
  493. unsigned n=*row2++;
  494. if( ((n>>shr)|p) & *row1++ ) return true;
  495. p=shl<32 ? n<<shl : 0;
  496. }
  497. #ifdef DEBUG_BITMASK
  498. if( row1<i1->cm_mask || row2<i2->cm_mask ){
  499. gx_runtime->debugError( "gxCanvas::collide row underflow" );
  500. }
  501. if( row1>=cm_mask_end1 || row2>=cm_mask_end2 ){
  502. gx_runtime->debugError( "gxCanvas::collide row overflow" );
  503. }
  504. #endif
  505. if( ((*row2>>shr)|p) & *row1 & lwm ) return true;
  506. s1+=i1_pitch;s2+=i2_pitch;
  507. }
  508. return false;
  509. }
  510. bool gxCanvas::rect_collide( int x1,int y1,int x2,int y2,int w2,int h2,bool solid )const{
  511. x1-=handle_x;if( x1+clip_rect.right<=x2 || x1>=x2+w2 ) return false;
  512. y1-=handle_y;if( y1+clip_rect.bottom<=y2 || y1>=y2+h2 ) return false;
  513. if( solid ) return true;
  514. Rect r1( x1,y1,clip_rect.right,clip_rect.bottom ),r2( x2,y2,w2,h2 ),ir;
  515. ir.left=r1.left>r2.left ? r1.left : r2.left;
  516. ir.right=r1.right<r2.right ? r1.right : r2.right;
  517. ir.top=r1.top>r2.top ? r1.top : r2.top;
  518. ir.bottom=r1.bottom<r2.bottom ? r1.bottom : r2.bottom;
  519. if( !cm_mask ){
  520. cm_mask=d_new unsigned[cm_pitch*clip_rect.bottom];
  521. updateBitMask( clip_rect );
  522. }
  523. unsigned *s1=cm_mask+(ir.top-r1.top)*cm_pitch;
  524. int startx=ir.left-r1.left;
  525. int stopx=ir.right-r1.left-1;
  526. int cnt=stopx/32-startx/32;
  527. unsigned fwm=FWMS[startx&31];
  528. unsigned lwm=LWMS[stopx&31];
  529. if( !cnt ) {fwm&=lwm;lwm=0;}
  530. s1+=startx/32;
  531. for( int h=ir.top;h<ir.bottom;++h ){
  532. unsigned *row=s1;
  533. if( *row & fwm ) return true;
  534. for( int x=1;x<cnt;++x ){
  535. if( *++row ) return true;
  536. }
  537. if( lwm && (*++row & lwm) ) return true;
  538. s1+=cm_pitch;
  539. }
  540. return false;
  541. }
  542. bool gxCanvas::lock()const{
  543. if( !locked_cnt++ ){
  544. DDSURFACEDESC2 desc={sizeof(desc)};
  545. if( surf->Lock( 0,&desc,DDLOCK_WAIT|DDLOCK_NOSYSLOCK,0 )<0 ){
  546. --locked_cnt;
  547. return false;
  548. }
  549. locked_pitch=desc.lPitch;
  550. locked_surf=(unsigned char*)desc.lpSurface;
  551. lock_mod_cnt=mod_cnt;
  552. }
  553. return true;
  554. }
  555. void gxCanvas::unlock()const{
  556. if( locked_cnt==1 ){
  557. if( lock_mod_cnt!=mod_cnt && cm_mask ) updateBitMask( clip_rect );
  558. surf->Unlock( 0 );
  559. }
  560. --locked_cnt;
  561. }
  562. void gxCanvas::setPixel( int x,int y,unsigned argb ){
  563. x+=origin_x;if( x<viewport.left || x>=viewport.right ) return;
  564. y+=origin_y;if( y<viewport.top || y>=viewport.bottom ) return;
  565. lock();
  566. setPixelFast( x,y,argb );
  567. unlock();
  568. }
  569. unsigned gxCanvas::getPixel( int x,int y )const{
  570. x+=origin_x;if( x<viewport.left || x>=viewport.right ) return format.toARGB( mask_surf );
  571. y+=origin_y;if( y<viewport.top || y>=viewport.bottom ) return format.toARGB( mask_surf );
  572. lock();
  573. unsigned p=getPixelFast( x,y );
  574. unlock();
  575. return p;
  576. }
  577. void gxCanvas::copyPixelFast( int x,int y,gxCanvas *src,int src_x,int src_y ){
  578. switch( format.getDepth() ){
  579. case 16:
  580. *(short*)(locked_surf+y*locked_pitch+x*2)=
  581. *(short*)(src->locked_surf+src_y*src->locked_pitch+src_x*2);
  582. break;
  583. case 24:{
  584. unsigned char *p=locked_surf+y*locked_pitch+x*3;
  585. unsigned char *t=src->locked_surf+src_y*src->locked_pitch+src_x*3;
  586. *(short*)p=*(short*)t;*(char*)(p+2)=*(char*)(t+2);}
  587. break;
  588. case 32:
  589. *(int*)(locked_surf+y*locked_pitch+x*4)=
  590. *(int*)(src->locked_surf+src_y*src->locked_pitch+src_x*4);
  591. break;
  592. }
  593. }
  594. void gxCanvas::copyPixel( int x,int y,gxCanvas *src,int src_x,int src_y ){
  595. x+=origin_x;if( x<viewport.left || x>=viewport.right ) return;
  596. y+=origin_y;if( y<viewport.top || y>=viewport.bottom ) return;
  597. src_x+=src->origin_x;if( src_x<src->viewport.left || src_x>=src->viewport.right ) return;
  598. src_y+=src->origin_y;if( src_y<src->viewport.top || src_y>=src->viewport.bottom ) return;
  599. lock();
  600. src->lock();
  601. copyPixelFast( x,y,src,src_x,src_y );
  602. src->unlock();
  603. unlock();
  604. }
  605. void gxCanvas::setCubeMode( int mode ){
  606. cube_mode=mode;
  607. }
  608. void gxCanvas::setCubeFace( int face ){
  609. getTexSurface();
  610. surf=cube_surfs[face];
  611. }