dougmencken/HeadOverHeels

Problems with shadows

Closed this issue · 8 comments

Why that same shadow needs to be casted nine times?

casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=144
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=144
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=144
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=144
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=144
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=144
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=144
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=144
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=144
casting shadow from free item "bars-ns" at x=4 y=127 z=144 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=96 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=144 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=96 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=144 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=96 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=144 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=96 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=144 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=96 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=144 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=96 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=144 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=96 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=144 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=96 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=144 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=96 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=48

I’m going to extract code which deals with casting of shadows at its lowest level into ShadowCaster class, possibly simplifying such code

differences between shading free & grid items are

--- a/grid
+++ b/free
@@ -1,9 +1,9 @@
 /* static */
-void ShadowCaster::castShadowImageOnGridItem( Item* thatItem, int x, int y, BITMAP* shadow, unsigned short shading, unsigned char transparency )
+void ShadowCaster::castShadowImageOnFreeItem( Item* thatItem, int x, int y, BITMAP* shadow, unsigned short shading, unsigned char transparency )
 {
-        if ( thatItem->whichKindOfItem() != "grid item" ) return;
+        if ( thatItem->whichKindOfItem() != "free item" ) return;
 
-        GridItem* item = dynamic_cast< GridItem* >( thatItem );
+        FreeItem* item = dynamic_cast< FreeItem* >( thatItem );
 
         // fully transparent stuff doesn’t drop any shadow
         if ( transparency >= 100 ) return;
@@ -13,8 +13,8 @@ void ShadowCaster::castShadowImageOnGridItem( Item* thatItem, int x, int y, BITM
 
         BITMAP* rawImage = item->getRawImage() ;
 
-        int width = item->getWidthX() ;
-        int deltaW = 0 ;  // widths of grid item are always equal
+        int width = ( item->getWidthX() > item->getWidthY() ? item->getWidthX() : item->getWidthY() ) ;
+        int deltaW = static_cast< int >( item->getWidthX() ) - static_cast< int >( item->getWidthY() ) ;
 
         int inix = x - item->getOffsetX();                      // initial X
         if ( inix < 0 ) inix = 0;
@@ -24,7 +24,7 @@ void ShadowCaster::castShadowImageOnGridItem( Item* thatItem, int x, int y, BITM
         if ( endx > rawImage->w ) endx = rawImage->w;
         int endy = y - item->getOffsetY() + shadow->h;          // final Y
         if ( endy > rawImage->h ) endy = rawImage->h;
-        int my = rawImage->h - width - item->getHeight() + 1;   // intermediate Y
+        int my = rawImage->h - width - item->getHeight ();      // intermediate Y
         if ( endy < my ) my = endy;
         if ( endy > my + width ) endy = my + width;
 
@@ -43,7 +43,7 @@ void ShadowCaster::castShadowImageOnGridItem( Item* thatItem, int x, int y, BITM
 
         int n2i = inix + item->getOffsetX() - x;
 
-        BITMAP* shadyImage = item->getProcessedImage();         // graphics of shaded item
+        BITMAP* shadyImage = item->getShadedNonmaskedImage();   // graphics of shaded item
 
         if ( ! shadyImage )
         {
@@ -371,5 +371,5 @@ void ShadowCaster::castShadowImageOnGridItem( Item* thatItem, int x, int y, BITM
                 }
         }
 
-        item->setProcessedImage( shadyImage );
+        item->setShadedNonmaskedImage( shadyImage );
 }

with current master with head commit “there’s no need to care for sequental amount of transparency while casting shadows at least” these same nine shadows are gone

casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=144
casting shadow from free item "bars-ns" at x=4 y=127 z=144 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=96 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=48
casting shadow from free item "bars-ns" at x=4 y=127 z=144 on free item "bars-ns" at x=4 y=127 z=0
casting shadow from free item "bars-ns" at x=4 y=127 z=48 on free item "bars-ns" at x=4 y=127 z=0
casting shadow from free item "bars-ns" at x=4 y=127 z=96 on free item "bars-ns" at x=4 y=127 z=0
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=0
casting shadow from free item "bars-ns" at x=4 y=127 z=144 on free item "bars-ns" at x=4 y=127 z=96
casting shadow from free item "extra-life" at x=2 y=125 z=168 on free item "bars-ns" at x=4 y=127 z=96

next thing: there’s regression~ no shadows from free item on other free items

plus these tristate WhichShady & WhichMask ~ are they really needed or just one boolean would be okay?

First variants of “ add class Shady ... ” commit introduced flickering of shadows on floor tile when there’s more than one item to shade the same tile

This update fixes that

--- a/src/ShadowCaster.cpp
+++ b/src/ShadowCaster.cpp
@@ -417,8 +417,6 @@ void ShadowCaster::castShadowOnItem( Item* item, int x, int y, BITMAP* shadow, u
 /* static */
 void ShadowCaster::castShadowOnFloor( FloorTile* tile, int x, int y, BITMAP* shadow, unsigned short shading, unsigned char transparency )
 {
-        if ( ! tile->getWantShadow() ) return;
-
         // fully transparent stuff doesn’t drop any shadow
         if ( transparency >= 100 ) return;

@@ -458,7 +456,11 @@ void ShadowCaster::castShadowOnFloor( FloorTile* tile, int x, int y, BITMAP* sha
                 shadyImage = create_bitmap_ex( colorDepthTile, tileImage->w, tileImage->h );
         }

-        blit( tileImage, shadyImage, 0, 0, 0, 0, tileImage->w, tileImage->h );
+        if ( tile->getWantShadow() )
+        {
+                blit( tileImage, shadyImage, 0, 0, 0, 0, tileImage->w, tileImage->h );
+                tile->setWantShadow( false );
+        }

         char iInc = ( colorDepthTile == 32 ? 4 : 3 );           // increment for iRpx, iGpx and iBpx
         char sInc = ( colorDepthShadow == 32 ? 4 : 3 );         // increment for sPixel
@@ -575,7 +577,6 @@ void ShadowCaster::castShadowOnFloor( FloorTile* tile, int x, int y, BITMAP* sha
         }

         tile->setShadyImage( shadyImage );
-        tile->setWantShadow( false );
 }

 }

I got how to fix “ no shadows on free items ”

the problem is >> 1 of unsigned int when it needs to be signed, as example
( freeItem->getWidthX() - freeItem->getWidthY() + 1 ) >> 1

@@ -404,8 +419,12 @@ void Mediator::castShadowOnFloor( FloorTile* floorTile )
 
                                 ShadowCaster::castShadowOnFloor (
                                         floorTile,
-                                        /* x */ ( ( freeItem->getX() - freeItem->getY() ) << 1 ) + room->getX0() + ( freeItem->getWidthX() + freeItem->getWidthY() ) - ( ( freeItem->getImageOfShadow()->w ) >> 1 ) - 1,
-                                        /* y */ freeItem->getX() + freeItem->getY() + room->getY0() + ( ( freeItem->getWidthX() - freeItem->getWidthY() + 1 ) >> 1 ) - ( ( freeItem->getImageOfShadow()->h ) >> 1 ),
+                                        /* x */ ( ( freeItem->getX() - freeItem->getY() ) << 1 ) + room->getX0()
+                                                        + static_cast< int >( freeItem->getWidthX() + freeItem->getWidthY() )
+                                                        - ( ( freeItem->getImageOfShadow()->w ) >> 1 ) - 1,
+                                        /* y */ freeItem->getX() + freeItem->getY() + room->getY0()
+                                                        + ( ( static_cast< int >( freeItem->getWidthX() ) - static_cast< int >( freeItem->getWidthY() ) + 1 ) >> 1 )
+                                                        - ( ( freeItem->getImageOfShadow()->h ) >> 1 ),
                                         /* shadow */ freeItem->getImageOfShadow(),
                                         /* shadingScale */ room->shadingScale,
                                         /* transparency */ freeItem->getTransparency()
@@ -472,8 +491,12 @@ void Mediator::castShadowOnGridItem( GridItem* gridItem )
 
                                 ShadowCaster::castShadowOnItem (
                                         gridItem,
-                                        /* x */ ( ( freeItem->getX() - freeItem->getY() ) << 1 ) + ( freeItem->getWidthX() + freeItem->getWidthY() ) - ( ( freeItem->getImageOfShadow()->w ) >> 1 ) - 1,
-                                        /* y */ freeItem->getX() + freeItem->getY() + ( ( freeItem->getWidthX() - freeItem->getWidthY() + 1 ) >> 1 ) - ( ( freeItem->getImageOfShadow()->h ) >> 1 ) - gridItem->getZ() - gridItem->getHeight(),
+                                        /* x */ ( ( freeItem->getX() - freeItem->getY() ) << 1 )
+                                                        + static_cast< int >( freeItem->getWidthX() + freeItem->getWidthY() )
+                                                        - ( ( freeItem->getImageOfShadow()->w ) >> 1 ) - 1,
+                                        /* y */ freeItem->getX() + freeItem->getY()
+                                                        + ( ( static_cast< int >( freeItem->getWidthX() ) - static_cast< int >( freeItem->getWidthY() ) + 1 ) >> 1 )
+                                                        - ( ( freeItem->getImageOfShadow()->h ) >> 1 ) - gridItem->getZ() - gridItem->getHeight(),
                                         /* shadow */ freeItem->getImageOfShadow(),
                                         /* shadingScale */ room->shadingScale,
                                         /* transparency */ freeItem->getTransparency()
@@ -551,8 +574,11 @@ void Mediator::castShadowOnFreeItem( FreeItem* freeItem )
 
                                 ShadowCaster::castShadowOnItem (
                                         freeItem,
-                                        /* x */ ( ( shadeItem->getX() - shadeItem->getY() ) << 1 ) + shadeItem->getWidthX() + shadeItem->getWidthY() - ( shadeItem->getImageOfShadow()->w >> 1 ) - 1,
-                                        /* y */ shadeItem->getX() + shadeItem->getY() - freeItem->getZ() - freeItem->getHeight() + ( ( shadeItem->getWidthX() - shadeItem->getWidthY() - shadeItem->getImageOfShadow()->h ) >> 1 ),
+                                        /* x */ ( ( shadeItem->getX() - shadeItem->getY() ) << 1 )
+                                                        + static_cast< int >( shadeItem->getWidthX() + shadeItem->getWidthY() )
+                                                        - ( shadeItem->getImageOfShadow()->w >> 1 ) - 1,
+                                        /* y */ shadeItem->getX() + shadeItem->getY() - freeItem->getZ() - freeItem->getHeight()
+                                                        + ( ( static_cast< int >( shadeItem->getWidthX() ) - static_cast< int >( shadeItem->getWidthY() ) - shadeItem->getImageOfShadow()->h ) >> 1 ),
                                         /* shadow */ shadeItem->getImageOfShadow(),
                                         /* shadingScale */ room->shadingScale,
                                         /* transparency */ freeItem->getTransparency()

plus there’s obviously a mistake

freeItem->getY() > freeItem->getY() - static_cast< int >( item->getWidthY() )
is the same as
0 > 0 - static_cast< int >( item->getWidthY() )
or
static_cast< int >( item->getWidthY() ) > 0
which is always true when width is not zero

it needs to be freeItem->getY() > item->getY() - static_cast< int >( item->getWidthY() )

@@ -326,14 +324,26 @@ void Mediator::shadeFreeItemsBeneathItem( Item* item )
         {
                 FreeItem* freeItem = *f ;

-                if ( freeItem->getUniqueName () != item->getUniqueName () )
+                if ( freeItem != item &&
+                        item->getUniqueName() != freeItem->getUniqueName() + " copy" )
                 {
-                        if ( ( freeItem->getX() + static_cast< int >( freeItem->getWidthX() ) > item->getX() )
-                                && ( freeItem->getX() < item->getX() + static_cast< int >( item->getWidthX() ) )
-                                && ( freeItem->getY() > freeItem->getY() - static_cast< int >( item->getWidthY() ) )
-                                && ( freeItem->getY() - static_cast< int >( freeItem->getWidthY() ) < item->getY() )
+                        int itemX = item->getX();       int itemY = item->getY();
+                        int freeX = freeItem->getX();   int freeY = freeItem->getY();
+                        int freeXend = freeX + static_cast< int >( freeItem->getWidthX() );
+                        int freeYend = freeY - static_cast< int >( freeItem->getWidthY() );
+                        int itemXend = itemX + static_cast< int >( item->getWidthX() );
+                        int itemYend = itemY - static_cast< int >( item->getWidthY() );
+
+                        if ( ( freeXend > itemX ) && ( freeX < itemXend )
+                                && ( freeY > itemYend ) && ( freeYend < itemY )
                                 && ( freeItem->getZ() < item->getZ() ) )
                         {
+                        # if  defined( DEBUG_SHADOWS )  &&  DEBUG_SHADOWS
+                                std::cout << "Mediator::shadeFreeItemsBeneathItem got item \"" << freeItem->getUniqueName ()
+                                          << "\" to shade from \"" << item->getUniqueName () << "\""
+                                          << std::endl ;
+                        #endif
+
                                 freeItem->setWhichShade( WantReshadow );
                         }
                 }

shadows are okay yet