724 lines
19 KiB
C++
724 lines
19 KiB
C++
|
|
#include "std.h"
|
|
#include "gxcanvas.h"
|
|
#include "gxgraphics.h"
|
|
#include "gxruntime.h"
|
|
#include "asmcoder.h"
|
|
|
|
#define DEBUG_BITMASK
|
|
|
|
static int canvas_cnt;
|
|
static DDBLTFX bltfx={sizeof(DDBLTFX)};
|
|
|
|
extern gxRuntime *gx_runtime;
|
|
|
|
static unsigned FWMS[]={
|
|
0xffffffff,0x7fffffff,0x3fffffff,0x1fffffff,
|
|
0x0fffffff,0x07ffffff,0x03ffffff,0x01ffffff,
|
|
0x00ffffff,0x007fffff,0x003fffff,0x001fffff,
|
|
0x000fffff,0x0007ffff,0x0003ffff,0x0001ffff,
|
|
0x0000ffff,0x00007fff,0x00003fff,0x00001fff,
|
|
0x00000fff,0x000007ff,0x000003ff,0x000001ff,
|
|
0x000000ff,0x0000007f,0x0000003f,0x0000001f,
|
|
0x0000000f,0x00000007,0x00000003,0x00000001};
|
|
static unsigned LWMS[]={
|
|
0x80000000,0xc0000000,0xe0000000,0xf0000000,
|
|
0xf8000000,0xfc000000,0xfe000000,0xff000000,
|
|
0xff800000,0xffc00000,0xffe00000,0xfff00000,
|
|
0xfff80000,0xfffc0000,0xfffe0000,0xffff0000,
|
|
0xffff8000,0xffffc000,0xffffe000,0xfffff000,
|
|
0xfffff800,0xfffffc00,0xfffffe00,0xffffff00,
|
|
0xffffff80,0xffffffc0,0xffffffe0,0xfffffff0,
|
|
0xfffffff8,0xfffffffc,0xfffffffe,0xffffffff};
|
|
|
|
static void calcShifts( unsigned mask,unsigned char *shr,unsigned char *shl ){
|
|
if( mask ){
|
|
for( *shl=0;!(mask&1);++*shl,mask>>=1 ){}
|
|
for( *shr=8;mask&1;--*shr,mask>>=1 ){}
|
|
}else *shr=*shl=0;
|
|
}
|
|
|
|
struct Rect : public RECT{
|
|
Rect(){
|
|
}
|
|
Rect( int x,int y,int w,int h ){
|
|
left=x;top=y;right=x+w;bottom=y+h;
|
|
}
|
|
};
|
|
|
|
static bool clip( const RECT &viewport,RECT *d ){
|
|
if( d->right<=d->left ||
|
|
d->bottom<=d->top ||
|
|
d->left>=viewport.right ||
|
|
d->right<=viewport.left ||
|
|
d->top>=viewport.bottom ||
|
|
d->bottom<=viewport.top ) return false;
|
|
if( d->left<viewport.left ) d->left=viewport.left;
|
|
if( d->right>viewport.right ) d->right=viewport.right;
|
|
if( d->top<viewport.top ) d->top=viewport.top;
|
|
if( d->bottom>viewport.bottom ) d->bottom=viewport.bottom;
|
|
return true;
|
|
}
|
|
|
|
static bool clip( const RECT &viewport,RECT *d,RECT *s ){
|
|
if( d->right<=d->left ||
|
|
d->bottom<=d->top ||
|
|
d->left>=viewport.right ||
|
|
d->right<=viewport.left ||
|
|
d->top>=viewport.bottom ||
|
|
d->bottom<=viewport.top ) return false;
|
|
int dx,dy;
|
|
if( (dx=viewport.left-d->left)>0 ){ d->left+=dx;s->left+=dx; }
|
|
if( (dx=viewport.right-d->right)<0 ){ d->right+=dx;s->right+=dx; }
|
|
if( (dy=viewport.top-d->top)>0 ){ d->top+=dy;s->top+=dy; }
|
|
if( (dy=viewport.bottom-d->bottom)<0 ){ d->bottom+=dy;s->bottom+=dy; }
|
|
return true;
|
|
}
|
|
|
|
gxCanvas::gxCanvas( gxGraphics *g,IDirectDrawSurface7 *s,int f ):
|
|
graphics(g),main_surf(s),surf(0),z_surf(0),flags(f),cube_mode(CUBEMODE_REFLECTION|CUBESPACE_WORLD),
|
|
t_surf(0),cm_mask(0),locked_cnt(0),mod_cnt(0),remip_cnt(0){
|
|
|
|
if( flags & CANVAS_TEX_CUBE ){
|
|
cube_surfs[2]=main_surf;
|
|
for( int k=0;k<6;++k ){
|
|
if( k==2 ) continue;
|
|
DWORD n;
|
|
switch( k ){
|
|
case 0:n=DDSCAPS2_CUBEMAP_NEGATIVEX;break;
|
|
case 1:n=DDSCAPS2_CUBEMAP_POSITIVEZ;break;
|
|
case 2:n=DDSCAPS2_CUBEMAP_POSITIVEX;break;
|
|
case 3:n=DDSCAPS2_CUBEMAP_NEGATIVEZ;break;
|
|
case 4:n=DDSCAPS2_CUBEMAP_POSITIVEY;break;
|
|
case 5:n=DDSCAPS2_CUBEMAP_NEGATIVEY;break;
|
|
default:return;
|
|
}
|
|
DDSCAPS2 caps={0};
|
|
caps.dwCaps2=DDSCAPS2_CUBEMAP|n;
|
|
main_surf->GetAttachedSurface( &caps,&cube_surfs[k] );
|
|
}
|
|
surf=cube_surfs[1];
|
|
}else{
|
|
surf=main_surf;
|
|
memset( cube_surfs,0,sizeof(cube_surfs) );
|
|
}
|
|
|
|
DDSURFACEDESC2 desc={sizeof(desc)};
|
|
surf->GetSurfaceDesc( &desc );
|
|
format.setFormat( desc.ddpfPixelFormat );
|
|
|
|
clip_rect.left=clip_rect.top=0;
|
|
clip_rect.right=desc.dwWidth;
|
|
clip_rect.bottom=desc.dwHeight;
|
|
cm_pitch=(clip_rect.right+31)/32+1;
|
|
setMask( 0 );
|
|
setColor( ~0 );
|
|
setClsColor( 0 );
|
|
setOrigin( 0,0 );
|
|
setHandle( 0,0 );
|
|
setFont( graphics->getDefaultFont() );
|
|
setViewport( 0,0,getWidth(),getHeight() );
|
|
if( flags & gxCanvas::CANVAS_TEXTURE ) ddUtil::buildMipMaps( surf );
|
|
}
|
|
|
|
gxCanvas::~gxCanvas(){
|
|
delete[] cm_mask;
|
|
if( locked_cnt ) surf->Unlock( 0 );
|
|
if( t_surf ) t_surf->Release();
|
|
releaseZBuffer();
|
|
main_surf->Release();
|
|
}
|
|
|
|
void gxCanvas::backup()const{
|
|
if( flags & CANVAS_TEX_CUBE ) return;
|
|
|
|
if( !t_surf ){
|
|
DDSURFACEDESC2 desc={sizeof(desc)};
|
|
if( surf->GetSurfaceDesc(&desc)<0 ) return;
|
|
if( desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) return;
|
|
|
|
DDSURFACEDESC2 t_desc={sizeof(t_desc)};
|
|
t_desc.dwFlags=DDSD_CAPS|DDSD_PIXELFORMAT|DDSD_WIDTH|DDSD_HEIGHT;
|
|
t_desc.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY;
|
|
t_desc.dwWidth=desc.dwWidth;t_desc.dwHeight=desc.dwHeight;
|
|
t_desc.ddpfPixelFormat=desc.ddpfPixelFormat;
|
|
|
|
if( graphics->dirDraw->CreateSurface( &t_desc,&t_surf,0 )<0 ){
|
|
t_surf=0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if( t_surf->Blt( 0,surf,0,DDBLT_WAIT,0 )<0 ) return;
|
|
}
|
|
|
|
void gxCanvas::restore()const{
|
|
if( !t_surf ) return;
|
|
|
|
if( surf->Blt( 0,t_surf,0,DDBLT_WAIT,0 )<0 ) return;
|
|
}
|
|
|
|
ddSurf *gxCanvas::getSurface()const{
|
|
return surf;
|
|
}
|
|
|
|
ddSurf *gxCanvas::getTexSurface()const{
|
|
if( mod_cnt==remip_cnt ) return main_surf;
|
|
ddUtil::buildMipMaps( surf );
|
|
remip_cnt=mod_cnt;
|
|
return main_surf;
|
|
}
|
|
|
|
bool gxCanvas::clip( RECT *d )const{
|
|
return ::clip( viewport,d );
|
|
}
|
|
|
|
bool gxCanvas::clip( RECT *d,RECT *s )const{
|
|
return ::clip( viewport,d,s );
|
|
}
|
|
|
|
void gxCanvas::updateBitMask( const RECT &r )const{
|
|
|
|
int w=r.right-r.left;if( w<=0 ) return;
|
|
int h=r.bottom-r.top;if( h<=0 ) return;
|
|
|
|
lock();
|
|
RECT t=r;
|
|
t.left&=~31;
|
|
t.right=(t.right+31)&~31;
|
|
w=(t.right-t.left)/32;
|
|
unsigned char *src_row=locked_surf+t.top*locked_pitch+t.left*format.getPitch();
|
|
unsigned *dest_row=cm_mask+t.top*cm_pitch+t.left/32;
|
|
unsigned mask_argb=format.toARGB( mask_surf ) & 0xffffff;
|
|
|
|
#ifdef DEBUG_BITMASK
|
|
unsigned *cm_mask_end=cm_mask+cm_pitch*clip_rect.bottom;
|
|
#endif
|
|
|
|
while( h-- ){
|
|
unsigned *dest=dest_row;
|
|
unsigned char *src=src_row;
|
|
for( int c=0;c<w;++c ){
|
|
unsigned mask=0;
|
|
for( int x=0;x<32;++x ){
|
|
unsigned pix=format.getPixel(src) & 0xffffff;
|
|
mask=(mask<<1)|(pix!=mask_argb);
|
|
src+=format.getPitch();
|
|
}
|
|
#ifdef DEBUG_BITMASK
|
|
if( dest<cm_mask || dest>=cm_mask_end ){
|
|
gx_runtime->debugError( "gxCanvas::updateBitMask dest out of range" );
|
|
}
|
|
#endif
|
|
*dest++=mask;
|
|
}
|
|
dest_row+=cm_pitch;
|
|
src_row+=locked_pitch;
|
|
}
|
|
unlock();
|
|
}
|
|
|
|
void gxCanvas::setModify( int n ){
|
|
mod_cnt=n;
|
|
}
|
|
|
|
int gxCanvas::getModify()const{
|
|
return mod_cnt;
|
|
}
|
|
|
|
bool gxCanvas::attachZBuffer(){
|
|
if( z_surf ) return true;
|
|
DDSURFACEDESC2 desc={sizeof(desc)};
|
|
desc.dwFlags=DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_PIXELFORMAT;
|
|
desc.dwWidth=getWidth();
|
|
desc.dwHeight=getHeight();
|
|
desc.ddsCaps.dwCaps=DDSCAPS_ZBUFFER|DDSCAPS_VIDEOMEMORY;
|
|
desc.ddpfPixelFormat=graphics->zbuffFmt;
|
|
if( graphics->dirDraw->CreateSurface( &desc,&z_surf,0 )<0 ) return false;
|
|
surf->AddAttachedSurface( z_surf );
|
|
return true;
|
|
}
|
|
|
|
void gxCanvas::releaseZBuffer(){
|
|
if( !z_surf ) return;
|
|
surf->DeleteAttachedSurface( 0,z_surf );
|
|
z_surf->Release();
|
|
z_surf=0;
|
|
}
|
|
|
|
void gxCanvas::damage( const RECT &r )const{
|
|
++mod_cnt;if( cm_mask ) updateBitMask( r );
|
|
}
|
|
|
|
void gxCanvas::setFont( gxFont *f ){
|
|
font=f;
|
|
}
|
|
|
|
void gxCanvas::setMask( unsigned argb ){
|
|
mask_surf=format.fromARGB( argb );
|
|
}
|
|
|
|
void gxCanvas::setColor( unsigned argb ){
|
|
argb|=0xff000000;
|
|
color_argb=argb;
|
|
color_surf=format.fromARGB( argb );
|
|
}
|
|
|
|
void gxCanvas::setClsColor( unsigned argb ){
|
|
argb|=0xff000000;
|
|
clsColor_surf=format.fromARGB( argb );
|
|
}
|
|
|
|
void gxCanvas::setOrigin( int x,int y ){
|
|
origin_x=x;origin_y=y;
|
|
}
|
|
|
|
void gxCanvas::setHandle( int x,int y ){
|
|
handle_x=x;handle_y=y;
|
|
}
|
|
|
|
void gxCanvas::setViewport( int x,int y,int w,int h ){
|
|
Rect r( x,y,w,h );
|
|
if( !::clip( clip_rect,&r ) ) r=Rect(0,0,0,0);
|
|
viewport=r;
|
|
}
|
|
|
|
//renderering primitives
|
|
void gxCanvas::cls(){
|
|
bltfx.dwFillColor=clsColor_surf;
|
|
surf->Blt( &viewport,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
|
|
damage( viewport );
|
|
}
|
|
|
|
void gxCanvas::plot( int x,int y ){
|
|
x+=origin_x;if( x<viewport.left || x>=viewport.right ) return;
|
|
y+=origin_y;if( y<viewport.top || y>=viewport.bottom ) return;
|
|
bltfx.dwFillColor=color_surf;
|
|
Rect dest( x,y,1,1 );
|
|
surf->Blt( &dest,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
|
|
damage( dest );
|
|
}
|
|
|
|
void gxCanvas::line( int x0,int y0,int x1,int y1 ){
|
|
int ddf,padj,sadj;
|
|
int dx,dy,sx,sy,ax,ay;
|
|
|
|
x0+=origin_x;y0+=origin_y;
|
|
x1+=origin_x;y1+=origin_y;
|
|
|
|
int cx0,cx1,cy0,cy1,clip0,clip1;
|
|
|
|
cx0=viewport.left;
|
|
cx1=viewport.right-1;
|
|
cy0=viewport.top;
|
|
cy1=viewport.bottom-1;
|
|
|
|
while( true ){
|
|
clip0=0;clip1=0;
|
|
|
|
if(y0>cy1)clip0|=1;else if(y0<cy0)clip0|=2;
|
|
if(x0>cx1)clip0|=4;else if(x0<cx0)clip0|=8;
|
|
if(y1>cy1)clip1|=1;else if(y1<cy0)clip1|=2;
|
|
if(x1>cx1)clip1|=4;else if(x1<cx0)clip1|=8;
|
|
|
|
if((clip0|clip1)==0) break; //draw line
|
|
if((clip0&clip1)!=0) return; //outside
|
|
|
|
if((clip0&1)==1) {x0=x0+((x1-x0)*(cy1-y0))/(y1-y0);y0=cy1;continue;}
|
|
if((clip0&2)==2) {x0=x0+((x1-x0)*(cy0-y0))/(y1-y0);y0=cy0;continue;}
|
|
if((clip0&4)==4) {y0=y0+((y1-y0)*(cx1-x0))/(x1-x0);x0=cx1;continue;}
|
|
if((clip0&8)==8) {y0=y0+((y1-y0)*(cx0-x0))/(x1-x0);x0=cx0;continue;}
|
|
|
|
if((clip1&1)==1) {x1=x0+((x1-x0)*(cy1-y0))/(y1-y0);y1=cy1;continue;}
|
|
if((clip1&2)==2) {x1=x0+((x1-x0)*(cy0-y0))/(y1-y0);y1=cy0;continue;}
|
|
if((clip1&4)==4) {y1=y0+((y1-y0)*(cx1-x0))/(x1-x0);x1=cx1;continue;}
|
|
if((clip1&8)==8) {y1=y0+((y1-y0)*(cx0-x0))/(x1-x0);x1=cx0;continue;}
|
|
}
|
|
|
|
dx=x1-x0;dy=y1-y0;
|
|
if( (dx|dy)==0 ){
|
|
setPixel( x0,y0,color_argb );
|
|
return;
|
|
}
|
|
|
|
if (dx>=0) {sx=1;ax=dx;} else {sx=-1;ax=-dx;}
|
|
if (dy>=0) {sy=1;ay=dy;} else {sy=-1;ay=-dy;}
|
|
|
|
lock();
|
|
if( ax>ay ){
|
|
ddf=-ax;sadj=ax+ax;padj=ay+ay;
|
|
while( ax-->=0 ){
|
|
setPixelFast( x0,y0,color_argb );
|
|
x0+=sx;ddf+=padj;if( ddf>=0 ){ y0+=sy;ddf-=sadj; }
|
|
}
|
|
}else{
|
|
ddf=-ay;sadj=ay+ay;padj=ax+ax;
|
|
while( ay-->=0 ){
|
|
setPixelFast( x0,y0,color_argb );
|
|
y0+=sy;ddf+=padj;if( ddf>=0 ){ x0+=sx;ddf-=sadj; }
|
|
}
|
|
|
|
}
|
|
unlock();
|
|
}
|
|
|
|
void gxCanvas::rect( int x,int y,int w,int h,bool solid ){
|
|
x+=origin_x;y+=origin_y;
|
|
Rect dest( x,y,w,h );
|
|
if( !clip( &dest ) ) return;
|
|
|
|
bltfx.dwFillColor=color_surf;
|
|
|
|
if( solid ){
|
|
surf->Blt( &dest,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
|
|
damage( dest );
|
|
return;
|
|
}
|
|
Rect r1( x,y,w,1 );if( clip( &r1 ) ){
|
|
surf->Blt( &r1,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
|
|
}
|
|
Rect r2( x,y,1,h );if( clip( &r2 ) ){
|
|
surf->Blt( &r2,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
|
|
}
|
|
Rect r3( x+w-1,y,1,h );if( clip( &r3 ) ){
|
|
surf->Blt( &r3,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
|
|
}
|
|
Rect r4( x,y+h-1,w,1 );if( clip( &r4 ) ){
|
|
surf->Blt( &r4,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
|
|
}
|
|
damage( dest );
|
|
}
|
|
|
|
void gxCanvas::oval( int x1,int y1,int w,int h,bool solid ){
|
|
x1+=origin_x;y1+=origin_y;
|
|
Rect dest( x1,y1,w,h );
|
|
if( !clip( &dest ) ) return;
|
|
|
|
bltfx.dwFillColor=color_surf;
|
|
|
|
float xr=w*.5f,yr=h*.5f,ar=(float)w/(float)h;
|
|
float cx=x1+xr+.5f,cy=y1+yr-.5f,rsq=yr*yr,y;
|
|
|
|
if( solid ){
|
|
y=dest.top-cy;
|
|
for( int t=dest.top;t<dest.bottom;++y,++t ){
|
|
float x=sqrt( rsq-y*y )*ar;
|
|
int xa=floor( cx-x ),xb=floor( cx+x );
|
|
if( xb<=xa || xa>=viewport.right || xb<=viewport.left ) continue;
|
|
Rect dr;dr.top=t;dr.bottom=t+1;
|
|
dr.left=xa<viewport.left ? viewport.left : xa;
|
|
dr.right=xb>viewport.right ? viewport.right : xb;
|
|
surf->Blt( &dr,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
|
|
}
|
|
damage( dest );
|
|
return;
|
|
}
|
|
|
|
int p_xa,p_xb,t,hh=floor(cy);
|
|
|
|
p_xa=p_xb=cx;
|
|
t=dest.top;y=t-cy;
|
|
if( dest.top>y1 ){ --t;--y; }
|
|
for( ;t<=hh;++y,++t ){
|
|
float x=sqrt( rsq-y*y )*ar;
|
|
int xa=floor( cx-x ),xb=floor( cx+x );
|
|
Rect r1( xa,t,p_xa-xa,1 );if( r1.right<=r1.left ) r1.right=r1.left+1;
|
|
if( clip( &r1 ) ) surf->Blt( &r1,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
|
|
Rect r2( p_xb,t,xb-p_xb,1 );if( r2.left>=r2.right ) r2.left=r2.right-1;
|
|
if( clip( &r2 ) ) surf->Blt( &r2,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
|
|
p_xa=xa;p_xb=xb;
|
|
}
|
|
|
|
p_xa=p_xb=cx;
|
|
t=dest.bottom-1;y=t-cy;
|
|
if( dest.bottom<y1+h ){ ++t;++y; }
|
|
for( ;t>hh;--y,--t ){
|
|
float x=sqrt( rsq-y*y )*ar;
|
|
int xa=floor( cx-x ),xb=floor( cx+x );
|
|
Rect r1( xa,t,p_xa-xa,1 );if( r1.right<=r1.left ) r1.right=r1.left+1;
|
|
if( clip( &r1 ) ) surf->Blt( &r1,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
|
|
Rect r2( p_xb,t,xb-p_xb,1 );if( r2.left>=r2.right ) r2.left=r2.right-1;
|
|
if( clip( &r2 ) ) surf->Blt( &r2,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx );
|
|
p_xa=xa;p_xb=xb;
|
|
}
|
|
damage( dest );
|
|
}
|
|
|
|
void gxCanvas::blit( int x,int y,gxCanvas *src,int src_x,int src_y,int src_w,int src_h,bool solid ){
|
|
x+=origin_x-src->handle_x;
|
|
y+=origin_y-src->handle_y;
|
|
Rect dest_r( x,y,src_w,src_h ),src_r( src_x,src_y,src_w,src_h );
|
|
if( !clip( &dest_r,&src_r ) ) return;
|
|
if( !::clip( src->clip_rect,&src_r,&dest_r ) ) return;
|
|
|
|
if( solid ){
|
|
surf->Blt( &dest_r,src->surf,&src_r,DDBLT_WAIT,0 );
|
|
}else{
|
|
bltfx.ddckSrcColorkey.dwColorSpaceLowValue=
|
|
bltfx.ddckSrcColorkey.dwColorSpaceHighValue=src->mask_surf;
|
|
surf->Blt( &dest_r,src->surf,&src_r,DDBLT_WAIT|DDBLT_KEYSRCOVERRIDE,&bltfx );
|
|
}
|
|
damage( dest_r );
|
|
}
|
|
|
|
void gxCanvas::text( int x,int y,const string &t ){
|
|
|
|
int ty=y+origin_y;
|
|
if( ty>=viewport.bottom ) return;
|
|
if( ty+font->getHeight()<=viewport.top ) return;
|
|
|
|
int tx=x+origin_x;
|
|
if( tx>=viewport.right ) return;
|
|
|
|
int b=0,w;
|
|
while( b<t.size() && tx+(w=font->charWidth( t[b] ))<=viewport.left ){
|
|
tx+=w;x+=w;++b;
|
|
}
|
|
int e=b;
|
|
while( e<t.size() && tx<viewport.right ){
|
|
tx+=font->charWidth( t[e] );++e;
|
|
}
|
|
|
|
if( e>b ) font->render( this,format.toARGB( color_surf ),x,y,t.substr( b,e-b ) );
|
|
}
|
|
|
|
int gxCanvas::getWidth()const{
|
|
return clip_rect.right;
|
|
}
|
|
|
|
int gxCanvas::getHeight()const{
|
|
return clip_rect.bottom;
|
|
}
|
|
|
|
int gxCanvas::getDepth()const{
|
|
return format.getDepth();
|
|
}
|
|
|
|
void gxCanvas::getOrigin( int *x,int *y )const{
|
|
*x=origin_x;*y=origin_y;
|
|
}
|
|
|
|
void gxCanvas::getHandle( int *x,int *y )const{
|
|
*x=handle_x;*y=handle_y;
|
|
}
|
|
|
|
void gxCanvas::getViewport( int *x,int *y,int *w,int *h )const{
|
|
*x=viewport.left;*y=viewport.top;
|
|
*w=viewport.right-viewport.left;*h=viewport.bottom-viewport.top;
|
|
}
|
|
|
|
unsigned gxCanvas::getMask()const{
|
|
return format.toARGB( mask_surf );
|
|
}
|
|
|
|
unsigned gxCanvas::getColor()const{
|
|
return format.toARGB( color_surf );
|
|
}
|
|
|
|
unsigned gxCanvas::getClsColor()const{
|
|
return format.toARGB( clsColor_surf );
|
|
}
|
|
|
|
bool gxCanvas::collide( int x1,int y1,const gxCanvas *i2,int x2,int y2,bool solid )const{
|
|
|
|
x1-=handle_x;x2-=i2->handle_x;
|
|
if( x1+clip_rect.right<=x2 || x1>=x2+i2->clip_rect.right ) return false;
|
|
y1-=handle_y;y2-=i2->handle_y;
|
|
if( y1+clip_rect.bottom<=y2 || y1>=y2+i2->clip_rect.bottom ) return false;
|
|
|
|
if( solid ) return true;
|
|
|
|
if( !cm_mask ){
|
|
cm_mask=d_new unsigned[cm_pitch*clip_rect.bottom];
|
|
updateBitMask( clip_rect );
|
|
}
|
|
if( !i2->cm_mask ){
|
|
i2->cm_mask=d_new unsigned[i2->cm_pitch*i2->clip_rect.bottom];
|
|
i2->updateBitMask( i2->clip_rect );
|
|
}
|
|
|
|
const gxCanvas *i1=this;
|
|
|
|
//to keep me sane!
|
|
if( x1>x2 ){
|
|
std::swap( x1,x2 );
|
|
std::swap( y1,y2 );
|
|
std::swap( i1,i2 );
|
|
}
|
|
|
|
Rect r1,r2,ir;
|
|
r1.left=x1;r1.top=y1;r1.right=x1+i1->clip_rect.right;r1.bottom=y1+i1->clip_rect.bottom;
|
|
r2.left=x2;r2.top=y2;r2.right=x2+i2->clip_rect.right;r2.bottom=y2+i2->clip_rect.bottom;
|
|
ir.left=r1.left>r2.left ? r1.left : r2.left;
|
|
ir.right=r1.right<r2.right ? r1.right : r2.right;
|
|
ir.top=r1.top>r2.top ? r1.top : r2.top;
|
|
ir.bottom=r1.bottom<r2.bottom ? r1.bottom : r2.bottom;
|
|
|
|
unsigned *s1=i1->cm_mask,*s2=i2->cm_mask;
|
|
int i1_pitch=i1->cm_pitch,i2_pitch=i2->cm_pitch;
|
|
s1+=(ir.top-r1.top)*i1_pitch;
|
|
s2+=(ir.top-r2.top)*i2_pitch;
|
|
|
|
int startx=ir.left-r1.left;
|
|
int stopx=ir.right-r1.left-1;
|
|
int shr=startx&31;
|
|
int shl=32-shr;
|
|
int cnt=stopx/32-startx/32;
|
|
unsigned lwm=LWMS[stopx&31];
|
|
|
|
#ifdef DEBUG_BITMASK
|
|
unsigned *cm_mask_end1=i1->cm_mask + i1_pitch*i1->clip_rect.bottom;
|
|
unsigned *cm_mask_end2=i2->cm_mask + i2_pitch*i2->clip_rect.bottom;
|
|
#endif
|
|
|
|
s1+=startx/32;
|
|
for( int y=ir.top;y<ir.bottom;++y ){
|
|
unsigned p=0;
|
|
unsigned *row1=s1,*row2=s2;
|
|
for( int x=0;x<cnt;++x ){
|
|
#ifdef DEBUG_BITMASK
|
|
if( row1<i1->cm_mask || row2<i2->cm_mask ){
|
|
gx_runtime->debugError( "gxCanvas::collide row underflow" );
|
|
}
|
|
if( row1>=cm_mask_end1 || row2>=cm_mask_end2 ){
|
|
gx_runtime->debugError( "gxCanvas::collide row overflow" );
|
|
}
|
|
#endif
|
|
unsigned n=*row2++;
|
|
if( ((n>>shr)|p) & *row1++ ) return true;
|
|
p=shl<32 ? n<<shl : 0;
|
|
}
|
|
#ifdef DEBUG_BITMASK
|
|
if( row1<i1->cm_mask || row2<i2->cm_mask ){
|
|
gx_runtime->debugError( "gxCanvas::collide row underflow" );
|
|
}
|
|
if( row1>=cm_mask_end1 || row2>=cm_mask_end2 ){
|
|
gx_runtime->debugError( "gxCanvas::collide row overflow" );
|
|
}
|
|
#endif
|
|
if( ((*row2>>shr)|p) & *row1 & lwm ) return true;
|
|
s1+=i1_pitch;s2+=i2_pitch;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool gxCanvas::rect_collide( int x1,int y1,int x2,int y2,int w2,int h2,bool solid )const{
|
|
|
|
x1-=handle_x;if( x1+clip_rect.right<=x2 || x1>=x2+w2 ) return false;
|
|
y1-=handle_y;if( y1+clip_rect.bottom<=y2 || y1>=y2+h2 ) return false;
|
|
|
|
if( solid ) return true;
|
|
|
|
Rect r1( x1,y1,clip_rect.right,clip_rect.bottom ),r2( x2,y2,w2,h2 ),ir;
|
|
|
|
ir.left=r1.left>r2.left ? r1.left : r2.left;
|
|
ir.right=r1.right<r2.right ? r1.right : r2.right;
|
|
ir.top=r1.top>r2.top ? r1.top : r2.top;
|
|
ir.bottom=r1.bottom<r2.bottom ? r1.bottom : r2.bottom;
|
|
|
|
if( !cm_mask ){
|
|
cm_mask=d_new unsigned[cm_pitch*clip_rect.bottom];
|
|
updateBitMask( clip_rect );
|
|
}
|
|
|
|
unsigned *s1=cm_mask+(ir.top-r1.top)*cm_pitch;
|
|
|
|
int startx=ir.left-r1.left;
|
|
int stopx=ir.right-r1.left-1;
|
|
int cnt=stopx/32-startx/32;
|
|
unsigned fwm=FWMS[startx&31];
|
|
unsigned lwm=LWMS[stopx&31];
|
|
|
|
if( !cnt ) {fwm&=lwm;lwm=0;}
|
|
|
|
s1+=startx/32;
|
|
for( int h=ir.top;h<ir.bottom;++h ){
|
|
unsigned *row=s1;
|
|
if( *row & fwm ) return true;
|
|
for( int x=1;x<cnt;++x ){
|
|
if( *++row ) return true;
|
|
}
|
|
if( lwm && (*++row & lwm) ) return true;
|
|
s1+=cm_pitch;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool gxCanvas::lock()const{
|
|
if( !locked_cnt++ ){
|
|
DDSURFACEDESC2 desc={sizeof(desc)};
|
|
if( surf->Lock( 0,&desc,DDLOCK_WAIT|DDLOCK_NOSYSLOCK,0 )<0 ){
|
|
--locked_cnt;
|
|
return false;
|
|
}
|
|
locked_pitch=desc.lPitch;
|
|
locked_surf=(unsigned char*)desc.lpSurface;
|
|
lock_mod_cnt=mod_cnt;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void gxCanvas::unlock()const{
|
|
if( locked_cnt==1 ){
|
|
if( lock_mod_cnt!=mod_cnt && cm_mask ) updateBitMask( clip_rect );
|
|
surf->Unlock( 0 );
|
|
}
|
|
--locked_cnt;
|
|
}
|
|
|
|
void gxCanvas::setPixel( int x,int y,unsigned argb ){
|
|
x+=origin_x;if( x<viewport.left || x>=viewport.right ) return;
|
|
y+=origin_y;if( y<viewport.top || y>=viewport.bottom ) return;
|
|
lock();
|
|
setPixelFast( x,y,argb );
|
|
unlock();
|
|
}
|
|
|
|
unsigned gxCanvas::getPixel( int x,int y )const{
|
|
x+=origin_x;if( x<viewport.left || x>=viewport.right ) return format.toARGB( mask_surf );
|
|
y+=origin_y;if( y<viewport.top || y>=viewport.bottom ) return format.toARGB( mask_surf );
|
|
lock();
|
|
unsigned p=getPixelFast( x,y );
|
|
unlock();
|
|
return p;
|
|
}
|
|
|
|
void gxCanvas::copyPixelFast( int x,int y,gxCanvas *src,int src_x,int src_y ){
|
|
switch( format.getDepth() ){
|
|
case 16:
|
|
*(short*)(locked_surf+y*locked_pitch+x*2)=
|
|
*(short*)(src->locked_surf+src_y*src->locked_pitch+src_x*2);
|
|
break;
|
|
case 24:{
|
|
unsigned char *p=locked_surf+y*locked_pitch+x*3;
|
|
unsigned char *t=src->locked_surf+src_y*src->locked_pitch+src_x*3;
|
|
*(short*)p=*(short*)t;*(char*)(p+2)=*(char*)(t+2);}
|
|
break;
|
|
case 32:
|
|
*(int*)(locked_surf+y*locked_pitch+x*4)=
|
|
*(int*)(src->locked_surf+src_y*src->locked_pitch+src_x*4);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void gxCanvas::copyPixel( int x,int y,gxCanvas *src,int src_x,int src_y ){
|
|
x+=origin_x;if( x<viewport.left || x>=viewport.right ) return;
|
|
y+=origin_y;if( y<viewport.top || y>=viewport.bottom ) return;
|
|
src_x+=src->origin_x;if( src_x<src->viewport.left || src_x>=src->viewport.right ) return;
|
|
src_y+=src->origin_y;if( src_y<src->viewport.top || src_y>=src->viewport.bottom ) return;
|
|
lock();
|
|
src->lock();
|
|
copyPixelFast( x,y,src,src_x,src_y );
|
|
src->unlock();
|
|
unlock();
|
|
}
|
|
|
|
void gxCanvas::setCubeMode( int mode ){
|
|
cube_mode=mode;
|
|
}
|
|
|
|
void gxCanvas::setCubeFace( int face ){
|
|
|
|
getTexSurface();
|
|
surf=cube_surfs[face];
|
|
} |