diff --git a/src/include/deco.h b/src/include/deco.h index a25e92744..3247f5acb 100644 --- a/src/include/deco.h +++ b/src/include/deco.h @@ -124,6 +124,7 @@ extern Deco *DecorationAdd( void *data, unsigned x, unsigned y, unsigned w, unsigned h ); extern void DecorationRemove( Deco *d ); +extern void DecorationRemoveLevels( DecorationLevel min, DecorationLevel max ); extern void DecorationMark( Deco *d ); diff --git a/src/map/map_draw.cpp b/src/map/map_draw.cpp index ea3320e7a..735f6b373 100644 --- a/src/map/map_draw.cpp +++ b/src/map/map_draw.cpp @@ -1521,7 +1521,9 @@ global void MarkDrawEntireMap(void) #endif #ifdef NEW_DECODRAW - DecorationMark( mapdeco ); +// Hmm.. remove levels directly might not be a good idea, but it is faster ;) +// DecorationRemoveLevels( LevCarLow, LevSkyHighest ); +// DecorationMark( mapdeco ); #endif MustRedraw|=RedrawMap; diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp index e94dbfc26..2706d3e24 100644 --- a/src/unit/unit.cpp +++ b/src/unit/unit.cpp @@ -1149,10 +1149,12 @@ global int CheckUnitToBeDrawn(const Unit * unit) #else #ifdef NEW_DECODRAW if ( !unit->Removed && UnitVisibleOnScreen(unit) ) { - int x = Map2ScreenX(unit->X)+unit->IX; - int y = Map2ScreenY(unit->Y)+unit->IY; - int w = unit->Type->BoxWidth; - int h = unit->Type->BoxHeight; + // FIXME: Inaccurate dimension to take unit's extras into account.. + // Should be solved by adding each unit extra as separate decoration + int x = Map2ScreenX(unit->X)+unit->IX-10; + int y = Map2ScreenY(unit->Y)+unit->IY-10; + int w = unit->Type->Width+20; + int h = unit->Type->Height+20; if ( unit->deco ) { diff --git a/src/unit/unit_draw.cpp b/src/unit/unit_draw.cpp index 973aa924c..4c0ee29e3 100644 --- a/src/unit/unit_draw.cpp +++ b/src/unit/unit_draw.cpp @@ -1340,7 +1340,10 @@ local void DrawUnit(const Unit* unit) GraphicPlayerPixels(unit->Player,type->Sprite); DrawUnitType(type,unit->Frame,x,y); +#ifndef NEW_DECODRAW +// Unit's extras not fully supported.. need to be deocrations themselves. DrawInformations(unit,type,x,y); +#endif } /** diff --git a/src/video/deco.cpp b/src/video/deco.cpp index be605fda2..60fc81efd 100644 --- a/src/video/deco.cpp +++ b/src/video/deco.cpp @@ -346,6 +346,7 @@ extern Deco *DecorationAdd( void *data, unsigned x, unsigned y, unsigned w, unsigned h ); extern void DecorationRemove( Deco *d ); +extern void DecorationRemoveLevels( DecorationLevel min, DecorationLevel max ); extern void DecorationMark( Deco *d ); @@ -568,6 +569,41 @@ void DecorationRemove( Deco *d ) while ( t ); } +/** +** Remove all decorations belonging to a range of levels at once.. +** +** @param min = first level to remove +** @param max = last level to remove (higher or equal to min) +**/ +void DecorationRemoveLevels( DecorationLevel min, DecorationLevel max ) +{ + DebugCheck( min > max || max == LevCount ); + + do + { + Deco *d; + + while ( (d=dhead[ min ]) ) + { + DecorationSingle *t, *tmp; + + DecorationMark( d ); + t = d->singles; + DecorationDelete( d ); + do + { + tmp = t; + t = t->nxt; + DecorationSingleDelete( tmp ); + } + while ( t ); + + dhead[ min ] = d->nxt; + } + } + while ( ++min < max ); +} + /** ** Clears the dirtyscreen array, making all tiles 'unmarked' ** FIXME: is there some way to get this fast? @@ -600,8 +636,8 @@ void DecorationInit(void) // Get memory for array dirtyscreen as 4x4bit matrixes each denoting 16 // tiles. So (dirtyscreen_xtiles*dirtyscreen_ytiles)/16 matrixes of 2 bytes - dirtyscreen_xbitmaps = 1 + dirtyscreen_xtiles / 4; - dirtyscreen_ybitmaps = 1 + dirtyscreen_ytiles / 4; + dirtyscreen_xbitmaps = 1 + (dirtyscreen_xtiles-1) / 4; + dirtyscreen_ybitmaps = 1 + (dirtyscreen_ytiles-1) / 4; dirtyscreen_size = dirtyscreen_xbitmaps * dirtyscreen_ybitmaps * 2; if ( dirtyscreen ) dirtyscreen = realloc( dirtyscreen, dirtyscreen_size ); @@ -626,6 +662,41 @@ void DecorationInit(void) } } +/* +** dirtyscreen = the array itself +** dirtyscreen_xtiles = no. 2-byte tiles horizontally (screen width) +** dirtyscreen_ytiles = no. 2-byte tiles vertically (screen height) +*/ +global void debugdirtyscreen(void) +{ + char *p; + unsigned int x, y, xbit, ybit, mask; + + printf( " " ); + for ( x=y=0; x<dirtyscreen_xtiles; y++ ) + if ( y % 5 == 0 ) + printf( " " ); + else printf("%d", x++ % 10 ); + printf( "\n" ); + + for ( y=0; y<dirtyscreen_ybitmaps; y++ ) + { + for ( ybit=0; ybit<4; ybit++ ) + { + printf( "%3d", y*4+ybit ); + p = dirtyscreen + y * dirtyscreen_xbitmaps * 2; + for ( x=0; x<dirtyscreen_xbitmaps; x++, p+=2 ) + { + mask = ((p[1] << 8) | p[0]) >> (ybit*4); + printf(" "); + for ( xbit=1; xbit<=8; xbit <<= 1 ) + printf( "%c", (mask & xbit) ? '1' : '0' ); + } + printf("\n"); + } + } +} + /** ** Marks given position on screen as 'dirty', which can later be checked ** to determine if something is overlapping it and to denote what needs to @@ -656,13 +727,13 @@ static void MarkPos( unsigned x, unsigned y ) // of char (8bit), where as sizeof(unsigned) can be bigger. // But to perform bit-operation on the 16bit element, we need to get the // 4x4bit matrix as type unsigned at tile-index y*dirtyscreen_xtiles+x, - // which is matrix-index tile-index/16 and char-index matrix-index*2 : - // p = dirtyscreen + ( (y*dirtyscreen_xtiles+x) / 16 ) * 2; - p = dirtyscreen + ((y*dirtyscreen_xtiles+x)>>3); - bits = (p[1] << 8) | p[0]; + // which is translated into 16bit bitmap-index as: + // p = dirtyscreen + ((y/4)*dirtyscreen_xbitmaps+(x/4))*2 + p = dirtyscreen + (((y>>2)*dirtyscreen_xbitmaps+(x>>2))<<1); // Mark the one bit refering to the tile (x,y) in least sig. 4x4 bits - bits |= ( 1 << ((x & 0x000F) + ((y & 0x000F)>>2)) ); + bits = (p[1] << 8) | p[0]; + bits |= ( 1 << ((x & 0x000F) + ((y & 0x000F)<<2)) ); p[0] = bits & 0x00FF; p[1] = (bits >> 8); } @@ -696,7 +767,7 @@ void MarkArea( int x, int y, int w, int h ) DebugCheck( w > dirtyscreen_xtiles || h > dirtyscreen_ytiles ); // Reference to top-left 4x4bit matrix containing tile (x,y) in dirtyscreen - tiles = dirtyscreen + ((y*dirtyscreen_xtiles+x)>>3); + tiles = dirtyscreen + (((y>>2)*dirtyscreen_xbitmaps+(x>>2))<<1); // Now scale (w,h) down to the number of 16bit elements (in a 4x4 bit matrix) // to check and denote when we need to check the four sides with a bitmask @@ -725,7 +796,7 @@ void MarkArea( int x, int y, int w, int h ) { // ymaskhead and ymasktail in same 4x4 matrix row --> combine to one if ( y >= dirtyscreen_ytiles - 4 ) // at bottom side of screen { // move one 4x4 matrix upwards to prevent acces outside 2D dimension - tiles -= 4 * 2 * dirtyscreen_xtiles; + tiles -= 2 * dirtyscreen_xbitmaps; ymasktail &= ymaskhead; ymaskhead = 0; } @@ -739,7 +810,7 @@ void MarkArea( int x, int y, int w, int h ) // // Mark the tiles with above bitmasks.. // - nextline=(dirtyscreen_xtiles-w)*2; + nextline=(dirtyscreen_xbitmaps-(w>>2))*2; w-=2; h-=2; @@ -845,7 +916,7 @@ static void CheckRedraw( Deco *d, DecorationSingle *t ) unsigned long topbits, bottombits, leftbits, rightbits, bits; top = t->tiles; - bottom = top + dirtyscreen_xtiles; + bottom = top + dirtyscreen_xbitmaps * 2; // Get left-top and -bottom 16bit 4x4 matrixes, masked to get the 'dirty' // area overlapped by this decoration in a single 32bit back to 16bit @@ -911,7 +982,11 @@ static void CheckRedraw( Deco *d, DecorationSingle *t ) } } -global decobits( unsigned long bits ) +/* +** FOR DEBUG PURPOSE ONLY +** Will print the given 16bit as 4x4 tiles. +*/ +global debugdecobits( unsigned int bits ) { int y; printf( "16bits as 4x4: 3210\n" ); @@ -924,36 +999,75 @@ global decobits( unsigned long bits ) } } -global singlebits( DecorationSingle *t ) +/* +** Convert 8x8 tiles from 4 16bit masks into 8x4 tiles in one 32bit, +** moving the set bits up with given bitshift in y-direction. +** For this to work only a 4x4 area within above 8x8 tiles might be set. +** +** @param ybitshift = a (full) bitshift to move bits to upper tile +** @param topleftmask = 16bit bitmask for top-left 4x4 tiles +** @param toprightmask = 16bit bitmask for top-right 4x4 tiles +** @param bottomleftmas k = 16bit bitmask for bottom-left 4x4 tiles +** @param bottomrightmask = 16bit bitmask for bottom-right 4x4 tiles +*/ +local unsigned long convert8x8to8x4( + int ybitshift, + unsigned int topleftmask, unsigned int toprightmask, + unsigned int bottomleftmask, unsigned int bottomrightmask ) { - unsigned long leftbits, rightbits, bits32; - int y; - int x; + unsigned long leftmask, rightmask; - leftbits = t->leftbottommask; - leftbits <<= 16; - leftbits |= t->lefttopmask; - leftbits >>= t->bity4; + leftmask = (unsigned long)bottomleftmask << 16; + leftmask |= topleftmask; + leftmask >>= ybitshift; - leftbits = ((leftbits & 0xF000) << 12) - | ((leftbits & 0x0F00) << 8) - | ((leftbits & 0x00F0) << 4) - | (leftbits & 0x000F); + leftmask = ((leftmask & 0xF000) << 12) + | ((leftmask & 0x0F00) << 8) + | ((leftmask & 0x00F0) << 4) + | (leftmask & 0x000F); - rightbits = t->rightbottommask; - rightbits <<= 16; - rightbits |= t->righttopmask; - rightbits >>= t->bity4; + rightmask = (unsigned long)bottomrightmask << 16; + rightmask |= toprightmask; + rightmask >>= ybitshift; - rightbits = ((rightbits & 0xF000) << 16) - | ((rightbits & 0x0F00) << 12) - | ((rightbits & 0x00F0) << 8) - | ((rightbits & 0x000F) << 4); + rightmask = ((rightmask & 0xF000) << 16) + | ((rightmask & 0x0F00) << 12) + | ((rightmask & 0x00F0) << 8) + | ((rightmask & 0x000F) << 4); - bits32 = rightbits | leftbits; + return leftmask | rightmask; +} +/* +** FOR DEBUG PURPOSE ONLY +** Will print the given t as separate bitvalues. +*/ +global debugsinglebits( DecorationSingle *t ) +{ + char *p; + unsigned long topleftscreen, toprightscreen, bottomleftscreen, + bottomrightscreen, leftbits, rightbits, bits32, mark32; + int y, x; + +// 2x2 16bit matrixes for 8x8 tiles translated to 8x4 tiles in one 32bit + bits32 = convert8x8to8x4( t->bity4, t->lefttopmask, t->righttopmask, + t->leftbottommask, t->rightbottommask ); + +// now the same for marked bits + p = t->tiles; + topleftscreen = (p[1] << 8) | p[0]; + toprightscreen = (p[3] << 8) | p[2]; + p = t->tiles + dirtyscreen_xbitmaps * 2; + bottomleftscreen = (p[1] << 8) | p[0]; + bottomrightscreen = (p[3] << 8) | p[2]; + mark32 = convert8x8to8x4( t->bity4, topleftscreen & t->lefttopmask, + toprightscreen & t->righttopmask, + bottomleftscreen & t->leftbottommask, + bottomrightscreen & t->rightbottommask ); + +// print 8x8 and 9x4 tiles representations printf( "DecorationSingle as 8x8 tiles\n" ); - printf( " 76543210\n "); + printf( " 76543210 76543210 76543210 76543210\n "); for ( x=7; t->bitx<x; x-- ) printf( " " ); printf( "^\n" ); @@ -962,12 +1076,28 @@ global singlebits( DecorationSingle *t ) for ( y=0; y<=7; y++ ) { printf( "%s%d ", (y * 4 == t->bity4) ? "-->" : " ", y ); + + for ( x=8; x; x>>=1 ) + printf( "%c", toprightscreen & x ? '1' : '0' ); + for ( x=8; x; x>>=1 ) + printf( "%c", topleftscreen & x ? '1' : '0' ); + + printf( " " ); for ( x=8; x; x>>=1 ) printf( "%c", rightbits & x ? '1' : '0' ); - rightbits >>= 4; for ( x=8; x; x>>=1 ) printf( "%c", leftbits & x ? '1' : '0' ); - leftbits >>= 4; + + printf( " " ); + for ( x=8; x; x>>=1 ) + printf( "%c", rightbits & toprightscreen & x ? '1' : '0' ); + for ( x=8; x; x>>=1 ) + printf( "%c", leftbits & topleftscreen & x ? '1' : '0' ); + + topleftscreen >>= 4; + toprightscreen >>= 4; + leftbits >>= 4; + rightbits >>= 4; if ( y < 4 ) { @@ -975,19 +1105,28 @@ global singlebits( DecorationSingle *t ) for ( x=128; x; x>>=1 ) printf( "%c", bits32 & x ? '1' : '0' ); bits32 >>= 8; + printf( " " ); + for ( x=128; x; x>>=1 ) + printf( "%c", mark32 & x ? '1' : '0' ); + mark32 >>= 8; } printf( "\n" ); if ( y == 3 ) { - leftbits = t->leftbottommask; + leftbits = t->leftbottommask; rightbits = t->rightbottommask; + topleftscreen = bottomleftscreen; + toprightscreen = bottomrightscreen; } } + printf( " (screen)&( deco )=(redraw) ( deco ) (redraw)\n"); } /** +** Will mark a DecorationSingle (restricted to 4x4 tiles) ** +** @param t = one DecorationSingle (will not follow its filed nxt!) **/ static void DecorationSingleMark( DecorationSingle *t ) { @@ -1008,7 +1147,7 @@ static void DecorationSingleMark( DecorationSingle *t ) p[3] = (bits >> 8); // Mark left-bottom 16bit 4x4 matrix with area overlapped by this decoration - p += dirtyscreen_xtiles; + p += dirtyscreen_xbitmaps * 2; bits = (p[1] << 8) | p[0]; bits |= t->leftbottommask; p[0] = bits & 0x00FF; @@ -1022,7 +1161,9 @@ static void DecorationSingleMark( DecorationSingle *t ) } /** +** Will mark a complete Decoration (maybe multiple DecorationSingle) ** +** @param d = Deco to completely mark **/ void DecorationMark( Deco *d ) { @@ -1065,7 +1206,7 @@ static DecorationSingle *DecorationSingleNew( unsigned x, unsigned y, DebugCheck( w > DECOSINGLE_TILES || h > DECOSINGLE_TILES ); // Reference to top-left 4x4bit matrix containing tile (x,y) in dirtyscreen - t->tiles = dirtyscreen + ((y*dirtyscreen_xtiles+x)>>3); + t->tiles = dirtyscreen + (((y>>2)*dirtyscreen_xbitmaps+(x>>2))<<1); // Now scale (w,h) down to the number of 16bit elements (in a 4x4 bit matrix) // to check and denote when we need to check the four sides with a bitmask @@ -1095,7 +1236,7 @@ static DecorationSingle *DecorationSingleNew( unsigned x, unsigned y, { // ymaskhead and ymasktail in same 4x4 matrix row --> combine to one if ( y >= dirtyscreen_ytiles - 4 ) // at bottom side of screen { // move one 4x4 matrix upwards to prevent acces outside 2D dimension - t->tiles -= 4 * 2 * dirtyscreen_xtiles; + t->tiles -= 2 * dirtyscreen_xbitmaps; ymasktail &= ymaskhead; ymaskhead = 0; } @@ -1146,9 +1287,6 @@ Deco *DecorationAdd( void *data, DecorationSingle **prevt; Deco *list, *d, *prv, **pprv; - DebugCheck( x < 0 || y < 0 || w <= 0 || h <= 0 || - (x+w) >= VideoWidth || (y+h) >= VideoHeight ); - // Allocate and fill in this new DecorationType so it can be used d = DecorationAllocate(); d->drawclip = drawclip; @@ -1159,7 +1297,7 @@ Deco *DecorationAdd( void *data, d->w = w; d->h = h; - // Restrict to screen (keeping original total location in d) + // Restrict to screen (keeping original total location in d for check later) if( x<0 ) { int ofs=-x; if( w<=ofs ) { @@ -1192,6 +1330,8 @@ Deco *DecorationAdd( void *data, } h=VideoHeight-y; } + DebugCheck( x < 0 || y < 0 || w <= 0 || h <= 0 || + (x+w) > VideoWidth || (y+h) > VideoHeight ); // Find entry for this decoration ordered on z(l):y:x and add it @@ -1248,16 +1388,17 @@ Deco *DecorationAdd( void *data, } /** -** -** +** Invalidate atleast that part of the screen that is marked dirty. +** (note that not the minimum area, but a somehwat bigger area can be +** invalidated for efficiency reasons). **/ static void InvalidateDirtyscreen(void) { char *p; unsigned bits, pixelx, pixely, pixelstep, dirtylinesize, xcount, ycount; - dirtylinesize = (dirtyscreen_xtiles/4)*2; - ycount = (dirtyscreen_ytiles/4)*2; + dirtylinesize = dirtyscreen_xbitmaps*2; + ycount = dirtyscreen_ybitmaps*2; pixelstep = 4 << DIRTYSCREEN_BITDETAIL; p = dirtyscreen; pixely = 0; diff --git a/src/video/sprite.cpp b/src/video/sprite.cpp index f8057fdca..9d026b982 100644 --- a/src/video/sprite.cpp +++ b/src/video/sprite.cpp @@ -391,13 +391,12 @@ global void VideoDraw8to8Clip(const Graphic* sprite,unsigned frame,int x,int y) const VMemType8* pixels; unsigned da; - ox=oy=0; - sw=w=sprite->Width; - h=sprite->Height; // // reduce to visible range // + sw=w=sprite->Width; + h=sprite->Height; CLIP_RECTANGLE_OFS(x,y,w,h,ox,oy,ex); // @@ -529,13 +528,11 @@ global void VideoDraw8to16Clip(const Graphic* sprite,unsigned frame,int x,int y) const VMemType16* pixels; unsigned da; - ox=oy=0; - sw=w=sprite->Width; - h=sprite->Height; - // // reduce to visible range // + sw=w=sprite->Width; + h=sprite->Height; CLIP_RECTANGLE_OFS(x,y,w,h,ox,oy,ex); // @@ -667,13 +664,11 @@ global void VideoDraw8to24Clip(const Graphic* sprite,unsigned frame,int x,int y) const VMemType24* pixels; unsigned da; - ox=oy=0; - sw=w=sprite->Width; - h=sprite->Height; - // // reduce to visible range // + sw=w=sprite->Width; + h=sprite->Height; CLIP_RECTANGLE_OFS(x,y,w,h,ox,oy,ex); // @@ -805,13 +800,11 @@ global void VideoDraw8to32Clip(const Graphic* sprite,unsigned frame,int x,int y) const VMemType32* pixels; unsigned da; - ox=oy=0; - sw=w=sprite->Width; - h=sprite->Height; - // // reduce to visible range // + sw=w=sprite->Width; + h=sprite->Height; CLIP_RECTANGLE_OFS(x,y,w,h,ox,oy,ex); // @@ -944,13 +937,11 @@ global void VideoDraw8to8ClipX(const Graphic* sprite,unsigned frame,int x,int y) const VMemType8* pixels; unsigned da; - ox=oy=0; - sw=w=sprite->Width; - h=sprite->Height; - // // reduce to visible range // + sw=w=sprite->Width; + h=sprite->Height; CLIP_RECTANGLE_OFS(x,y,w,h,ox,oy,ex); // @@ -1084,13 +1075,12 @@ global void VideoDraw8to16ClipX(const Graphic* sprite,unsigned frame const VMemType16* pixels; unsigned da; - ox=oy=0; - sw=w=sprite->Width; - h=sprite->Height; // // reduce to visible range // + sw=w=sprite->Width; + h=sprite->Height; CLIP_RECTANGLE_OFS(x,y,w,h,ox,oy,ex); // @@ -1224,13 +1214,11 @@ global void VideoDraw8to24ClipX(const Graphic* sprite,unsigned frame const VMemType24* pixels; unsigned da; - ox=oy=0; - sw=w=sprite->Width; - h=sprite->Height; - // // reduce to visible range // + sw=w=sprite->Width; + h=sprite->Height; CLIP_RECTANGLE_OFS(x,y,w,h,ox,oy,ex); // @@ -1364,13 +1352,11 @@ global void VideoDraw8to32ClipX(const Graphic* sprite,unsigned frame const VMemType32* pixels; unsigned da; - ox=oy=0; - sw=w=sprite->Width; - h=sprite->Height; - // // reduce to visible range // + sw=w=sprite->Width; + h=sprite->Height; CLIP_RECTANGLE_OFS(x,y,w,h,ox,oy,ex); //