;/*
sc RESOPT DATA=NEAR UCHAR CONSTLIB STREQ NMINC STRMERGE NOSTKCHK NOSTDIO OPTIMIZE OPTSIZE IGNORE=73 Shade.c
slink from LIB:c.o Shade.o to //Clients/Shade LIB LIB:sc.lib LIB:amiga.lib /lib/client.lib SC SD STRIPDEBUG NOICONS
delete Shade.o
quit

 Shade 1.0  (Client for BServer)

 Copyright © 1994-1995 Stefano Reksten of 3AM - The Three Amigos!!!
 All rights reserved.

 This was asked by Massimo Capanni. Why couldn't HE make it? :-)
*/

#include <exec/types.h>
#include <exec/memory.h>
#include <graphics/gfxbase.h>

#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <clib/alib_protos.h>
#include <time.h>

#include "/include/client.h"

char *ver = "$VER: Shade 1.0 "__AMIGADATE__;

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct DisplayIDInformation *dinfo;

UWORD __chip plasma_mask[58] = {
 0x1F, 0xC000,
 0xFF, 0xF800,
 0x1FF, 0xFC00,
 0x7FF, 0xFF00,
 0xFFF, 0xFF80,
 0x1FFF, 0xFFC0,
 0x1FFF, 0xFFC0,
 0x3FFF, 0xFFE0,
 0x7FFF, 0xFFF0,
 0x7FFF, 0xFFF0,
 0x7FFF, 0xFFF0,
 0xFFFF, 0xFFF8,
 0xFFFF, 0xFFF8,
 0xFFFF, 0xFFF8,
 0xFFFF, 0xFFF8,
 0xFFFF, 0xFFF8,
 0xFFFF, 0xFFF8,
 0xFFFF, 0xFFF8,
 0x7FFF, 0xFFF0,
 0x7FFF, 0xFFF0,
 0x7FFF, 0xFFF0,
 0x3FFF, 0xFFE0,
 0x1FFF, 0xFFC0,
 0x1FFF, 0xFFC0,
 0xFFF, 0xFF80,
 0x7FF, 0xFF00,
 0x1FF, 0xFC00,
 0xFF, 0xF800,
 0x1F, 0xC000
 };

UWORD __chip plasmaplanes[8][58];
UWORD __chip carryplanes[8][58];

#define BALLDIM 0x1D

extern ULONG RangeSeed;

struct Screen *scr;
UWORD swidth, sheight;
UBYTE sdepth;
struct BitMap *scrbmap;
struct RastPort rp;
struct BitMap plasmabmap, carrybmap, maskbmap, tempplasmabmap, tempcarrybmap, tempscrbmap;
WORD X, Y, velX, velY;


void Moveplasma( void )
{
UBYTE n;

/* plasma movement... OK this part is a load of crap :-) */

X += velX;
if ( X >= swidth - BALLDIM )
	{
	X = swidth - BALLDIM;
	velX = RangeRand( 6 ) - 8;
	}
if ( X < 0 )
	{
	X = 0;
	velX = RangeRand( 6 ) + 3;
	}

Y += velY;
if ( Y >= sheight - BALLDIM )
	{
	Y = sheight - BALLDIM;
	velY = RangeRand( 6 ) - 8;
	}
if ( Y < 0 )
	{
	Y = 0;
	velY = RangeRand( 6 ) + 3;
	}

/*
	And now... a bit of plasma THEORY... by GUNDAM of 3AM !!! :-)

	How can plasma be generated? Well. Suppose we are working in a 32
	colors screen. We have 6 bitplanes. We order the colors in crescent
	order, so the color number 0 will be the darkest, the color number 31
	will be the brightest. All we have to do is simply this: when we
	draw the ball... we must increase by one the color of the pixels
	"under" the ball. «Yes, we knew it!» Okie-dokie, just wait a bit! :-)

	Consider this: HOW can we increase the colors under the ball? It is
	NOT possible to ReadPixel then increase the color then WritePixel
	again! Let's use the blitter => all we have then is to increase a
	number using the blitter. Consider e.g. we have this pixel color
	under the ball: 00010111. We have to get to the number 00011000. Of
	course the blitter is not an ALU so we just have to simulate it. :-)
	We must increase the pixel IF the corresponding bit in the mask is 1.
	So for the first bit let's use the mask. For the other bits, we will
	have to increase them ONLY if the previous bit generated a carry.
	Let's define the function that generates the SUM: (BNC|NBC), where
	B indicates the source, C the destination, NB and NC their negated
	values. The function that calculates the CARRY is (BC). To prove that
	this will work, let's increase the previous 00010111 number.

	76543210   Bit 0 is (11), because 1 was in the mask. So sum is (10|01)
    CCCCCCCM   that is 0; carry is (11) that is 1. To calculate bits from
	00010111   1 to 7 we will use the carry. Bit 1 is (10|01) = 0, carry (11) 
	SSSSSSSS   is 1. Bit 2 is (10|01) = 0, carry (11) = 1. Bit 3 is (11|00)
	           which is 1, while carry is (10) = 0. From here, having 0 in
	the carry, sums will have the B's bit value and 0 for the carry, as the
	sum will be (1B|0NB) => B and the carry will be (0B) => 0. So we DID
	increase a number using the blitter! Is this magic? No: a man's magic
	is another man's (ME :-) engineering! It took me nearly 5 minutes to
	get to this solution!

	All we have to do now is to put that value back.

	So all we have to do is
	1) a first blit using the screen's bitmap and the plasma mask to a
	   "sum" place using the SUM function.
	2) a second blit using the screen's bitmap and the plasma mask to a
	   "carry" place using the CARRY function.
	3) FOR all the remaining planes DO
	       blit the carry and the sum in the sum using SUM
	       blit the carry and the sum in the carry using CARRY

	Believe me or not... This was HARD to write USING THE OS!!! ;-)
	All those double blits could be avoided BUMPING directly in the hardware!

*/

tempscrbmap.Planes[0] = scrbmap->Planes[0];

tempplasmabmap.Planes[0] = plasmabmap.Planes[0];
BltBitMap( &maskbmap, 0, 0, &tempplasmabmap, 0, 0, BALLDIM, BALLDIM, (ABC|ABNC), 0xFF, NULL ); /* VANILLA */
BltBitMap( &tempscrbmap, X, Y, &tempplasmabmap, 0, 0, BALLDIM, BALLDIM, (ANBC|ABNC), 0xFF, NULL ); /* SUM */

tempcarrybmap.Planes[0] = carrybmap.Planes[1];
BltBitMap( &maskbmap, 0, 0, &tempcarrybmap, 0, 0, BALLDIM, BALLDIM, (ABC|ABNC), 0xFF, NULL ); /* VANILLA */
BltBitMap( &tempscrbmap, X, Y, &tempcarrybmap, 0, 0, BALLDIM, BALLDIM, (ABC), 0xFF, NULL ); /* CARRY */

for ( n = 1; n < sdepth; n++ )
	{
	tempscrbmap.Planes[0] = scrbmap->Planes[n];

	tempplasmabmap.Planes[0] = plasmabmap.Planes[n];
	tempcarrybmap.Planes[0] = carrybmap.Planes[n]; /* just temp */
	BltBitMap( &tempcarrybmap, 0, 0, &tempplasmabmap, 0, 0, BALLDIM, BALLDIM, (ABC|ABNC), 0xFF, NULL ); /* VANILLA */
	BltBitMap( &tempscrbmap, X, Y, &tempplasmabmap, 0, 0, BALLDIM, BALLDIM, (ANBC|ABNC), 0xFF, NULL ); /* SUM */

	if ( n < sdepth - 1 )
		{
		tempcarrybmap.Planes[0] = carrybmap.Planes[n+1];
		tempplasmabmap.Planes[0] = carrybmap.Planes[n]; /* same here */
		BltBitMap( &tempplasmabmap, 0, 0, &tempcarrybmap, 0, 0, BALLDIM, BALLDIM, (ABC|ABNC), 0xFF, NULL ); /* VANILLA */
		BltBitMap( &tempscrbmap, X, Y, &tempcarrybmap, 0, 0, BALLDIM, BALLDIM, (ABC), 0xFF, NULL ); /* CARRY */
		}
	}

/* Unfortunately these are needed to avoid flickering... :-( */
BltBitMap( scrbmap, X, Y, &carrybmap, 0, 0, BALLDIM, BALLDIM, 0xC0, 0xFF, NULL );
BltMaskBitMapRastPort( &plasmabmap, 0, 0, &rp, 0, 0,
		BALLDIM, BALLDIM, (ABC|ABNC|ANBC), (PLANEPTR)plasma_mask );
WaitTOF();
BltBitMap( &carrybmap, 0, 0, scrbmap, X, Y, BALLDIM, BALLDIM, 0xC0, 0xFF, NULL );
}


void Blank( void )
{
struct Rectangle *rect;
UWORD n;
UBYTE brightness;
ULONG displayID;

rect = GETTXTOSCANRECT(dinfo);
swidth = RECTANGLEWIDTH(rect);
sheight = RECTANGLEHEIGHT(rect);
displayID = DISPLAYID( dinfo );
brightness = GETBRIGHTNESS(dinfo);

if ( CheckAA() )
	sdepth = 8;
else
	{
	sdepth = 5;

	if ( displayID & HIRES )
		{
		displayID &= ~HIRES;
		swidth >>= 1;
		}
	if ( displayID & SUPERHIRES )
		{
		displayID &= ~SUPERHIRES;
		swidth >>= 1;
		}
	}

if ( scr = OpenScreenTags( NULL,
	SA_Width, swidth,
	SA_Height, sheight,
	SA_Depth, sdepth,
	SA_Quiet, TRUE,
	SA_DisplayID, displayID,
	TAG_END ) )
	{
	register struct ViewPort *vp = &(scr->ViewPort);

	scrbmap = scr->RastPort.BitMap;
	SpritesOff();

	X = RangeRand( swidth - BALLDIM );
	Y = RangeRand( sheight - BALLDIM );
	velX = RangeRand( 8 ) - 16; if ( !velX ) velX = 1;
	velY = RangeRand( 8 ) - 16; if ( !velY ) velY = 1;

if ( CheckAA() )
	{
	for ( n = 0; n < 64; n++ )
		SetRGB32( vp, n, 0, 0, (n*brightness/100)<<25);
	for ( n = 0; n < 64; n++ )
		SetRGB32( vp, n+64, 0, (n*brightness/100)<<24, (63*brightness/100)<<25 );
	for ( n = 0; n < 64; n++ )
		SetRGB32( vp, n+128, (n*brightness/100)<<23, (63*brightness/100)<<24, ((63-n)*brightness/100)<<25 );
	for ( n = 0; n < 64; n++ )
		SetRGB32( vp, n+192, ((63-n)*brightness/100)<<23, ((63-n)*brightness/100)<<24, 0 );
	}
else
	{
	for ( n = 0; n < 16; n++ )
		SetRGB4( vp, n, 0, 0, n*brightness/100 );
	for ( n = 16; n < 32; n++ )
		SetRGB4( vp, n, 0, (n-15)*brightness/100, 15*brightness/100 );
	}

	InitBitMap( &plasmabmap, sdepth, BALLDIM, BALLDIM );
	InitBitMap( &carrybmap, sdepth, BALLDIM, BALLDIM );
	for ( n = 0; n < sdepth; n++ )
		{
		plasmabmap.Planes[n] = (PLANEPTR)plasmaplanes[n];
		carrybmap.Planes[n] = (PLANEPTR)carryplanes[n];
		}

	InitBitMap( &maskbmap, 1, BALLDIM, BALLDIM );
	maskbmap.Planes[0] = (PLANEPTR)plasma_mask;

	InitBitMap( &tempplasmabmap, 1, BALLDIM, BALLDIM );
	InitBitMap( &tempcarrybmap, 1, BALLDIM, BALLDIM );
	InitBitMap( &tempscrbmap, 1, swidth, sheight );
	/* No need for planes as these will be changed... */

	InitRastPort( &rp );
	rp.BitMap = &carrybmap;

	while( STILL_BLANKING )
		Moveplasma();

	CloseScreen( scr );
	SpritesOn();
	}
else
	SendClientMsg( ACTION_FAILED );
}


void __main( char *line )
{
if ( IntuitionBase = (struct IntuitionBase *)OpenLibrary( "intuition.library", 37L ) )
	{
	if ( GfxBase = (struct GfxBase *)OpenLibrary( "graphics.library", 37L ) )
		{
		if ( dinfo = OpenCommunication() )
			{
			RangeSeed = time( NULL );
			Blank();
			CloseCommunication( dinfo );
			}
		CloseLibrary( (struct Library *)GfxBase );
		}
	CloseLibrary( (struct Library *)IntuitionBase );
	}
}
