drawwave.c 8.92 KB
/********************************************************************************
						   NINTENDO64 Disk Drive IPL4

							  wave drawing module

							   November 20, 1996
 ********************************************************************************/

#include <ultra64.h>
#include "ipl4.h"
#include "graphics.h"
#include "static.h"


#define	PLANE_NBLOCKS	2

#define	PLANE_SIDE		(PLANE_NBLOCKS*12)
#define	PLANE_LIMIT		(PLANE_SIDE/2)
#define	PLANE_NEXT		(PLANE_SIDE+1)
#define	PLANE_SCALE		(2896/PLANE_LIMIT)

#define	PNT00	(             0)
#define	PNT01	(             1)
#define	PNT02	(             2)
#define	PNT10	(PLANE_NEXT    )
#define	PNT11	(PLANE_NEXT  +1)
#define	PNT12	(PLANE_NEXT  +2)
#define	PNT20	(PLANE_NEXT*2  )
#define	PNT21	(PLANE_NEXT*2+1)
#define	PNT22	(PLANE_NEXT*2+2)


#define	WAVE_SPEED		80.0f
#define	WAVE_LENGTH		1024.0f

static RGBAColor waveColor;
static float	 waveRadius;
static float	 waveAmplitude[6];

static WaveVertex waveVertex[PLANE_NEXT*PLANE_NEXT];


/********************************************************************************/
/*																				*/
/*	Wave generator																*/
/*																				*/
/********************************************************************************/
static short
SetWaveHeight(int centx, int centz, int posx, int posz)
{
	float height   = 0.0f;
	float distx	   = (float)(posx - centx);
	float distz    = (float)(posz - centz);
	float distance = sqrtf(distx * distx + distz * distz);


	if (waveRadius >= distance-10.f) {
		int	  select = (int)((waveRadius - distance) / WAVE_LENGTH);
		float phase  = (waveRadius - distance) / WAVE_LENGTH;

		height = waveAmplitude[select] * sinf(2.0f * M_PI * phase);
	}
	return((short)height);
}
/********************************************************************************/
/*																				*/
/*	Wave generator																*/
/*																				*/
/********************************************************************************/
static void
MoveWave(void)
{
	waveRadius += WAVE_SPEED;
	if (waveRadius >= WAVE_LENGTH*6.0f) {
		waveRadius		-= WAVE_LENGTH;
		waveAmplitude[0] = waveAmplitude[1];
		waveAmplitude[1] = waveAmplitude[2];
		waveAmplitude[2] = waveAmplitude[3];
		waveAmplitude[3] = waveAmplitude[4];
		waveAmplitude[4] = waveAmplitude[5];
		waveAmplitude[5] = 0.0f;
	}
}
/********************************************************************************/
/*																				*/
/*	Set water verteies.															*/
/*																				*/
/********************************************************************************/
static void
SetPlaneVertex(int posx, int posz)
{
	int		   cnt;
	Vtx		   *vtx  = (Vtx *)AllocDynamic(sizeof(Vtx)*13);
	WaveVertex *wave = &waveVertex[posz*PLANE_NEXT+posx];

	if (posz % 2) {
		gSPVertex(graphicp++, K0_TO_PHYS(vtx), 13, 0);
	} else {
		gSPVertex(graphicp++, K0_TO_PHYS(vtx), 13,13);
	}
	for (cnt = 0; cnt < 13; cnt++) {
		float len = 127.0f / sqrtf(wave->nx*wave->nx + wave->ny*wave->ny + wave->nz*wave->nz);

		vtx->v.ob[0] = wave->px;
		vtx->v.ob[1] = wave->py;
		vtx->v.ob[2] = wave->pz - 1326;
		vtx->v.flag  = 0;
		vtx->v.tc[0] = wave->px;
		vtx->v.tc[1] = wave->pz;
		vtx->v.cn[0] = (char)(wave->nx * len);
		vtx->v.cn[1] = (char)(wave->ny * len);
		vtx->v.cn[2] = (char)(wave->nz * len);
		vtx->v.cn[3] = 255;

		vtx  += 1;
		wave += 1;
		posx += 1;
	}
}
/********************************************************************************/
/*																				*/
/*	Set triangle																*/
/*																				*/
/********************************************************************************/
static void
SetTriangle(WaveVertex *pos1, WaveVertex *pos2, WaveVertex *pos3)
{
	register float x = (float)((pos2->py-pos1->py)*(pos3->pz-pos2->pz) - (pos3->py-pos2->py)*(pos2->pz-pos1->pz));
	register float y = (float)((pos2->pz-pos1->pz)*(pos3->px-pos2->px) - (pos3->pz-pos2->pz)*(pos2->px-pos1->px));
	register float z = (float)((pos2->px-pos1->px)*(pos3->py-pos2->py) - (pos3->px-pos2->px)*(pos2->py-pos1->py));
	register float r = 1.0f / sqrtf(x*x + y*y + z*z);

	x *= r;
	y *= r;
	z *= r;

	pos1->nx += x;	pos1->ny += y;	pos1->nz += z;
	pos2->nx += x;	pos2->ny += y;	pos2->nz += z;
	pos3->nx += x;	pos3->ny += y;	pos3->nz += z;
}
/********************************************************************************/
/*																				*/
/*	Set normal vector															*/
/*																				*/
/********************************************************************************/
static void
SetNormalVector(void)
{
	int	posx, posz;

	for (posz = 0; posz <= PLANE_NEXT*(PLANE_SIDE-2); posz += PLANE_NEXT*2) {
		for (posx = 0; posx <= (PLANE_SIDE-2); posx += 2) {
			int top = posx + posz;

			SetTriangle(&waveVertex[top+PNT10], &waveVertex[top+PNT01], &waveVertex[top+PNT00]);
			SetTriangle(&waveVertex[top+PNT10], &waveVertex[top+PNT11], &waveVertex[top+PNT01]);
			SetTriangle(&waveVertex[top+PNT01], &waveVertex[top+PNT11], &waveVertex[top+PNT12]);
			SetTriangle(&waveVertex[top+PNT01], &waveVertex[top+PNT12], &waveVertex[top+PNT02]);

			SetTriangle(&waveVertex[top+PNT10], &waveVertex[top+PNT20], &waveVertex[top+PNT21]);
			SetTriangle(&waveVertex[top+PNT10], &waveVertex[top+PNT21], &waveVertex[top+PNT11]);
			SetTriangle(&waveVertex[top+PNT21], &waveVertex[top+PNT12], &waveVertex[top+PNT11]);
			SetTriangle(&waveVertex[top+PNT21], &waveVertex[top+PNT22], &waveVertex[top+PNT12]);
		}
	}
}
/********************************************************************************/
/*																				*/
/*	Create waving water															*/
/*																				*/
/********************************************************************************/
static void
CreateWavingField(int centx, int centz, int scale)
{
	int		   posx, posz;
	WaveVertex *vertex = waveVertex;

	for (posz = -PLANE_LIMIT*scale; posz <= PLANE_LIMIT*scale; posz += scale) {
		for (posx = -PLANE_LIMIT*scale; posx <= PLANE_LIMIT*scale; posx += scale) {
			vertex->px = posx;
			vertex->py = SetWaveHeight(centx, centz, posx, posz);
			vertex->pz = posz;
			vertex->ct = 0;
			vertex->nx = 0.0f;
			vertex->ny = 0.0f;
			vertex->nz = 0.0f;
			vertex	  += 1;
		}
	}
}
/********************************************************************************/
/*																				*/
/*	Waving water main.															*/
/*																				*/
/********************************************************************************/
extern void
ControlAlpha(void)
{
	if (waveAmplitude[3] == 0.0f) {
		if (waveColor.a > 200)  waveColor.a -= 1;
		if (waveColor.r < 255)  waveColor.r += 1;
		if (waveColor.g < 255)  waveColor.g += 1;
		if (waveColor.b < 255)  waveColor.b += 1;
	}
	gDPSetEnvColor(graphicp++, waveColor.r, waveColor.g, waveColor.b, waveColor.a);
	gDPSetRenderMode(graphicp++, G_RM_FOG_SHADE_A, G_RM_AA_ZB_XLU_SURF2);
}
/********************************************************************************/
/*																				*/
/*	Setup display list.															*/
/*																				*/
/********************************************************************************/
static void
SetDisplayList(void)
{
	int slit, posx, posz;


	gDPPipeSync(graphicp++);
	gDPSetCycleType(graphicp++, G_CYC_2CYCLE);

	gDPSetCombineMode(graphicp++, G_CC_ENVSHADE, G_CC_PASS2);
	ControlAlpha();

//	gSPFogPosition	  (graphicp++, 996, 1000);
	gSPFogPosition	  (graphicp++, 940, 1000);
	gSPSetGeometryMode(graphicp++, G_FOG);
	gDPSetFogColor	  (graphicp++, 232,232,232,255);

	gSPMatrix(graphicp++, K0_TO_PHYS(&IdentMatrix), G_MTX_MODELVIEW |G_MTX_LOAD|G_MTX_NOPUSH);

	for (posx = 0; posx < PLANE_SIDE; posx += 12) {
		SetPlaneVertex(posx, 0);

		for (posz = 1; posz <= PLANE_SIDE; posz++) {
			SetPlaneVertex(posx, posz);
			if (posz % 2) {
				gSPDisplayList(graphicp++, Gfx_WavePlaneB);
			} else {
				gSPDisplayList(graphicp++, Gfx_WavePlaneA);
			}
		}
	}
	MoveWave();
	gDPPipeSync(graphicp++);
	gSPClearGeometryMode(graphicp++, G_FOG);
	gDPSetCycleType(graphicp++, G_CYC_1CYCLE);
}
/********************************************************************************/
/*																				*/
/*	Waving water main.															*/
/*																				*/
/********************************************************************************/
extern void
DisplayWater(void)
{
	if (waveAmplitude[0] != 0.0f) {
		CreateWavingField(0, 1326, PLANE_SCALE);
		SetNormalVector();
		SetDisplayList();
	} else {
		gDPPipeSync	  (graphicp++);
		gDPSetEnvColor(graphicp++, waveColor.r, waveColor.g, waveColor.b, waveColor.a);
		gSPDisplayList(graphicp++, Gfx_FlatPlane);
	}
}
/********************************************************************************/
/*																				*/
/*	Initialize wave parameters.													*/
/*																				*/
/********************************************************************************/
extern void
InitializeWater(void)
{
	waveColor.r = 160;
	waveColor.g = 160;
	waveColor.b = 255;
	waveColor.a = 255;

	waveRadius  =  0.0f;

	waveAmplitude[0] = 80.0f;
	waveAmplitude[1] = 60.0f;
	waveAmplitude[2] = 40.0f;
	waveAmplitude[3] = 00.0f;
	waveAmplitude[4] = 00.0f;
	waveAmplitude[5] = 00.0f;
}