/*
 * Leo Schwab's stars hack, turned into a screen saver module.
 *
 * Copyright 1991, Mike Meyer
 * All Rights Reserved
 *
 * See the file "ShadowMaster:Distribution" for information on distribution.
 *
 * ===build instructions
 * % lc stars ; output= stars.o input= stars.c savermain.h
 * % blink stars.o LIB lib:lcr.lib SC SD ND ; output= stars input=stars.o
 * % copy stars //savers
 * ===endbuild
 */

#include <exec/types.h>
#include <intuition/intuition.h>
#include <graphics/gfx.h>
#include <dos/dos.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/intuition.h>

int rand(void) ;
void srand(int) ;
static void dographics(void) ;

struct IntuitionBase	*IntuitionBase = NULL ;
struct GfxBase		*GfxBase = NULL ;
struct ExecBase		*SysBase = NULL ;
struct DosLibrary	*DOSBase = NULL ;
struct Screen		*screen = NULL ;
struct Window		*window = NULL ;

/* Don't change anything above this point... */

/*
 * This is the initial color table for the blanker screen. The format of a
 * ColorSpec is pen number, R, G, B. Add pens as required by your screen. You
 * should really set all pens, so you avoid color flashes after opening.
 * If you insist on doing it another way, add SA_ScreenBehind to the screen
 * and do a ScreenToFront after setting the colormap, but before you start
 * drawing.
 *
 * Don't forget to set the SA_Depth tag in ScreenTags...
 */
struct ColorSpec colorspec[] = {
	{0, 0, 0, 0},
	{1, 1, 1, 1},
	{2, 2, 2, 2},
	{3, 3, 3, 3},
	{4, 4, 4, 4},
	{5, 5, 5, 5},
	{6, 6, 6, 6},
	{7, 7, 7, 7},
	{8, 8, 8, 8},
	{9, 9, 9, 9},
	{10, 10, 10, 10},
	{11, 11, 11, 11},
	{12, 12, 12, 12},
	{13, 13, 13, 13},
	{14, 14, 14, 14},
	{15, 15, 15, 15},
	{ -1 } } ;

/*
 * You must have a better name to use here, right?
 */
static char *Title = "Stars" ;

/*
 * Screen open data. You'll probably want to change this to set your own
 * depth and mode. I'd recommend leaving the overscan as is, but it's your
 * graphics hack. Oh yes, feel free to give it your own title. 
 */
static struct TagItem	ScreenTags[] = {
	{SA_Depth, 4},
	{SA_Colors, &colorspec},
	{SA_DisplayID, LORES_KEY},
	{SA_Overscan, OSCAN_MAX},
	{SA_Title, &Title},
	{SA_ShowTitle, FALSE},
	{SA_Quiet, TRUE},
	{TAG_END, 0}
	} ;

/*
 * The window is for turning off the sprite, and that's about it. However,
 * if you want clipped rendering (which means part of your graphics aren't
 * going to be seen), you can use it's rastport. Until you're sure that's
 * not going on, you probably want to do that anyway. After you trust your
 * grahics code, render through the screen rastport to get extra speed.
 *
 * WARNING: WA_CustomScreen _MUST_ be the first entry!!!
 */
static struct TagItem WindowTags[] = {
	{WA_CustomScreen, FALSE},
	{WA_Activate, TRUE},
	{WA_SimpleRefresh, TRUE},
	{WA_Borderless, TRUE},
	{TAG_END, 0}
	};

#include "savermain.h"

/*
 * Add whatever graphics you want here. Be sure and do a
 * CheckSignal(SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C at regular intervals, as
 * that's how you're told to unblank. When that evaluates to true, you should
 * free everything you've allocated and return.
 *
 * Note that we seed the rand() number generator in _main, so that it can
 * happen before we drop the task priority. For saver hacks, that random
 * number generator should be good enough. If you need better, change that
 * seeding. Otherwise, you can just use rand() knowing you'll get different
 * sequences each time you get started. If you really don't want this, just
 * delete the stuff in main.
 *
 * This example doesn't _do_ anything, so it uses a Wait instead of checking
 * signals. We want to be a good citizen.
 */
#define NSTARS	128
short x[NSTARS], y[NSTARS], z[NSTARS] ;
short xo[NSTARS], yo[NSTARS] ;

void
mkpoint(short i) {
        x[i] = (rand() >> 8) % 256 - 128;
        y[i] = (rand() >> 8) % 150 - 75;
        z[i] = 255;
	}

#define	magic	256
#define	inc	3
void
dographics(void) {
	long	xs, ys ;
	int	i ;
	struct RastPort *rp = &screen->RastPort ;

        for (i=0; i<NSTARS; i++)
                mkpoint (i);

        for (;;) {
                for (i=0; i<NSTARS; i++) {
                        if ((z[i] -= inc) <= 0)
                                mkpoint (i);
                        xs = x[i] * magic / z[i] + 160;
                        ys = y[i] * magic / z[i] + 100;
                        SetAPen (rp, 0L);
                        WritePixel (rp, (long) xo[i], (long) yo[i]);
                        if (xs < 0 || xs > screen->Width - 1 || ys < 0 || ys > screen->Height - 1)
                                mkpoint (i);
                        else {
                                SetAPen (rp, (long) (256-z[i] >> 4));
                                WritePixel (rp, xs, ys);
                                xo[i] = xs;  yo[i] = ys;
                	        }
	                }
		if (CheckSignal(SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) return ;
		}
	}
