blitz3d/bbruntime/bbgraphics.cpp

1351 lines
34 KiB
C++

#include "std.h"
#include "bbgraphics.h"
#include "bbinput.h"
gxGraphics *gx_graphics;
gxCanvas *gx_canvas;
struct GfxMode{
int w,h,d,caps;
};
class bbImage{
public:
bbImage( const vector<gxCanvas*> &f ):frames(f){
}
~bbImage(){
for( int k=0;k<frames.size();++k ){
gx_graphics->freeCanvas( frames[k] );
}
}
const vector<gxCanvas*> &getFrames()const{
return frames;
}
void replaceFrame( int n,gxCanvas *c ){
gx_graphics->freeCanvas( frames[n] );
frames[n]=c;
}
private:
vector<gxCanvas*> frames;
};
//degrees to radians
static const float dtor=0.0174532925199432957692369076848861f;
static int gx_driver; //current graphics driver
static bool filter;
static bool auto_dirty;
static bool auto_midhandle;
static set<bbImage*> image_set;
static int curs_x,curs_y;
static gxCanvas *p_canvas;
static gxFont *curr_font;
static unsigned curr_color;
static unsigned curr_clsColor;
static vector<GfxMode> gfx_modes;
static inline void debugImage( bbImage *i,int frame=0 ){
if( debug ){
if( !image_set.count(i) ) RTEX( "Image does not exist" );
if( frame>=i->getFrames().size() ) RTEX( "Image frame out of range" );
}
}
static inline void debugFont( gxFont *f ){
if( debug ){
if( !gx_graphics->verifyFont( f ) ) RTEX( "Font does not exist" );
}
}
static inline void debugCanvas( gxCanvas *c ){
if( debug ){
if( !gx_graphics->verifyCanvas( c ) ) RTEX( "Buffer does not exist" );
}
}
static inline void debugDriver( int n ){
if( debug ){
if( n<1 || n>gx_runtime->numGraphicsDrivers() ){
RTEX( "Illegal graphics driver index" );
}
}
}
static inline void debugMode( int n ){
if( debug ){
if( n<1 || n>gfx_modes.size() ){
RTEX( "Illegal graphics mode index" );
}
}
}
void bbFreeImage( bbImage *i );
static void freeGraphics(){
#ifdef PRO
extern void blitz3d_close();
blitz3d_close();
#endif
while( image_set.size() ) bbFreeImage( *image_set.begin() );
if( p_canvas ){
gx_graphics->freeCanvas( p_canvas );
p_canvas=0;
}
}
#define RED(_X_) ( ((_X_)>>16) & 0xff )
#define GRN(_X_) ( ((_X_)>>8) & 0xff )
#define BLU(_X_) ( (_X_) & 0xff )
static int getPixel( gxCanvas *c,float x,float y ){
debugCanvas( c );
x-=.5f;y-=.5f;
float fx=floor(x),fy=floor(y);
int ix=fx,iy=fy;fx=x-fx;fy=y-fy;
int tl=c->getPixel( ix,iy );
int tr=c->getPixel( ix+1,iy );
int br=c->getPixel( ix+1,iy+1 );
int bl=c->getPixel( ix,iy+1 );
float w1=(1-fx)*(1-fy),w2=fx*(1-fy),w3=(1-fx)*fy,w4=fx*fy;
float r=RED(tl)*w1+RED(tr)*w2+RED(bl)*w3+RED(br)*w4;
float g=GRN(tl)*w1+GRN(tr)*w2+GRN(bl)*w3+GRN(br)*w4;
float b=BLU(tl)*w1+BLU(tr)*w2+BLU(bl)*w3+BLU(br)*w4;
return (int(r+.5f)<<16)|(int(g+.5f)<<8)|int(b+.5f);
}
struct vec2{ float x,y; };
static vec2 vrot( float m[2][2],const vec2 &v ){
vec2 t;t.x=m[0][0]*v.x+m[0][1]*v.y;t.y=m[1][0]*v.x+m[1][1]*v.y;
return t;
}
static float vmin( float a,float b,float c,float d ){
float t=a;if( b<t ) t=b;if( c<t ) t=c;if( d<t ) t=d;return t;
}
static float vmax( float a,float b,float c,float d ){
float t=a;if( b>t ) t=b;if( c>t ) t=c;if( d>t ) t=d;return t;
}
static gxCanvas *tformCanvas( gxCanvas *c,float m[2][2],int x_handle,int y_handle ){
vec2 v,v0,v1,v2,v3;
float i[2][2];
float dt=1.0f/(m[0][0]*m[1][1]-m[1][0]*m[0][1]);
i[0][0]=dt*m[1][1];i[1][0]=-dt*m[1][0];
i[0][1]=-dt*m[0][1];i[1][1]=dt*m[0][0];
float ox=x_handle,oy=y_handle;
v0.x=-ox;v0.y=-oy; //tl
v1.x=c->getWidth()-ox;v1.y=-oy; //tr
v2.x=c->getWidth()-ox;v2.y=c->getHeight()-oy; //br
v3.x=-ox;v3.y=c->getHeight()-oy; //bl
v0=vrot(m,v0);v1=vrot(m,v1);v2=vrot(m,v2);v3=vrot(m,v3);
float minx=floor( vmin( v0.x,v1.x,v2.x,v3.x ) );
float miny=floor( vmin( v0.y,v1.y,v2.y,v3.y ) );
float maxx=ceil( vmax( v0.x,v1.x,v2.x,v3.x ) );
float maxy=ceil( vmax( v0.y,v1.y,v2.y,v3.y ) );
int iw=maxx-minx,ih=maxy-miny;
gxCanvas *t=gx_graphics->createCanvas( iw,ih,0 );
t->setHandle( -minx,-miny );
t->setMask( c->getMask() );
c->lock();
t->lock();
v.y=miny+.5f;
for( int y=0;y<ih;++v.y,++y ){
v.x=minx+.5f;
for( int x=0;x<iw;++v.x,++x ){
vec2 q=vrot(i,v);
unsigned rgb=filter ? getPixel( c,q.x+ox,q.y+oy ) : c->getPixel( floor(q.x+ox),floor(q.y+oy) );
t->setPixel( x,y,rgb );
}
}
t->unlock();
c->unlock();
return t;
}
static bool saveCanvas( gxCanvas *c,const string &f ){
ofstream out( f.c_str(),ios::binary );
if( !out.good() ) return false;
int tempsize=(c->getWidth()*3+3)&~3;
BITMAPFILEHEADER bf;
memset( &bf,0,sizeof(bf) );
bf.bfType='MB';
bf.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+tempsize*c->getHeight();
bf.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
BITMAPINFOHEADER bi;memset( &bi,0,sizeof(bi) );
bi.biSize=sizeof(bi);
bi.biWidth=c->getWidth();
bi.biHeight=c->getHeight();
bi.biPlanes=1;
bi.biBitCount=24;
out.write( (char*)&bf,sizeof(bf) );
out.write( (char*)&bi,sizeof(bi) );
unsigned char *temp=d_new unsigned char[ tempsize ];
memset( temp,0,tempsize );
c->lock();
for( int y=c->getHeight()-1;y>=0;--y ){
unsigned char *dest=temp;
for( int x=0;x<c->getWidth();++x ){
unsigned rgb=c->getPixelFast( x,y );
*dest++=rgb&0xff;
*dest++=(rgb>>8)&0xff;
*dest++=(rgb>>16)&0xff;
}
out.write( (char*)temp,tempsize );
}
c->unlock();
delete [] temp;
return out.good();
}
int bbCountGfxDrivers(){
return gx_runtime->numGraphicsDrivers();
}
BBStr * bbGfxDriverName( int n ){
debugDriver( n );
string t;int caps;
gx_runtime->graphicsDriverInfo( n-1,&t,&caps );
return d_new BBStr( t );
}
void bbSetGfxDriver( int n ){
debugDriver( n );
gfx_modes.clear();
gx_driver=n-1;
}
int bbCountGfxModes(){
gfx_modes.clear();
int n=gx_runtime->numGraphicsModes( gx_driver );
for( int k=0;k<n;++k ){
GfxMode m;
gx_runtime->graphicsModeInfo( gx_driver,k,&m.w,&m.h,&m.d,&m.caps );
gfx_modes.push_back( m );
}
return gfx_modes.size();
}
int bbGfxModeWidth( int n ){
debugMode( n );
return gfx_modes[n-1].w;
}
int bbGfxModeHeight( int n ){
debugMode( n );
return gfx_modes[n-1].h;
}
int bbGfxModeDepth( int n ){
debugMode( n );
return gfx_modes[n-1].d;
}
static int modeExists( int w,int h,int d,bool bb3d ){
int cnt=gx_runtime->numGraphicsModes( gx_driver );
for( int k=0;k<cnt;++k ){
int tw,th,td,tc;
gx_runtime->graphicsModeInfo( gx_driver,k,&tw,&th,&td,&tc );
if( bb3d && !(tc&gxRuntime::GFXMODECAPS_3D) ) continue;
if( w==tw && h==th && d==td ) return 1;
}
return 0;
}
int bbGfxModeExists( int w,int h,int d ){
return modeExists( w,h,d,false );
}
#ifdef PRO
int bbGfxDriver3D( int n ){
debugDriver( n );
string t;int caps;
gx_runtime->graphicsDriverInfo( n-1,&t,&caps );
return (caps & gxRuntime::GFXMODECAPS_3D) ? 1 : 0;
}
int bbCountGfxModes3D(){
gfx_modes.clear();
int n=gx_runtime->numGraphicsModes( gx_driver );
for( int k=0;k<n;++k ){
GfxMode m;
gx_runtime->graphicsModeInfo( gx_driver,k,&m.w,&m.h,&m.d,&m.caps );
if( m.caps & gxRuntime::GFXMODECAPS_3D) gfx_modes.push_back( m );
}
return gfx_modes.size();
}
int bbGfxMode3DExists( int w,int h,int d ){
return modeExists( w,h,d,true );
}
int bbGfxMode3D( int n ){
debugMode( n );
return gfx_modes[n-1].caps & gxRuntime::GFXMODECAPS_3D ? 1 :0;
}
int bbWindowed3D(){
int tc;
gx_runtime->windowedModeInfo( &tc );
return (tc & gxRuntime::GFXMODECAPS_3D) ? 1 : 0;
}
#endif
int bbTotalVidMem(){
return gx_graphics->getTotalVidmem();
}
int bbAvailVidMem(){
return gx_graphics->getAvailVidmem();
}
void bbSetBuffer( gxCanvas *buff ){
debugCanvas( buff );
gx_canvas=buff;
curs_x=curs_y=0;
gx_canvas->setOrigin( 0,0 );
gx_canvas->setViewport( 0,0,gx_canvas->getWidth(),gx_canvas->getHeight() );
gx_canvas->setColor( curr_color );
gx_canvas->setClsColor( curr_clsColor );
gx_canvas->setFont( curr_font );
}
gxCanvas *bbGraphicsBuffer(){
return gx_canvas;
}
int bbLoadBuffer( gxCanvas *c,BBStr *str ){
debugCanvas( c );
string s=*str;delete str;
gxCanvas *t=gx_graphics->loadCanvas( s,0 );
if( !t ) return 0;
float m[2][2];
m[0][0]=(float)c->getWidth()/(float)t->getWidth();
m[1][1]=(float)c->getHeight()/(float)t->getHeight();
m[1][0]=m[0][1]=0;
gxCanvas *p=tformCanvas( t,m,0,0 );
gx_graphics->freeCanvas( t );
int ox,oy;
c->getOrigin( &ox,&oy );c->setOrigin( 0,0 );
c->blit( 0,0,p,0,0,p->getWidth(),p->getHeight(),true );
gx_graphics->freeCanvas( p );
return 1;
}
int bbSaveBuffer( gxCanvas *c,BBStr *str ){
debugCanvas( c );
string t=*str;delete str;
return saveCanvas( c,t ) ? 1 : 0;
}
void bbBufferDirty( gxCanvas *c ){
debugCanvas( c );
c->backup();
}
static void graphics( int w,int h,int d,int flags ){
freeGraphics();
gx_runtime->closeGraphics( gx_graphics );
gx_graphics=gx_runtime->openGraphics( w,h,d,gx_driver,flags );
if( !gx_runtime->idle() ) RTEX( 0 );
if( !gx_graphics ){
RTEX( "Unable to set graphics mode" );
}
curr_clsColor=0;
curr_color=0xffffffff;
curr_font=gx_graphics->getDefaultFont();
gxCanvas *buff=(flags & gxGraphics::GRAPHICS_3D) ?
gx_graphics->getBackCanvas() : gx_graphics->getFrontCanvas();
bbSetBuffer( buff );
}
void bbGraphics( int w,int h,int d,int mode ){
int flags=0;
switch( mode ){
case 0:flags|=debug ? gxGraphics::GRAPHICS_WINDOWED : 0 ;break;
case 1:break;
case 2:flags|=gxGraphics::GRAPHICS_WINDOWED;break;
case 3:flags|=gxGraphics::GRAPHICS_WINDOWED|gxGraphics::GRAPHICS_SCALED;break;
case 6:flags|=gxGraphics::GRAPHICS_WINDOWED|gxGraphics::GRAPHICS_AUTOSUSPEND;break;
case 7:flags|=gxGraphics::GRAPHICS_WINDOWED|gxGraphics::GRAPHICS_SCALED|gxGraphics::GRAPHICS_AUTOSUSPEND;break;
default:RTEX( "Illegal Graphics mode" );
}
graphics( w,h,d,flags );
}
#ifdef PRO
void bbGraphics3D( int w,int h,int d,int mode ){
int flags=gxGraphics::GRAPHICS_3D;
switch( mode ){
case 0:flags|=(debug && bbWindowed3D()) ? gxGraphics::GRAPHICS_WINDOWED : 0 ;break;
case 1:break;
case 2:flags|=gxGraphics::GRAPHICS_WINDOWED;break;
case 3:flags|=gxGraphics::GRAPHICS_WINDOWED|gxGraphics::GRAPHICS_SCALED;break;
case 6:flags|=gxGraphics::GRAPHICS_WINDOWED|gxGraphics::GRAPHICS_AUTOSUSPEND;break;
case 7:flags|=gxGraphics::GRAPHICS_WINDOWED|gxGraphics::GRAPHICS_SCALED|gxGraphics::GRAPHICS_AUTOSUSPEND;break;
default:RTEX( "Illegal Graphics3D mode" );
}
graphics( w,h,d,flags );
extern void blitz3d_open();
blitz3d_open();
}
#endif
void bbEndGraphics(){
freeGraphics();
gx_runtime->closeGraphics( gx_graphics );
gx_graphics=gx_runtime->openGraphics( 400,300,0,0,gxGraphics::GRAPHICS_WINDOWED );
if( !gx_runtime->idle() ) RTEX( 0 );
if( gx_graphics ){
curr_clsColor=0;
curr_color=0xffffffff;
curr_font=gx_graphics->getDefaultFont();
bbSetBuffer( gx_graphics->getFrontCanvas() );
return;
}
RTEX( "Unable to set graphics mode" );
}
int bbGraphicsLost(){
return gx_runtime->graphicsLost();
}
void bbSetGamma( int r,int g,int b,float dr,float dg,float db ){
if( dr<0 ) dr=0;
else if( dr>255.0f ) dr=255.0f;
if( dg<0 ) dg=0;
else if( dg>255.0f ) dg=255.0f;
if( db<0 ) db=0;
else if( db>255.0f ) db=255.0f;
gx_graphics->setGamma( r,g,b,dr,dg,db );
}
void bbUpdateGamma( int calibrate ){
gx_graphics->updateGamma( !!calibrate );
}
float bbGammaRed( int n ){
float dr,dg,db;
gx_graphics->getGamma( n,n,n,&dr,&dg,&db );
return dr;
}
float bbGammaGreen( int n ){
float dr,dg,db;
gx_graphics->getGamma( n,n,n,&dr,&dg,&db );
return dg;
}
float bbGammaBlue( int n ){
float dr,dg,db;
gx_graphics->getGamma( n,n,n,&dr,&dg,&db );
return db;
}
gxCanvas *bbFrontBuffer(){
return gx_graphics->getFrontCanvas();
}
gxCanvas *bbBackBuffer(){
return gx_graphics->getBackCanvas();
}
void bbLockBuffer( gxCanvas *buff ){
if( buff ) debugCanvas( buff );
(buff ? buff : gx_canvas)->lock();
}
void bbUnlockBuffer( gxCanvas *buff ){
if( buff ) debugCanvas( buff );
(buff ? buff : gx_canvas)->unlock();
}
int bbReadPixel( int x,int y,gxCanvas *buff ){
if( buff ) debugCanvas( buff );
return (buff ? buff : gx_canvas)->getPixel( x,y );
}
void bbWritePixel( int x,int y,int argb,gxCanvas *buff ){
if( buff ) debugCanvas( buff );
(buff ? buff : gx_canvas)->setPixel( x,y,argb );
}
int bbReadPixelFast( int x,int y,gxCanvas *buff ){
return (buff ? buff : gx_canvas)->getPixelFast( x,y );
}
void bbWritePixelFast( int x,int y,int argb,gxCanvas *buff ){
(buff ? buff : gx_canvas)->setPixelFast( x,y,argb );
}
void bbCopyPixel( int src_x,int src_y,gxCanvas *src,int dest_x,int dest_y,gxCanvas *buff ){
(buff ? buff : gx_canvas)->copyPixel( dest_x,dest_y,src ? src : gx_canvas,src_x,src_y );
}
void bbCopyPixelFast( int src_x,int src_y,gxCanvas *src,int dest_x,int dest_y,gxCanvas *buff ){
(buff ? buff : gx_canvas)->copyPixelFast( dest_x,dest_y,src ? src : gx_canvas,src_x,src_y );
}
int bbScanLine(){
return gx_graphics->getScanLine();
}
void bbVWait( int n ){
gx_graphics->vwait();
if( !gx_runtime->idle() ) RTEX( 0 );
}
void bbFlip( int vwait ){
gx_graphics->flip( vwait ? true : false );
if( !gx_runtime->idle() ) RTEX( 0 );
}
int bbGraphicsWidth(){
return gx_graphics->getWidth();
}
int bbGraphicsHeight(){
return gx_graphics->getHeight();
}
int bbGraphicsDepth(){
return gx_graphics->getDepth();
}
void bbOrigin( int x,int y ){
gx_canvas->setOrigin( x,y );
}
void bbViewport( int x,int y,int w,int h ){
gx_canvas->setViewport( x,y,w,h );
}
void bbColor( int r,int g,int b ){
gx_canvas->setColor( curr_color=(r<<16)|(g<<8)|b );
}
void bbGetColor( int x,int y ){
gx_canvas->setColor( curr_color=gx_canvas->getPixel( x,y ) );
}
int bbColorRed(){
return (gx_canvas->getColor()>>16)&0xff;
}
int bbColorGreen(){
return (gx_canvas->getColor()>>8)&0xff;
}
int bbColorBlue(){
return gx_canvas->getColor()&0xff;
}
void bbClsColor( int r,int g,int b ){
gx_canvas->setClsColor( curr_clsColor=(r<<16)|(g<<8)|b );
}
void bbSetFont( gxFont *f ){
debugFont( f );
gx_canvas->setFont( curr_font=f );
}
void bbCls(){
gx_canvas->cls();
}
void bbPlot( int x,int y ){
gx_canvas->plot( x,y );
}
void bbLine( int x1,int y1,int x2,int y2 ){
gx_canvas->line( x1,y1,x2,y2 );
}
void bbRect( int x,int y,int w,int h,int solid ){
gx_canvas->rect( x,y,w,h,solid ? true : false );
}
void bbOval( int x,int y,int w,int h,int solid ){
gx_canvas->oval( x,y,w,h,solid ? true : false );
}
void bbText( int x,int y,BBStr *str,int centre_x,int centre_y ){
if( centre_x ) x-=curr_font->getWidth( *str )/2;
if( centre_y ) y-=curr_font->getHeight()/2;
gx_canvas->text( x,y,*str );
delete str;
}
void bbCopyRect( int sx,int sy,int w,int h,int dx,int dy,gxCanvas *src,gxCanvas *dest ){
if( src ) debugCanvas( src );
else src=gx_canvas;
if( dest ) debugCanvas( dest );
else dest=gx_canvas;
dest->blit( dx,dy,src,sx,sy,w,h,true );
}
gxFont *bbLoadFont( BBStr *name,int height,int bold,int italic,int underline ){
int flags=
(bold ? gxFont::FONT_BOLD : 0 ) |
(italic ? gxFont::FONT_ITALIC : 0 ) |
(underline ? gxFont::FONT_UNDERLINE : 0 );
gxFont *font=gx_graphics->loadFont( *name,height,flags );
delete name;
return font;
}
void bbFreeFont( gxFont *f ){
debugFont( f );
if( f==curr_font ) bbSetFont( gx_graphics->getDefaultFont() );
gx_graphics->freeFont( f );
}
int bbFontWidth(){
return curr_font->getWidth();
}
int bbFontHeight(){
return curr_font->getHeight();
}
int bbStringWidth( BBStr *str ){
string t=*str;delete str;
return curr_font->getWidth( t );
}
int bbStringHeight( BBStr *str ){
delete str;
return curr_font->getHeight();
}
gxMovie *bbOpenMovie( BBStr *s ){
gxMovie *movie=gx_graphics->openMovie( *s,0 );delete s;
return movie;
}
int bbDrawMovie( gxMovie *movie,int x,int y,int w,int h ){
if( w<0 ) w=movie->getWidth();
if( h<0 ) h=movie->getHeight();
int playing=movie->draw( gx_canvas,x,y,w,h );
if( !gx_runtime->idle() ) RTEX( 0 );
return playing;
}
int bbMovieWidth( gxMovie *movie ){
return movie->getWidth();
}
int bbMovieHeight( gxMovie *movie ){
return movie->getHeight();
}
int bbMoviePlaying( gxMovie *movie ){
return movie->isPlaying();
}
void bbCloseMovie( gxMovie *movie ){
gx_graphics->closeMovie( movie );
}
bbImage *bbLoadImage( BBStr *s ){
string t=*s;delete s;
gxCanvas *c=gx_graphics->loadCanvas( t,0 );
if( !c ) return 0;
if( auto_dirty ) c->backup();
if( auto_midhandle ) c->setHandle( c->getWidth()/2,c->getHeight()/2 );
vector<gxCanvas*> frames;
frames.push_back( c );
bbImage *i=d_new bbImage( frames );
image_set.insert( i );
return i;
}
bbImage *bbLoadAnimImage( BBStr *s,int w,int h,int first,int cnt ){
string t=*s;delete s;
if( cnt<1 ) RTEX( "Illegal frame count" );
if( first<0 ) RTEX( "Illegal first frame" );
gxCanvas *pic=gx_graphics->loadCanvas( t,gxCanvas::CANVAS_NONDISPLAY );
if( !pic ) return 0;
//frames per row, per picture
int fpr=pic->getWidth()/w;
int fpp=pic->getHeight()/h*fpr;
if( first+cnt>fpp ){
gx_graphics->freeCanvas( pic );
RTEX( "Not enough frames in bitmap" );
}
//x,y of first frame...
vector<gxCanvas*> frames;
int src_x=first%fpr*w,src_y=first/fpr*h;
for( int k=0;k<cnt;++k ){
gxCanvas *c=gx_graphics->createCanvas( w,h,0 );
if( !c ){
for( --k;k>=0;--k ) gx_graphics->freeCanvas( frames[k] );
gx_graphics->freeCanvas( pic );return 0;
}
c->blit( 0,0,pic,src_x,src_y,w,h,true );
if( auto_dirty ) c->backup();
if( auto_midhandle ) c->setHandle( c->getWidth()/2,c->getHeight()/2 );
frames.push_back( c );
src_x+=w;if( src_x+w>pic->getWidth() ){ src_x=0;src_y+=h; }
}
gx_graphics->freeCanvas( pic );
bbImage *i=d_new bbImage( frames );
image_set.insert( i );
return i;
}
bbImage *bbCopyImage( bbImage *i ){
debugImage( i );
vector<gxCanvas*> frames;
const vector<gxCanvas*> &f=i->getFrames();
for( int k=0;k<f.size();++k ){
gxCanvas *t=f[k];
gxCanvas *c=gx_graphics->createCanvas( t->getWidth(),t->getHeight(),0 );
if( !c ){
for( --k;k>=0;--k ) gx_graphics->freeCanvas( frames[k] );
return 0;
}
int x,y;
t->getHandle( &x,&y );
t->setHandle( 0,0 );
c->blit( 0,0,t,0,0,t->getWidth(),t->getHeight(),true );
if( auto_dirty ) c->backup();
t->setHandle( x,y );
c->setHandle( x,y );
c->setMask( t->getMask() );
frames.push_back( c );
}
bbImage *t=d_new bbImage( frames );
image_set.insert( t );
return t;
}
bbImage *bbCreateImage( int w,int h,int n ){
vector<gxCanvas*> frames;
for( int k=0;k<n;++k ){
gxCanvas *c=gx_graphics->createCanvas( w,h,0 );
if( !c ){
for( --k;k>=0;--k ) gx_graphics->freeCanvas( frames[k] );
return 0;
}
if( auto_dirty ) c->backup();
if( auto_midhandle ) c->setHandle( c->getWidth()/2,c->getHeight()/2 );
frames.push_back( c );
}
bbImage *i=d_new bbImage( frames );
image_set.insert( i );
return i;
}
void bbFreeImage( bbImage *i ){
if( !image_set.erase(i) ) return;
const vector<gxCanvas*> &f=i->getFrames();
for( int k=0;k<f.size();++k ){
if( f[k]==gx_canvas ){
bbSetBuffer( gx_graphics->getFrontCanvas() );
break;
}
}
delete i;
}
int bbSaveImage( bbImage *i,BBStr *str,int n ){
debugImage( i,n );
string t=*str;delete str;
gxCanvas *c=i->getFrames()[n];
return saveCanvas( c,t ) ? 1 : 0;
}
void bbGrabImage( bbImage *i,int x,int y,int n ){
debugImage( i,n );
gxCanvas *c=i->getFrames()[n];
int src_ox,src_oy,dst_hx,dst_hy;
gx_canvas->getOrigin( &src_ox,&src_oy );
c->getHandle( &dst_hx,&dst_hy );
x+=src_ox-dst_hx;y+=src_oy-dst_hy;
c->setViewport( 0,0,c->getWidth(),c->getHeight() );
c->blit( 0,0,gx_canvas,x,y,c->getWidth(),c->getHeight(),true );
if( auto_dirty ) c->backup();
}
gxCanvas *bbImageBuffer( bbImage *i,int n ){
debugImage( i,n );
return i->getFrames()[n];
}
void bbDrawImage( bbImage *i,int x,int y,int frame ){
debugImage( i,frame );
gxCanvas *c=i->getFrames()[frame];
gx_canvas->blit( x,y,c,0,0,c->getWidth(),c->getHeight(),false );
}
void bbDrawBlock( bbImage *i,int x,int y,int frame ){
debugImage( i,frame );
gxCanvas *c=i->getFrames()[frame];
gx_canvas->blit( x,y,c,0,0,c->getWidth(),c->getHeight(),true );
}
static void tile( bbImage *i,int x,int y,int frame,bool solid ){
gxCanvas *c=i->getFrames()[frame];
int hx,hy;
c->getHandle( &hx,&hy );
int w=c->getWidth(),h=c->getHeight();
int ox,oy,vp_x,vp_y,vp_w,vp_h;
gx_canvas->getOrigin( &ox,&oy );
gx_canvas->getViewport( &vp_x,&vp_y,&vp_w,&vp_h );
int dx=vp_x-ox+hx;
int dy=vp_y-oy+hy;
x-=dx;
y-=dy;
dx+=(x>=0?x%w:w-(-x%w));
dy+=(y>=0?y%h:h-(-y%h));
for( y=-h;y<vp_h;y+=h ){
for( x=-w;x<vp_w;x+=w ){
gx_canvas->blit( x+dx,y+dy,c,0,0,w,h,solid );
}
}
}
void bbTileImage( bbImage *i,int x,int y,int frame ){
debugImage( i,frame );
tile( i,x,y,frame,false );
}
void bbTileBlock( bbImage *i,int x,int y,int frame ){
debugImage( i,frame );
tile( i,x,y,frame,true );
}
void bbDrawImageRect( bbImage *i,int x,int y,int r_x,int r_y,int r_w,int r_h,int frame ){
debugImage( i,frame );
gxCanvas *c=i->getFrames()[frame];
gx_canvas->blit( x,y,c,r_x,r_y,r_w,r_h,false );
}
void bbDrawBlockRect( bbImage *i,int x,int y,int r_x,int r_y,int r_w,int r_h,int frame ){
debugImage( i,frame );
gxCanvas *c=i->getFrames()[frame];
gx_canvas->blit( x,y,c,r_x,r_y,r_w,r_h,true );
}
void bbMaskImage( bbImage *i,int r,int g,int b ){
debugImage( i );
unsigned argb=(r<<16)|(g<<8)|b;
const vector<gxCanvas*> &f=i->getFrames();
for( int k=0;k<f.size();++k ) f[k]->setMask( argb );
}
void bbHandleImage( bbImage *i,int x,int y ){
debugImage( i );
const vector<gxCanvas*> &f=i->getFrames();
for( int k=0;k<f.size();++k ) f[k]->setHandle( x,y );
}
void bbMidHandle( bbImage *i ){
debugImage( i );
const vector<gxCanvas*> &f=i->getFrames();
for( int k=0;k<f.size();++k ) f[k]->setHandle( f[k]->getWidth()/2,f[k]->getHeight()/2 );
}
void bbAutoMidHandle( int enable ){
auto_midhandle=enable ? true : false;
}
int bbImageWidth( bbImage *i ){
debugImage( i );
return i->getFrames()[0]->getWidth();
}
int bbImageHeight( bbImage *i ){
debugImage( i );
return i->getFrames()[0]->getHeight();
}
int bbImageXHandle( bbImage *i ){
debugImage( i );
int x,y;
i->getFrames()[0]->getHandle( &x,&y );
return x;
}
int bbImageYHandle( bbImage *i ){
debugImage( i );
int x,y;
i->getFrames()[0]->getHandle( &x,&y );
return y;
}
int bbImagesOverlap( bbImage *i1,int x1,int y1,bbImage *i2,int x2,int y2 ){
debugImage( i1 );
debugImage( i2 );
gxCanvas *c1=i1->getFrames()[0];
gxCanvas *c2=i2->getFrames()[0];
return c1->collide( x1,y1,c2,x2,y2,true );
}
int bbImagesCollide( bbImage *i1,int x1,int y1,int f1,bbImage *i2,int x2,int y2,int f2 ){
debugImage( i1,f1 );
debugImage( i2,f2 );
gxCanvas *c1=i1->getFrames()[f1];
gxCanvas *c2=i2->getFrames()[f2];
return c1->collide( x1,y1,c2,x2,y2,false );
}
int bbRectsOverlap( int x1,int y1,int w1,int h1,int x2,int y2,int w2,int h2 ){
if( x1+w1<=x2 || x1>=x2+w2 || y1+h1<=y2 || y1>=y2+h2 ) return 0;
return 1;
}
int bbImageRectOverlap( bbImage *i,int x,int y,int x2,int y2,int w2,int h2 ){
debugImage( i );
gxCanvas *c=i->getFrames()[0];
return c->rect_collide( x,y,x2,y2,w2,h2,true );
}
int bbImageRectCollide( bbImage *i,int x,int y,int f,int x2,int y2,int w2,int h2 ){
debugImage( i,f );
gxCanvas *c=i->getFrames()[f];
return c->rect_collide( x,y,x2,y2,w2,h2,false );
}
void bbTFormImage( bbImage *i,float a,float b,float c,float d ){
debugImage( i );
const vector<gxCanvas*> &f=i->getFrames();
int k;
for( k=0;k<f.size();++k ){
if( f[k]==gx_canvas ){
bbSetBuffer( gx_graphics->getFrontCanvas() );
break;
}
}
float m[2][2];
m[0][0]=a;m[1][0]=b;m[0][1]=c;m[1][1]=d;
for( k=0;k<f.size();++k ){
gxCanvas *c=f[k];
int hx,hy;c->getHandle( &hx,&hy );
gxCanvas *t=tformCanvas( c,m,hx,hy );
i->replaceFrame( k,t );
t->backup();
}
}
void bbScaleImage( bbImage *i,float w,float h ){
debugImage( i );
bbTFormImage( i,w,0,0,h );
}
void bbResizeImage( bbImage *i,float w,float h ){
debugImage( i );
gxCanvas *c=i->getFrames()[0];
bbTFormImage( i,w/(float)c->getWidth(),0,0,h/(float)c->getHeight() );
}
void bbRotateImage( bbImage *i,float d ){
debugImage( i );
d*=-dtor;
bbTFormImage( i,cos(d),-sin(d),sin(d),cos(d) );
}
void bbTFormFilter( int enable ){
filter=enable ? true : false;
}
static int p_ox,p_oy,p_hx,p_hy,p_vpx,p_vpy,p_vpw,p_vph;
static gxCanvas *startPrinting(){
gxCanvas *c=gx_graphics->getFrontCanvas();
c->lock();
c->unlock();
c->getOrigin( &p_ox,&p_oy );
c->getHandle( &p_hx,&p_hy );
c->getViewport( &p_vpx,&p_vpy,&p_vpw,&p_vph );
c->setOrigin( 0,0 );
c->setHandle( 0,0 );
c->setViewport( 0,0,c->getWidth(),c->getHeight() );
if( c!=gx_canvas ){
c->setFont( curr_font );
c->setColor( curr_color );
}
int dy=curs_y+curr_font->getHeight()-c->getHeight();
if( dy>0 ){
curs_y=c->getHeight()-curr_font->getHeight();
c->blit( 0,0,c,0,dy,c->getWidth(),c->getHeight()-dy,true );
c->setColor( curr_clsColor );
c->rect( 0,c->getHeight()-dy,c->getWidth(),dy,true );
c->setColor( curr_color );
}
return c;
}
static void endPrinting( gxCanvas *c ){
c->setViewport( p_vpx,p_vpy,p_vpw,p_vph );
c->setHandle( p_hx,p_hy );
c->setOrigin( p_ox,p_oy );
if( c==gx_canvas ) c->setColor( curr_color );
if( !gx_runtime->idle() ) RTEX( 0 );
}
void bbWrite( BBStr *str ){
gxCanvas *c=startPrinting();
c->text( curs_x,curs_y,*str );
curs_x+=curr_font->getWidth( *str );
endPrinting( c );
delete str;
}
void bbPrint( BBStr *str ){
gxCanvas *c=startPrinting();
c->text( curs_x,curs_y,*str );
curs_x=0;
curs_y+=curr_font->getHeight();
endPrinting( c );
delete str;
}
BBStr *bbInput( BBStr *prompt ){
gxCanvas *c=startPrinting();
string t=*prompt;delete prompt;
//get temp canvas
if( !p_canvas || p_canvas->getWidth()<c->getWidth() || p_canvas->getHeight()<curr_font->getHeight()*2 ){
if( p_canvas ) gx_graphics->freeCanvas( p_canvas );
p_canvas=gx_graphics->createCanvas( c->getWidth(),curr_font->getHeight()*2,0 );
if( !p_canvas ){
endPrinting(c);
return d_new BBStr();
}
}
//draw prompt
c->text( curs_x,curs_y,t );
curs_x+=curr_font->getWidth( t );
p_canvas->setFont( curr_font );
p_canvas->setColor( curr_color );
p_canvas->blit( 0,0,c,0,curs_y,c->getWidth(),curr_font->getHeight(),true );
string str;
bool go=true;
int curs=0,last_key=0,last_time,rep_delay;
while( go ){
//render all text
//calc curs x and width
int cx=curs_x+curr_font->getWidth( str.substr( 0,curs ) );
int cw=curr_font->getWidth( curs<str.size() ? str.substr( curs,1 ) : "X" );
//wait for a key
int key=0,st=gx_runtime->getMilliSecs(),tc=-1;
while( gx_runtime->idle() ){
int t=gx_runtime->getMilliSecs();
int n=(t-st)/320;
if( n!=tc ){
tc=n;
if( !(tc&1) ){ //cursor ON
c->setColor( curr_clsColor^0xffffff );
c->rect( cx,curs_y,cw,curr_font->getHeight(),true );
c->setColor( curr_clsColor );
}else{ //cursor OFF
c->blit( cx,curs_y,p_canvas,cx,0,cw,curr_font->getHeight(),true );
c->setColor( curr_color );
}
c->text( cx,curs_y,str.substr( curs,1 ) );
}
if( key=gx_keyboard->getKey() ){
if( int asc=gx_input->toAscii( key ) ){
rep_delay=280;
last_key=key;
last_time=t;
key=asc;
break;
}
}
if( last_key && gx_keyboard->keyDown( last_key ) ){
if( t-last_time>rep_delay ){
if( key=gx_input->toAscii( last_key ) ){
last_time+=rep_delay;
rep_delay=40;
break;
}
}
}else last_key=0;
gx_runtime->delay( 20 );
}
//check the key
switch( key ){
case 0:
go=false;
str="";
break;
case 8:
if( curs ){
str=str.substr( 0,curs-1 )+str.substr( curs );
--curs;
}
break;
case 27:
curs=0;str="";
break;
case gxInput::ASC_DELETE:
if( curs<str.size() ) str=str.substr( 0,curs )+str.substr( curs+1 );
break;
case gxInput::ASC_HOME:
curs=0;
break;
case gxInput::ASC_END:
curs=str.size();
break;
case gxInput::ASC_LEFT:
if( curs ) --curs;
break;
case gxInput::ASC_RIGHT:
if( curs<str.size() ) ++curs;
break;
case '\r':
go=false;
break;
default:
if( curr_font->isPrintable( key ) ){
str=str.substr(0,curs)+char(key)+str.substr(curs);
++curs;
}
}
//render text
p_canvas->blit( 0,curr_font->getHeight(),p_canvas,0,0,c->getWidth(),curr_font->getHeight(),true );
p_canvas->text( curs_x,curr_font->getHeight(),str );
c->blit( 0,curs_y,p_canvas,0,curr_font->getHeight(),c->getWidth(),curr_font->getHeight(),true );
}
curs_x=0;
curs_y+=curr_font->getHeight();
endPrinting( c );
return d_new BBStr( str );
}
void bbLocate( int x,int y ){
gxCanvas *c=gx_graphics->getFrontCanvas();
curs_x=x<0 ? 0 : (x > c->getWidth() ? c->getWidth() : x);
curs_y=y<0 ? 0 : (y > c->getHeight() ? c->getHeight() : y);
}
void bbShowPointer(){
gx_runtime->setPointerVisible( true );
}
void bbHidePointer(){
gx_runtime->setPointerVisible( false );
}
bool graphics_create(){
p_canvas=0;
filter=true;
gx_driver=0;
freeGraphics();
auto_dirty=true;
auto_midhandle=false;
gx_graphics=gx_runtime->openGraphics( 400,300,0,0,gxGraphics::GRAPHICS_WINDOWED );
if( gx_graphics ){
curr_clsColor=0;
curr_color=0xffffffff;
curr_font=gx_graphics->getDefaultFont();
bbSetBuffer( bbFrontBuffer() );
return true;
}
return false;
}
bool graphics_destroy(){
freeGraphics();
gfx_modes.clear();
if( gx_graphics ){
gx_runtime->closeGraphics( gx_graphics );
gx_graphics=0;
}
return true;
}
void graphics_link( void (*rtSym)( const char *sym,void *pc ) ){
//gfx driver info
rtSym( "%CountGfxDrivers",bbCountGfxDrivers );
rtSym( "$GfxDriverName%driver",bbGfxDriverName );
rtSym( "SetGfxDriver%driver",bbSetGfxDriver );
//gfx mode info
rtSym( "%CountGfxModes",bbCountGfxModes );
rtSym( "%GfxModeExists%width%height%depth",bbGfxModeExists );
rtSym( "%GfxModeWidth%mode",bbGfxModeWidth );
rtSym( "%GfxModeHeight%mode",bbGfxModeHeight );
rtSym( "%GfxModeDepth%mode",bbGfxModeDepth );
rtSym( "%AvailVidMem",bbAvailVidMem );
rtSym( "%TotalVidMem",bbTotalVidMem );
#ifdef PRO
rtSym( "%GfxDriver3D%driver",bbGfxDriver3D );
rtSym( "%CountGfxModes3D",bbCountGfxModes3D );
rtSym( "%GfxMode3DExists%width%height%depth",bbGfxMode3DExists );
rtSym( "%GfxMode3D%mode",bbGfxMode3D );
rtSym( "%Windowed3D",bbWindowed3D );
#endif
//display mode
rtSym( "Graphics%width%height%depth=0%mode=0",bbGraphics );
#ifdef PRO
rtSym( "Graphics3D%width%height%depth=0%mode=0",bbGraphics3D );
#endif
rtSym( "EndGraphics",bbEndGraphics );
rtSym( "%GraphicsLost",bbGraphicsLost );
rtSym( "SetGamma%src_red%src_green%src_blue#dest_red#dest_green#dest_blue",bbSetGamma );
rtSym( "UpdateGamma%calibrate=0",bbUpdateGamma );
rtSym( "#GammaRed%red",bbGammaRed );
rtSym( "#GammaGreen%green",bbGammaGreen );
rtSym( "#GammaBlue%blue",bbGammaBlue );
rtSym( "%FrontBuffer",bbFrontBuffer );
rtSym( "%BackBuffer",bbBackBuffer );
rtSym( "%ScanLine",bbScanLine );
rtSym( "VWait%frames=1",bbVWait );
rtSym( "Flip%vwait=1",bbFlip );
rtSym( "%GraphicsWidth",bbGraphicsWidth );
rtSym( "%GraphicsHeight",bbGraphicsHeight );
rtSym( "%GraphicsDepth",bbGraphicsDepth );
//buffer management
rtSym( "SetBuffer%buffer",bbSetBuffer );
rtSym( "%GraphicsBuffer",bbGraphicsBuffer );
rtSym( "%LoadBuffer%buffer$bmpfile",bbLoadBuffer );
rtSym( "%SaveBuffer%buffer$bmpfile",bbSaveBuffer );
rtSym( "BufferDirty%buffer",bbBufferDirty );
//fast pixel reads/write
rtSym( "LockBuffer%buffer=0",bbLockBuffer );
rtSym( "UnlockBuffer%buffer=0",bbUnlockBuffer );
rtSym( "%ReadPixel%x%y%buffer=0",bbReadPixel );
rtSym( "WritePixel%x%y%argb%buffer=0",bbWritePixel );
rtSym( "%ReadPixelFast%x%y%buffer=0",bbReadPixelFast );
rtSym( "WritePixelFast%x%y%argb%buffer=0",bbWritePixelFast );
rtSym( "CopyPixel%src_x%src_y%src_buffer%dest_x%dest_y%dest_buffer=0",bbCopyPixel );
rtSym( "CopyPixelFast%src_x%src_y%src_buffer%dest_x%dest_y%dest_buffer=0",bbCopyPixelFast );
//rendering
rtSym( "Origin%x%y",bbOrigin );
rtSym( "Viewport%x%y%width%height",bbViewport );
rtSym( "Color%red%green%blue",bbColor );
rtSym( "GetColor%x%y",bbGetColor );
rtSym( "%ColorRed",bbColorRed );
rtSym( "%ColorGreen",bbColorGreen );
rtSym( "%ColorBlue",bbColorBlue );
rtSym( "ClsColor%red%green%blue",bbClsColor );
rtSym( "SetFont%font",bbSetFont );
rtSym( "Cls",bbCls );
rtSym( "Plot%x%y",bbPlot );
rtSym( "Rect%x%y%width%height%solid=1",bbRect );
rtSym( "Oval%x%y%width%height%solid=1",bbOval );
rtSym( "Line%x1%y1%x2%y2",bbLine );
rtSym( "Text%x%y$text%centre_x=0%centre_y=0",bbText );
rtSym( "CopyRect%source_x%source_y%width%height%dest_x%dest_y%src_buffer=0%dest_buffer=0",bbCopyRect );
//fonts
rtSym( "%LoadFont$fontname%height=12%bold=0%italic=0%underline=0",bbLoadFont );
rtSym( "FreeFont%font",bbFreeFont );
rtSym( "%FontWidth",bbFontWidth );
rtSym( "%FontHeight",bbFontHeight );
rtSym( "%StringWidth$string",bbStringWidth );
rtSym( "%StringHeight$string",bbStringHeight );
//movies
rtSym( "%OpenMovie$file",bbOpenMovie );
rtSym( "%DrawMovie%movie%x=0%y=0%w=-1%h=-1",bbDrawMovie );
rtSym( "%MovieWidth%movie",bbMovieWidth );
rtSym( "%MovieHeight%movie",bbMovieHeight );
rtSym( "%MoviePlaying%movie",bbMoviePlaying );
rtSym( "CloseMovie%movie",bbCloseMovie );
rtSym( "%LoadImage$bmpfile",bbLoadImage );
rtSym( "%LoadAnimImage$bmpfile%cellwidth%cellheight%first%count",bbLoadAnimImage );
rtSym( "%CopyImage%image",bbCopyImage );
rtSym( "%CreateImage%width%height%frames=1",bbCreateImage );
rtSym( "FreeImage%image",bbFreeImage );
rtSym( "%SaveImage%image$bmpfile%frame=0",bbSaveImage );
rtSym( "GrabImage%image%x%y%frame=0",bbGrabImage );
rtSym( "%ImageBuffer%image%frame=0",bbImageBuffer );
rtSym( "DrawImage%image%x%y%frame=0",bbDrawImage );
rtSym( "DrawBlock%image%x%y%frame=0",bbDrawBlock );
rtSym( "TileImage%image%x=0%y=0%frame=0",bbTileImage );
rtSym( "TileBlock%image%x=0%y=0%frame=0",bbTileBlock );
rtSym( "DrawImageRect%image%x%y%rect_x%rect_y%rect_width%rect_height%frame=0",bbDrawImageRect );
rtSym( "DrawBlockRect%image%x%y%rect_x%rect_y%rect_width%rect_height%frame=0",bbDrawBlockRect );
rtSym( "MaskImage%image%red%green%blue",bbMaskImage );
rtSym( "HandleImage%image%x%y",bbHandleImage );
rtSym( "MidHandle%image",bbMidHandle );
rtSym( "AutoMidHandle%enable",bbAutoMidHandle );
rtSym( "%ImageWidth%image",bbImageWidth );
rtSym( "%ImageHeight%image",bbImageHeight );
rtSym( "%ImageXHandle%image",bbImageXHandle );
rtSym( "%ImageYHandle%image",bbImageYHandle );
rtSym( "ScaleImage%image#xscale#yscale",bbScaleImage );
rtSym( "ResizeImage%image#width#height",bbResizeImage );
rtSym( "RotateImage%image#angle",bbRotateImage );
rtSym( "TFormImage%image#a#b#c#d",bbTFormImage );
rtSym( "TFormFilter%enable",bbTFormFilter );
rtSym( "%ImagesOverlap%image1%x1%y1%image2%x2%y2",bbImagesOverlap );
rtSym( "%ImagesCollide%image1%x1%y1%frame1%image2%x2%y2%frame2",bbImagesCollide );
rtSym( "%RectsOverlap%x1%y1%width1%height1%x2%y2%width2%height2",bbRectsOverlap );
rtSym( "%ImageRectOverlap%image%x%y%rect_x%rect_y%rect_width%rect_height",bbImageRectOverlap );
rtSym( "%ImageRectCollide%image%x%y%frame%rect_x%rect_y%rect_width%rect_height",bbImageRectCollide );
rtSym( "Write$string",bbWrite );
rtSym( "Print$string=\"\"",bbPrint );
rtSym( "$Input$prompt=\"\"",bbInput );
rtSym( "Locate%x%y",bbLocate );
rtSym( "ShowPointer",bbShowPointer );
rtSym( "HidePointer",bbHidePointer );
}