drawskel.c 9.86 KB
/********************************************************************************
						   NINTENDO64 Disk Drive IPL4

							  mario drawing module

								February 27, 1997
 ********************************************************************************/

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


#define	ANIM_STAT_INACTIVE	0
#define	ANIM_STAT_TRANS		1
#define	ANIM_STAT_ANGLE		2

static AnimePlay animplay;


//////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//		Animation control.
//
//
//
//
//////////////////////////////////////////////////////////////////////////////////

/********************************************************************************/
/*																				*/
/*	Set skeleton animation.														*/
/*																				*/
/********************************************************************************/
extern int
SetAnimation(CtrlShape *shape, short id, AnimeData *anime, long speed)
{
	AnimeCtrl  *animctrl = &shape->animation;


	if ((animctrl->anime != anime) || (animctrl->code != id)) {
		animctrl->code	= id;
		animctrl->anime = anime;
		animctrl->frame = (anime->start<<16) - speed;
	}
	animctrl->speed = speed;
	return(animctrl->frame >> 16);
}
/********************************************************************************/
/*																				*/
/*	Check skeleton animation frame.												*/
/*																				*/
/********************************************************************************/
static int
CheckAnimeFrame(CtrlShape *shape, int frame)
{
	int		   result;
	AnimeCtrl *animctrl	 = &shape->animation;
	long	   nextframe = animctrl->frame + animctrl->speed;
	long	   testframe = frame << 16;


	result = ((animctrl->frame < testframe) && (testframe <= nextframe));
	return(result);	
}
/********************************************************************************/
/*																				*/
/*	get skeleton animation index.												*/
/*																				*/
/********************************************************************************/
static int
AnimeIndex(int frame, short **table)
{
	int index;

	if ((*table)[0] > frame)  index = (*table)[1] + frame;
						else  index = (*table)[1] + (*table)[0] - 1;
	*table += 2;
	return(index);
}
/********************************************************************************/
/*																				*/
/*	Calculate next animation frame.												*/
/*																				*/
/********************************************************************************/
static long
NextAnimeFrame(AnimeCtrl *animctrl)
{
	SPacked    frame;
	AnimeData *anime = animctrl->anime;


	frame.word = animctrl->frame + animctrl->speed;

	if (frame.half[0] >= anime->nframes) {
		if (anime->attr & HMS_ANIM_ONETIME)  frame.half[0] = anime->nframes - 1;
									   else  frame.half[0] = anime->loop;
	}
	return(frame.word);
}
/********************************************************************************/
/*																				*/
/*	Begin animation.															*/
/*																				*/
/********************************************************************************/
static void
BeginAnimation(AnimeCtrl *animctrl, int animesw)
{
	if (animesw)  animctrl->frame = NextAnimeFrame(animctrl);

	animplay.status = ANIM_STAT_TRANS;
	animplay.frame  = animctrl->frame >> 16;
	animplay.scale  = 1.0f;
	animplay.table  = animctrl->anime->table;
	animplay.param  = animctrl->anime->param;
}


//////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//		Skeleton control.
//
//
//
//
//////////////////////////////////////////////////////////////////////////////////

/********************************************************************************/
/*																				*/
/*	Select head.																*/
/*																				*/
/********************************************************************************/
static void
DoSelectHead(Gfx *gfxlist1, Gfx *gfxlist2, Gfx *gfxlist3, int offset)
{
	static char eyeBlink[7] = { 1,2,1,0,1,2,1 };

	int select = 0;
	int count  = ((frameCounter+offset) >> 1) & 0x1f;

	if (count < 7)  select = eyeBlink[count];

	switch (select) {
		case 0: gSPDisplayList(graphicp++, gfxlist1);	break;
		case 1: gSPDisplayList(graphicp++, gfxlist2);	break;
		case 2: gSPDisplayList(graphicp++, gfxlist3);	break;
	}
}
/********************************************************************************/
/*																				*/
/*	Select head.																*/
/*																				*/
/********************************************************************************/
static void
DoSelectHand(short flags, Gfx *gfxlist1, Gfx *gfxlist2)
{
	if (flags & SHAPE_FLAG_OPENHAND) {
		gSPDisplayList(graphicp++, gfxlist2);
	} else {
		gSPDisplayList(graphicp++, gfxlist1);
	}
}
/********************************************************************************/
/*																				*/
/*	Do Joint.																	*/
/*																				*/
/********************************************************************************/
static void
DoJoint(Gfx *gfxlist, short offsetx, short offsety, short offsetz)
{
	FVector	angle;
	FVector	trans;
	Mtx *	matrix = (Mtx *)AllocDynamic(sizeof(Mtx));


	SetFVector(&angle, 0.0f			 , 0.0f			 ,  0.0f		 ); 
	SetFVector(&trans, (float)offsetx, (float)offsety, (float)offsetz);

	if (animplay.status == ANIM_STAT_TRANS) {
		trans.x += (float)animplay.param[ AnimeIndex(animplay.frame, &animplay.table)] * animplay.scale;
		trans.y += (float)animplay.param[ AnimeIndex(animplay.frame, &animplay.table)] * animplay.scale;
		trans.z += (float)animplay.param[ AnimeIndex(animplay.frame, &animplay.table)] * animplay.scale;
		animplay.status = ANIM_STAT_ANGLE;
	}
	angle.x = AngleToRadian( animplay.param[ AnimeIndex(animplay.frame, &animplay.table)]);
	angle.y = AngleToRadian( animplay.param[ AnimeIndex(animplay.frame, &animplay.table)]);
	angle.z = AngleToRadian( animplay.param[ AnimeIndex(animplay.frame, &animplay.table)]);

	CreateJointMatrix(matrix, &trans, &angle);
	gSPMatrix(graphicp++, K0_TO_PHYS(matrix), G_MTX_MODELVIEW|G_MTX_MUL|G_MTX_PUSH)
	if (gfxlist != NULL)  gSPDisplayList(graphicp++, gfxlist);
}
/********************************************************************************/
/*																				*/
/*	Pop matrix.																	*/
/*																				*/
/********************************************************************************/
static void
PopMatrix(void)
{
	gSPPopMatrix(graphicp++, G_MTX_MODELVIEW);
}
/********************************************************************************/
/*																				*/
/*	Draw skeleton shape.														*/
/*																				*/
/********************************************************************************/
extern void
DrawSkeleton(CtrlShape *shape, Skeleton skeleton, int drawmode)
{
	if (shape->flags & SHAPE_FLAG_ENABLE) {
		FVector	radian;
		FVector scaling;
		FVector position = shape->position;
		Mtx *	modeling = (Mtx *)AllocDynamic(sizeof(Mtx));

		SetFVector(&radian , 0.0f, AngleToRadian(shape->angle), 0.0f);
		SetFVector(&scaling, 1.0f,				 shape->scale , 1.0f);


		position.y += 10.0f;		/* for 3D calculate error correction	*/

		if (drawmode == SHAPE_DRAW_MIRROR) {
			position.y *= -1.0f;
			scaling.y  *= -1.0f;	
			gSPClearGeometryMode(graphicp++, G_CULL_BACK );
			gSPSetGeometryMode  (graphicp++, G_CULL_FRONT);
		}
		CreateModelMatrix(modeling, &position, &radian, &scaling);

		gSPMatrix(graphicp++, K0_TO_PHYS(modeling), G_MTX_MODELVIEW |G_MTX_LOAD|G_MTX_NOPUSH);
		BeginAnimation(&shape->animation, (drawmode == SHAPE_DRAW_NORMAL));
		skeleton(shape->flags);

		if (drawmode == SHAPE_DRAW_MIRROR) {
    		gSPClearGeometryMode(graphicp++, G_CULL_FRONT);
			gSPSetGeometryMode  (graphicp++, G_CULL_BACK );
		}
	}
}


//////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//		Skeleton shape data.
//
//
//
//
//////////////////////////////////////////////////////////////////////////////////

/********************************************************************************/
/*																				*/
/*	Mario skeleton data.														*/
/*																				*/
/********************************************************************************/
extern void
MarioSkeleton(short flags)
{
	DoJoint(NULL, 0, 0, 0);																/* chn14		*/
		DoJoint(RCP_mario_near14, 0, 0, 0);												/* m_waist1_3	*/
			DoJoint(RCP_mario_near_body, 68, 0, 0);										/* m_body1		*/
				DoJoint(NULL, 87, 0, 0);												/* m_head2		*/
					DoSelectHead(RCP_mario_head1, RCP_mario_head2, RCP_mario_head3,  0);
				PopMatrix();
	
				DoJoint(NULL, 67, -10, 79);												/* chn6			*/
					DoJoint(RCP_mario_near2, 0, 0, 0);									/* m_larmA1		*/
						DoJoint(RCP_mario_near1, 65, 0, 0);								/* m_larmB1		*/
							DoJoint(NULL, 60, 0, 0);									/* m_lhand1		*/
								DoSelectHand(flags, RCP_mario_near0, RCP_mario_swim_l);
							PopMatrix();
						PopMatrix();
					PopMatrix();
				PopMatrix();

				DoJoint(NULL, 68, -10, -79);											/* chn10		*/
					DoJoint(RCP_mario_near5, 0, 0, 0);									/* m_rarmA1		*/
						DoJoint(RCP_mario_near4, 65, 0, 0);								/* m_rarmB1		*/
							DoJoint(NULL, 60, 0, 0);									/* m_rhand1		*/
								DoSelectHand(flags, RCP_mario_near3, RCP_mario_swim_r);
							PopMatrix();
						PopMatrix();
					PopMatrix();
				PopMatrix();

			PopMatrix();

			DoJoint(NULL, 13, -8, 42);													/* chn15		*/
				DoJoint(RCP_mario_near11, 0, 0, 0);										/* m_llegA1		*/
					DoJoint(RCP_mario_near10, 89, 0, 0);								/* m_llegB1		*/
						DoJoint(RCP_mario_near9, 67, 0, 0);								/* m_lfoot1		*/
						PopMatrix();
					PopMatrix();
				PopMatrix();
			PopMatrix();

			DoJoint(NULL, 13, -8, -42);													/* chn17		*/
				DoJoint(RCP_mario_near8, 0, 0, 0);										/* m_rlegA1		*/
					DoJoint(RCP_mario_near7, 89, 0, 0);									/* m_rlegB1		*/
						DoJoint(RCP_mario_near6, 67, 0, 0);
						PopMatrix();
					PopMatrix();
				PopMatrix();
			PopMatrix();
		PopMatrix();
	PopMatrix();
}