mirror of
https://github.com/OpenDriver2/REDRIVER2.git
synced 2024-11-22 10:22:48 +01:00
2019 lines
39 KiB
C
2019 lines
39 KiB
C
#include "driver2.h"
|
|
#include "motion_c.h"
|
|
#include "pedest.h"
|
|
#include "system.h"
|
|
#include "mission.h"
|
|
#include "texture.h"
|
|
#include "camera.h"
|
|
#include "shadow.h"
|
|
#include "debris.h"
|
|
#include "draw.h"
|
|
#include "dr2roads.h"
|
|
#include "sky.h"
|
|
#include "players.h"
|
|
#include "main.h"
|
|
|
|
#include "cars.h"
|
|
#include "convert.h"
|
|
|
|
#ifdef USE_PGXP
|
|
#include <math.h>
|
|
#endif
|
|
|
|
enum LIMBS
|
|
{
|
|
ROOT = 0,
|
|
LOWERBACK = 1,
|
|
JOINT_1 = 2,
|
|
NECK = 3,
|
|
HEAD = 4,
|
|
LSHOULDER = 5,
|
|
LELBOW = 6,
|
|
LHAND = 7,
|
|
LFINGERS = 8,
|
|
RSHOULDER = 9,
|
|
RELBOW = 10,
|
|
RHAND = 11,
|
|
RFINGERS = 12,
|
|
HIPS = 13,
|
|
LHIP = 14,
|
|
LKNEE = 15,
|
|
LFOOT = 16,
|
|
LTOE = 17,
|
|
RHIP = 18,
|
|
RKNEE = 19,
|
|
RFOOT = 20,
|
|
RTOE = 21,
|
|
JOINT = 22,
|
|
};
|
|
|
|
enum TEXTURE_PALS
|
|
{
|
|
NO_PAL = 0,
|
|
JEANS_PAL = 1,
|
|
ARM_PAL = 2,
|
|
CHEST_PAL = 3,
|
|
};
|
|
|
|
struct BONE
|
|
{
|
|
LIMBS id;
|
|
BONE* pParent;
|
|
char numChildren;
|
|
BONE(*pChildren[3]);
|
|
SVECTOR_NOPAD* pvOrigPos;
|
|
SVECTOR* pvRotation;
|
|
VECTOR vOffset;
|
|
VECTOR vCurrPos;
|
|
MODEL** pModel;
|
|
};
|
|
|
|
struct PED_DATA
|
|
{
|
|
char cWidth;
|
|
u_char cAdj;
|
|
TEXTURE_DETAILS* ptd;
|
|
TEXTURE_PALS texPal;
|
|
};
|
|
|
|
#define NUM_BONES 23
|
|
|
|
LIMBS lRoutes[5][8] = {
|
|
{
|
|
ROOT, LOWERBACK,
|
|
HIPS, LHIP,
|
|
LKNEE, LFOOT,
|
|
LTOE, ROOT
|
|
},
|
|
{
|
|
HIPS, RHIP,
|
|
RKNEE, RFOOT,
|
|
RTOE, ROOT,
|
|
ROOT, ROOT
|
|
},
|
|
{
|
|
LOWERBACK, JOINT_1,
|
|
LSHOULDER, LELBOW,
|
|
LHAND, LFINGERS,
|
|
ROOT, ROOT
|
|
},
|
|
{
|
|
JOINT_1, RSHOULDER,
|
|
RELBOW, RHAND,
|
|
RFINGERS, ROOT,
|
|
ROOT, ROOT
|
|
},
|
|
{
|
|
JOINT_1, NECK,
|
|
HEAD, ROOT,
|
|
ROOT, ROOT,
|
|
ROOT, ROOT
|
|
},
|
|
};
|
|
|
|
PED_DATA MainPed[NUM_BONES] =
|
|
{
|
|
{ 0, 68u, &chest1_texture, CHEST_PAL },
|
|
{ 1, 68u, &chest1_texture, CHEST_PAL },
|
|
{ 17, 36u, &chest1_texture, CHEST_PAL },
|
|
{ 6, 68u, &forearm1_texture, ARM_PAL },
|
|
{ 8, 22u, &head1_texture, NO_PAL },
|
|
{ 6, 68u, &arm1_texture, CHEST_PAL },
|
|
{ 8, 36u, &arm1_texture, CHEST_PAL },
|
|
{ 7, 68u, &forearm1_texture, ARM_PAL },
|
|
{ 3, 244u, &forearm1_texture, ARM_PAL },
|
|
{ 6, 68u, &arm1_texture, CHEST_PAL },
|
|
{ 8, 36u, &arm1_texture, CHEST_PAL },
|
|
{ 7, 68u, &forearm1_texture, ARM_PAL },
|
|
{ 3, 244u, &forearm1_texture, ARM_PAL },
|
|
{ 1, 68u, &jeans_texture, NO_PAL },
|
|
{ 6, 68u, &jeans_texture, NO_PAL },
|
|
{ 13, 100u, &jeans_texture, JEANS_PAL },
|
|
{ 11, 244u, &jeans_texture, JEANS_PAL },
|
|
{ 6, 63u, &chest1_texture, JEANS_PAL },
|
|
{ 6, 68u, &arm1_texture, NO_PAL },
|
|
{ 13, 100u, &jeans_texture, JEANS_PAL },
|
|
{ 11, 244u, &jeans_texture, JEANS_PAL },
|
|
{ 6, 63u, &chest1_texture, JEANS_PAL },
|
|
{ 2, 68u, &jeans_texture, JEANS_PAL }
|
|
};
|
|
|
|
|
|
// FIXME: could be incorrect
|
|
BONE Skel[NUM_BONES] =
|
|
{
|
|
{
|
|
ROOT,
|
|
NULL,
|
|
2,
|
|
{ &Skel[LOWERBACK], &Skel[HIPS], NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
NULL
|
|
},
|
|
{
|
|
LOWERBACK,
|
|
&Skel[ROOT],
|
|
3,
|
|
{ &Skel[JOINT_1], &Skel[LHIP], &Skel[RHIP] },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
NULL
|
|
},
|
|
{
|
|
JOINT_1,
|
|
&Skel[LOWERBACK],
|
|
3,
|
|
{ &Skel[NECK], &Skel[LSHOULDER], &Skel[RSHOULDER] },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
&pmTannerModels[0]
|
|
},
|
|
{
|
|
NECK,
|
|
&Skel[JOINT_1],
|
|
1,
|
|
{ &Skel[HEAD], NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
&pmTannerModels[14]
|
|
},
|
|
{
|
|
HEAD,
|
|
&Skel[NECK],
|
|
0,
|
|
{ NULL, NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
&pmTannerModels[1]
|
|
},
|
|
{
|
|
LSHOULDER,
|
|
&Skel[JOINT_1],
|
|
1,
|
|
{ &Skel[LELBOW], NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
NULL
|
|
},
|
|
{
|
|
LELBOW,
|
|
&Skel[LSHOULDER],
|
|
1,
|
|
{ &Skel[LHAND], NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
&pmTannerModels[8]
|
|
},
|
|
{
|
|
LHAND,
|
|
&Skel[LELBOW],
|
|
1,
|
|
{ &Skel[LFINGERS], NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
&pmTannerModels[9]
|
|
},
|
|
{
|
|
LFINGERS,
|
|
&Skel[LHAND],
|
|
0,
|
|
{ NULL, NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
&pmTannerModels[10]
|
|
},
|
|
{
|
|
RSHOULDER,
|
|
&Skel[JOINT_1],
|
|
1,
|
|
{ &Skel[RELBOW], NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
NULL
|
|
},
|
|
{
|
|
RELBOW,
|
|
&Skel[RSHOULDER],
|
|
1,
|
|
{ &Skel[RHAND], NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
&pmTannerModels[2]
|
|
},
|
|
{
|
|
RHAND,
|
|
&Skel[RELBOW],
|
|
1,
|
|
{ &Skel[RFINGERS], NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
&pmTannerModels[3]
|
|
},
|
|
{
|
|
RFINGERS,
|
|
&Skel[RHAND],
|
|
0,
|
|
{ NULL, NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
&pmTannerModels[4]
|
|
},
|
|
{
|
|
HIPS,
|
|
&Skel[ROOT],
|
|
2,
|
|
{ &Skel[RHIP], &Skel[LHIP], NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
NULL
|
|
},
|
|
{
|
|
LHIP,
|
|
&Skel[HIPS],
|
|
1,
|
|
{ &Skel[LKNEE], NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
&pmTannerModels[15]
|
|
},
|
|
{
|
|
LKNEE,
|
|
&Skel[LHIP],
|
|
1,
|
|
{ &Skel[LFOOT], NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
&pmTannerModels[11]
|
|
},
|
|
{
|
|
LFOOT,
|
|
&Skel[LKNEE],
|
|
1,
|
|
{ &Skel[LTOE], NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
&pmTannerModels[12]
|
|
},
|
|
{
|
|
LTOE,
|
|
&Skel[LFOOT],
|
|
0,
|
|
{ NULL, NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
&pmTannerModels[13]
|
|
},
|
|
{
|
|
RHIP,
|
|
&Skel[HIPS],
|
|
1,
|
|
{ &Skel[RKNEE], NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
NULL
|
|
},
|
|
{
|
|
RKNEE,
|
|
&Skel[RHIP],
|
|
1,
|
|
{ &Skel[RFOOT], NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
&pmTannerModels[5]
|
|
},
|
|
{
|
|
RFOOT,
|
|
&Skel[RKNEE],
|
|
1,
|
|
{ &Skel[RTOE], NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
&pmTannerModels[6]
|
|
},
|
|
{
|
|
RTOE,
|
|
&Skel[RFOOT],
|
|
0,
|
|
{ NULL, NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
&pmTannerModels[7]
|
|
},
|
|
{
|
|
JOINT,
|
|
&Skel[LOWERBACK],
|
|
0,
|
|
{ NULL, NULL, NULL },
|
|
NULL,
|
|
NULL,
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
NULL
|
|
}
|
|
};
|
|
|
|
int boneIdvals[] = {
|
|
// 1
|
|
JOINT_1,
|
|
NECK,
|
|
HEAD,
|
|
|
|
// 2
|
|
LELBOW,
|
|
LHAND,
|
|
LFINGERS,
|
|
|
|
// 3
|
|
RELBOW,
|
|
RHAND,
|
|
RFINGERS,
|
|
|
|
// 4
|
|
LKNEE,
|
|
LFOOT,
|
|
LTOE,
|
|
|
|
// 5
|
|
RKNEE,
|
|
RFOOT,
|
|
RTOE
|
|
};
|
|
|
|
TEXTURE_DETAILS jeans_texture;
|
|
TEXTURE_DETAILS arm1_texture;
|
|
TEXTURE_DETAILS forearm1_texture;
|
|
TEXTURE_DETAILS chest1_texture;
|
|
TEXTURE_DETAILS head1_texture;
|
|
|
|
MODEL* gPed1HeadModelPtr;
|
|
MODEL* gPed2HeadModelPtr;
|
|
MODEL* gPed3HeadModelPtr;
|
|
MODEL* gPed4HeadModelPtr;
|
|
|
|
char* MotionCaptureData[MAX_MOTION_CAPTURE]; // [A] actually, pointers
|
|
int ThisMotion;
|
|
|
|
short cTannerVNumbers[24];
|
|
SVECTOR vTannerList[210];
|
|
|
|
short cJerichoVNumbers[7];
|
|
SVECTOR vJerichoList[102];
|
|
|
|
int vStored = 0;
|
|
|
|
// [D] [T]
|
|
void ProcessMotionLump(char* lump_ptr, int lump_size)
|
|
{
|
|
if (ThisMotion < MAX_MOTION_CAPTURE)
|
|
{
|
|
int size = (lump_size + 3) & ~3;
|
|
|
|
D_MALLOC_BEGIN();
|
|
MotionCaptureData[ThisMotion] = D_MALLOC(size);
|
|
D_MALLOC_END();
|
|
|
|
memcpy((u_char*)MotionCaptureData[ThisMotion], (u_char*)lump_ptr, size);
|
|
|
|
ThisMotion++;
|
|
}
|
|
}
|
|
|
|
// [D] [T]
|
|
void SetupPedMotionData(LPPEDESTRIAN pPed)
|
|
{
|
|
pPed->motion = MotionCaptureData[pPed->type];
|
|
}
|
|
|
|
|
|
// [D] [T]
|
|
void SetupPedestrian(LPPEDESTRIAN pedptr)
|
|
{
|
|
pedptr->velocity.vy = 10;
|
|
pedptr->speed = 10;
|
|
|
|
pedptr->dir.vx = 0;
|
|
pedptr->dir.vz = 0;
|
|
|
|
pedptr->frame1 = 0;
|
|
pedptr->motion = MotionCaptureData[pedptr->type];
|
|
}
|
|
|
|
int bDoingShadow = 0;
|
|
int gCurrentZ;
|
|
|
|
// [D] [T] [A]
|
|
void DrawBodySprite(LPPEDESTRIAN pDrawingPed, int boneId, VERTTYPE v1[2], VERTTYPE v2[2], int sz, int sy)
|
|
{
|
|
#if 0
|
|
// debug code
|
|
{
|
|
LINE_F2* line = (LINE_F2*)current->primptr;
|
|
setLineF2(line);
|
|
setSemiTrans(line, 1);
|
|
|
|
line->x0 = v1[0];
|
|
line->y0 = v1[1];
|
|
line->x1 = v2[0];
|
|
line->y1 = v2[1];
|
|
|
|
line->r0 = 255;
|
|
line->g0 = 0;
|
|
line->b0 = 0;
|
|
|
|
addPrim(current->ot + 2, line);
|
|
current->primptr += sizeof(LINE_F2);
|
|
}
|
|
#endif
|
|
|
|
int clut;
|
|
int angle;
|
|
char tmp;
|
|
int tmp2;
|
|
int dx1, dy1,dx2,dy2;
|
|
int width;
|
|
POLY_FT4* prims;
|
|
LIMBS bone;
|
|
TEXTURE_DETAILS* body_texture;
|
|
int x, y, z, z2;
|
|
int tpage;
|
|
int pal;
|
|
int cs, sn;
|
|
|
|
bone = (LIMBS)(boneId & 0x7f);
|
|
body_texture = MainPed[bone].ptd;
|
|
|
|
if (bDoingShadow)
|
|
z = sz + (scr_z / 2);
|
|
else
|
|
z = gCurrentZ + (scr_z / 2);
|
|
|
|
z2 = ((scr_z * 4096) / z) * 25 >> 5;
|
|
|
|
if (bone == JOINT_1)
|
|
{
|
|
// make ped thinner from side view
|
|
u_int ang;
|
|
ang = RCOS((pDrawingPed->dir.vy + camera_angle.vy) * 2) >> 6;
|
|
|
|
z2 += ang;
|
|
}
|
|
|
|
if (pDrawingPed->type == PED_ACTION_JUMP)
|
|
{
|
|
width = MainPed[bone].cWidth + 4;
|
|
}
|
|
else
|
|
{
|
|
if (pDrawingPed->flags & 0x8000)
|
|
width = MainPed[bone].cWidth - 3;
|
|
else if (pDrawingPed->flags & 0x4000)
|
|
width = MainPed[bone].cWidth + 8;
|
|
else
|
|
width = MainPed[bone].cWidth + 3;
|
|
}
|
|
|
|
if (bDoingShadow &&
|
|
(bone == RKNEE || bone == LKNEE ||
|
|
bone == LFOOT || bone == RFOOT))
|
|
{
|
|
width -= 5;
|
|
}
|
|
|
|
x = v1[0] - v2[0];
|
|
y = v1[1] - v2[1];
|
|
|
|
angle = -ratan2(y, x);
|
|
|
|
cs = FIXEDH(z2 * RSIN(angle) * (width & 0x3f) * 2);
|
|
sn = FIXEDH(z2 * RCOS(angle) * (width & 0x3f) * 2);
|
|
|
|
tmp = MainPed[bone].cAdj & 0xf;
|
|
|
|
dx2 = x >> tmp;
|
|
dy2 = y >> tmp;
|
|
|
|
if ((bone == RKNEE || bone == LKNEE) && pDrawingPed->type != PED_ACTION_JUMP && bDoingShadow == 0)
|
|
{
|
|
dx1 = -x >> 3;
|
|
dy1 = -y >> 3;
|
|
}
|
|
else
|
|
{
|
|
tmp2 = MainPed[bone].cAdj >> 4;
|
|
|
|
dx1 = x >>tmp2;
|
|
dy1 = y >> tmp2;
|
|
}
|
|
|
|
prims = (POLY_FT4*)current->primptr;
|
|
setPolyFT4(prims);
|
|
|
|
current->primptr += sizeof(POLY_FT4);
|
|
|
|
prims->x0 = v1[0] + FIXEDH(cs) + dx2;
|
|
prims->y0 = v1[1] + FIXEDH(sn) + dy2;
|
|
|
|
prims->x1 = v1[0] - FIXEDH(cs) + dx2;
|
|
prims->y1 = v1[1] - FIXEDH(sn) + dy2;
|
|
|
|
prims->x2 = v2[0] + FIXEDH(cs) - dx1;
|
|
prims->y2 = v2[1] + FIXEDH(sn) - dy1;
|
|
|
|
prims->x3 = v2[0] - FIXEDH(cs) - dx1;
|
|
prims->y3 = v2[1] - FIXEDH(sn) - dy1;
|
|
|
|
#ifdef USE_PGXP
|
|
if (!bDoingShadow) // [A] Psy-X is currently incorrectly offsets the offscreen PGXP geometry. We don't need it anyway.
|
|
{
|
|
PGXPVData vdata1, vdata2;
|
|
PGXP_GetCacheData(&vdata1, PGXP_LOOKUP_VALUE(v1[0], v1[1]), 0);
|
|
PGXP_GetCacheData(&vdata2, PGXP_LOOKUP_VALUE(v2[0], v2[1]), 0);
|
|
|
|
{
|
|
float len;
|
|
|
|
x = (v1[0] - v2[0]) * 4.0f;
|
|
y = (v1[1] - v2[1]) * 4.0f;
|
|
|
|
// compute normalization lengths
|
|
len = 1.0 / sqrtf(float(x*x) + float(y*y) + 1.0);
|
|
|
|
angle = -ratan2(y, x);
|
|
|
|
sn = RSIN(angle) * width;
|
|
cs = RCOS(angle) * width;
|
|
|
|
tmp = MainPed[bone].cAdj & 0xf;
|
|
|
|
dx2 = sn >> tmp;
|
|
dy2 = cs >> tmp;
|
|
|
|
if ((bone == RKNEE || bone == LKNEE) && pDrawingPed->type != PED_ACTION_JUMP && bDoingShadow == 0)
|
|
{
|
|
dx1 = -sn >> 3;
|
|
dy1 = -cs >> 3;
|
|
}
|
|
else
|
|
{
|
|
tmp2 = MainPed[bone].cAdj >> 4;
|
|
|
|
dx1 = sn >> tmp2;
|
|
dy1 = cs >> tmp2;
|
|
}
|
|
|
|
dx1 = FIXED(dx1);
|
|
dx2 = FIXED(dx2);
|
|
dy1 = FIXED(dy1) + 2;
|
|
dy2 = FIXED(dy2) - 2;
|
|
|
|
if (bone == HEAD)
|
|
{
|
|
dx1 >>= 1;
|
|
dx2 >>= 1;
|
|
}
|
|
|
|
if (bone == JOINT_1)
|
|
{
|
|
dx1 -= 5;
|
|
dy2 -= 10;
|
|
}
|
|
}
|
|
|
|
PGXPVData v0data = { PGXP_LOOKUP_VALUE(prims->x0, prims->y0),
|
|
vdata1.px + (FIXEDH(sn) - dx1) * 0.01f,
|
|
vdata1.py + (FIXEDH(cs) + dy1) * 0.01f,
|
|
vdata1.pz, vdata1.scr_h, vdata1.ofx, vdata1.ofy };
|
|
|
|
|
|
PGXPVData v1data = { PGXP_LOOKUP_VALUE(prims->x1, prims->y1),
|
|
vdata1.px - (FIXEDH(sn) - dx1) * 0.01f,
|
|
vdata1.py - (FIXEDH(cs) - dy1) * 0.01f,
|
|
vdata1.pz, vdata1.scr_h, vdata1.ofx, vdata1.ofy };
|
|
|
|
|
|
PGXPVData v2data = { PGXP_LOOKUP_VALUE(prims->x2, prims->y2),
|
|
vdata2.px + (FIXEDH(sn) + dx2) * 0.01f,
|
|
vdata2.py + (FIXEDH(cs) - dy2) * 0.01f,
|
|
vdata2.pz, vdata2.scr_h, vdata2.ofx, vdata2.ofy };
|
|
|
|
|
|
PGXPVData v3data = { PGXP_LOOKUP_VALUE(prims->x3, prims->y3),
|
|
vdata2.px - (FIXEDH(sn) + dx2) * 0.01f,
|
|
vdata2.py - (FIXEDH(cs) + dy2) * 0.01f,
|
|
vdata2.pz, vdata2.scr_h, vdata2.ofx, vdata2.ofy };
|
|
|
|
PGXP_EmitCacheData(&v0data);
|
|
PGXP_EmitCacheData(&v1data);
|
|
PGXP_EmitCacheData(&v2data);
|
|
PGXP_EmitCacheData(&v3data);
|
|
}
|
|
#endif
|
|
|
|
if (bDoingShadow)
|
|
{
|
|
tpage = texture_pages[gShadowTexturePage];
|
|
clut = texture_cluts[gShadowTexturePage][gShadowTextureNum];
|
|
}
|
|
else
|
|
{
|
|
tpage = body_texture->tpageid;
|
|
clut = body_texture->clutid;
|
|
|
|
if (MainPed[bone].texPal != NO_PAL)
|
|
{
|
|
pal = MainPed[bone].texPal == JEANS_PAL ? (pDrawingPed->pallet >> 4) : (pDrawingPed->pallet & 0xf);
|
|
|
|
if (pal != 0)
|
|
clut = civ_clut[0][body_texture->texture_number][pal];
|
|
}
|
|
else if(bone == HEAD)
|
|
{
|
|
pal = (pDrawingPed->pallet & 0xf);
|
|
|
|
if (pal != 0)
|
|
clut = civ_clut[0][body_texture->texture_number][pal];
|
|
}
|
|
}
|
|
|
|
prims->tpage = tpage;
|
|
prims->clut = clut;
|
|
|
|
if (bDoingShadow)
|
|
{
|
|
setSemiTrans(prims, 1);
|
|
prims->tpage |= 0x20;
|
|
|
|
*(ushort*)&prims->u0 = *(ushort*)&shadowuv.u0;
|
|
*(ushort*)&prims->u1 = *(ushort*)&shadowuv.u1;
|
|
*(ushort*)&prims->u2 = *(ushort*)&shadowuv.u2;
|
|
*(ushort*)&prims->u3 = *(ushort*)&shadowuv.u3;
|
|
}
|
|
else
|
|
{
|
|
if (bone == HEAD)
|
|
{
|
|
x = (-camera_angle.vy - pDrawingPed->dir.vy & 0xfffU) >> 7;
|
|
|
|
prims->u0 = body_texture->coords.u0 + x;
|
|
prims->v0 = body_texture->coords.v0;
|
|
|
|
prims->u1 = body_texture->coords.u1 + x;
|
|
prims->v1 = body_texture->coords.v1;
|
|
|
|
prims->u2 = body_texture->coords.u2 + x;
|
|
prims->v2 = body_texture->coords.v2;
|
|
|
|
prims->u3 = body_texture->coords.u3 + x;
|
|
prims->v3 = body_texture->coords.v3;
|
|
}
|
|
else if (bone == 2)
|
|
{
|
|
*(ushort*)&prims->u0 = *(ushort*)&body_texture->coords.u0;
|
|
*(ushort*)&prims->u1 = *(ushort*)&body_texture->coords.u1;
|
|
*(ushort*)&prims->u2 = *(ushort*)&body_texture->coords.u2;
|
|
*(ushort*)&prims->u3 = *(ushort*)&body_texture->coords.u3;
|
|
}
|
|
else
|
|
{
|
|
*(ushort*)&prims->u0 = *(ushort*)&body_texture->coords.u2;
|
|
*(ushort*)&prims->u1 = *(ushort*)&body_texture->coords.u3;
|
|
*(ushort*)&prims->u2 = *(ushort*)&body_texture->coords.u0;
|
|
*(ushort*)&prims->u3 = *(ushort*)&body_texture->coords.u1;
|
|
}
|
|
}
|
|
|
|
if (bDoingShadow)
|
|
{
|
|
prims->r0 = 254;
|
|
prims->g0 = 254;
|
|
prims->b0 = 254;
|
|
}
|
|
else if (gNight)
|
|
{
|
|
prims->r0 = 64;
|
|
prims->g0 = 64;
|
|
prims->b0 = 64;
|
|
}
|
|
else
|
|
{
|
|
prims->r0 = (combointensity >> 0x10) & 0xFF;
|
|
prims->g0 = (combointensity >> 8) & 0xFF;
|
|
prims->b0 = combointensity & 0xFF;
|
|
}
|
|
|
|
if (bDoingShadow != 0)
|
|
{
|
|
addPrim(current->ot + OTSIZE - 1, prims);
|
|
}
|
|
else
|
|
{
|
|
x = sz + sy >> 4;
|
|
addPrim(current->ot + x + (width >> 6), prims);
|
|
}
|
|
}
|
|
|
|
// [D] [T]
|
|
void StoreVertexLists(void)
|
|
{
|
|
BONE* pBone;
|
|
SVECTOR* destVerts;
|
|
SVECTOR* srcVerts;
|
|
MODEL* pModel;
|
|
int i,j,counter;
|
|
|
|
// store Tanner vertices
|
|
counter = 0;
|
|
for (i = 0; i < 23; i++)
|
|
{
|
|
pBone = &Skel[i];
|
|
|
|
if (pBone->pModel == NULL)
|
|
{
|
|
cTannerVNumbers[i] = -1;
|
|
continue;
|
|
}
|
|
|
|
pModel = *pBone->pModel;
|
|
|
|
if (pModel == NULL)
|
|
{
|
|
cTannerVNumbers[i] = -1;
|
|
continue;
|
|
}
|
|
|
|
// store start index
|
|
cTannerVNumbers[i] = counter;
|
|
|
|
destVerts = &vTannerList[counter];
|
|
srcVerts = (SVECTOR*)pModel->vertices;
|
|
|
|
for (j = 0; j < pModel->num_vertices; j++)
|
|
{
|
|
destVerts->vx = srcVerts->vx;
|
|
destVerts->vy = srcVerts->vy;
|
|
destVerts->vz = srcVerts->vz;
|
|
|
|
srcVerts++;
|
|
destVerts++;
|
|
counter++;
|
|
}
|
|
}
|
|
|
|
// Store Jericho vertices
|
|
counter = 0;
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
pModel = pmJerichoModels[i];
|
|
|
|
if (pModel == NULL)
|
|
{
|
|
cJerichoVNumbers[i] = -1;
|
|
continue;
|
|
}
|
|
|
|
srcVerts = (SVECTOR*)pModel->vertices;
|
|
|
|
// store start index
|
|
cJerichoVNumbers[i] = counter;
|
|
|
|
destVerts = &vJerichoList[counter];
|
|
|
|
for (j = 0; j < pModel->num_vertices; j++)
|
|
{
|
|
destVerts->vx = srcVerts->vx;
|
|
destVerts->vy = srcVerts->vy;
|
|
destVerts->vz = srcVerts->vz;
|
|
|
|
srcVerts++;
|
|
destVerts++;
|
|
counter++;
|
|
}
|
|
}
|
|
|
|
vStored = 1;
|
|
}
|
|
|
|
#define BODY_OFFSET 8
|
|
#define TORSO_OFFSET -2
|
|
|
|
#define JERICHO_BODY_OFFSET 6
|
|
#define JERICHO_TORSO_OFFSET -5
|
|
|
|
int bodyShiftEnabled = 1;
|
|
|
|
int bodyShiftValue = BODY_OFFSET;
|
|
int torsoShiftValue = TORSO_OFFSET;
|
|
|
|
// [D] [T]
|
|
void SetupTannerSkeleton(LPPEDESTRIAN pDrawingPed)
|
|
{
|
|
int i;
|
|
BONE* pBone;
|
|
char* pC;
|
|
SVECTOR* store;
|
|
SVECTOR_NOPAD* pSVNP;
|
|
|
|
Skel[ROOT].pvOrigPos = (SVECTOR_NOPAD*)(pDrawingPed->motion + pDrawingPed->frame1 * 144 + 146);
|
|
Skel[ROOT].pvRotation = (SVECTOR*)(pDrawingPed->motion + pDrawingPed->frame1 * 144 + 152);
|
|
|
|
Skel[ROOT].vCurrPos.vx = Skel[ROOT].pvOrigPos->vx;
|
|
Skel[ROOT].vCurrPos.vy = -Skel[ROOT].pvOrigPos->vy;
|
|
Skel[ROOT].vCurrPos.vz = -Skel[ROOT].pvOrigPos->vz;
|
|
|
|
Skel[ROOT].vOffset.vx = 0;
|
|
Skel[ROOT].vOffset.vy = 0;
|
|
Skel[ROOT].vOffset.vz = 0;
|
|
|
|
pC = (pDrawingPed->motion + pDrawingPed->frame1 * 144 + 158);
|
|
pSVNP = (SVECTOR_NOPAD*)(pDrawingPed->motion + 14);
|
|
|
|
for (i = 1; i < NUM_BONES; i++)
|
|
{
|
|
pBone = &Skel[i];
|
|
|
|
pBone->pvRotation = (SVECTOR*)pC;
|
|
pBone->pvOrigPos = &pSVNP[i - 1];
|
|
|
|
pC += sizeof(SVECTOR_NOPAD);
|
|
}
|
|
|
|
#ifdef PSX
|
|
store = (SVECTOR*)((u_char*)getScratchAddr(0) + 0x200);
|
|
#else
|
|
SVECTOR scratchVectors[64];
|
|
store = scratchVectors;
|
|
#endif
|
|
|
|
store[LOWERBACK].vx = Skel[LOWERBACK].pvOrigPos->vx;
|
|
store[LOWERBACK].vy = -Skel[LOWERBACK].pvOrigPos->vy;
|
|
store[LOWERBACK].vz = -Skel[LOWERBACK].pvOrigPos->vz;
|
|
|
|
// start at the torso and traverse down
|
|
for (i = 2; i < NUM_BONES; i++)
|
|
{
|
|
pBone = &Skel[i];
|
|
|
|
store[i].vx = pBone->pvOrigPos->vx - pBone->pParent->pvOrigPos->vx;
|
|
store[i].vy = pBone->pParent->pvOrigPos->vy - pBone->pvOrigPos->vy;
|
|
store[i].vz = pBone->pParent->pvOrigPos->vz - pBone->pvOrigPos->vz;
|
|
|
|
if (pBone->id == JOINT_1 && bodyShiftEnabled)
|
|
{
|
|
store[i].vy -= bodyShiftValue;
|
|
store[i].vz -= torsoShiftValue;
|
|
}
|
|
}
|
|
|
|
// start at the lower back and traverse down
|
|
for (i = 1; i < NUM_BONES; i++)
|
|
{
|
|
pBone = &Skel[i];
|
|
|
|
pBone->vCurrPos.vx = store[i].vx;
|
|
pBone->vOffset.vx = store[i].vx;
|
|
|
|
pBone->vCurrPos.vy = store[i].vy;
|
|
pBone->vOffset.vy = store[i].vy;
|
|
|
|
pBone->vCurrPos.vz = store[i].vz;
|
|
pBone->vOffset.vz = store[i].vz;
|
|
}
|
|
|
|
#if 0
|
|
// Draw T POSE
|
|
{
|
|
extern void Debug_AddLine(VECTOR & pointA, VECTOR & pointB, CVECTOR & color);
|
|
extern void Debug_AddLineOfs(VECTOR & pointA, VECTOR & pointB, VECTOR & ofs, CVECTOR & color);
|
|
|
|
CVECTOR bbcv = { 0, 0, 250 };
|
|
CVECTOR rrcv = { 250, 0, 0 };
|
|
CVECTOR yycv = { 250, 250, 0 };
|
|
|
|
for (int i = 0; i < NUM_BONES; i++)
|
|
{
|
|
pBone = &Skel[i];
|
|
|
|
for (int j = 0; j < pBone->numChildren; j++)
|
|
{
|
|
VECTOR v0 = {
|
|
pBone->pvOrigPos->vx,
|
|
pBone->pvOrigPos->vy,
|
|
pBone->pvOrigPos->vz };
|
|
|
|
VECTOR v1 = {
|
|
pBone->pChildren[j]->pvOrigPos->vx,
|
|
pBone->pChildren[j]->pvOrigPos->vy,
|
|
pBone->pChildren[j]->pvOrigPos->vz };
|
|
|
|
VECTOR ofs = *(VECTOR*)&pDrawingPed->position;
|
|
ofs.vy = -ofs.vy;
|
|
//ofs.vy += 270;
|
|
|
|
Debug_AddLineOfs(v0, v1, ofs, bbcv);
|
|
}
|
|
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// [A] - was inlined in newShowTanner
|
|
void DrawSprite(LPPEDESTRIAN pDrawingPed, BONE* pBone, VECTOR* vJPos)
|
|
{
|
|
VERTTYPE t0[2], t1[2]; // [A] was two longs
|
|
int z, z1, z2;
|
|
|
|
#ifdef PSX
|
|
SVECTOR* data = (SVECTOR*)((u_char*)getScratchAddr(0) + 0x200);
|
|
#else
|
|
SVECTOR scratchVectors[64];
|
|
SVECTOR* data = scratchVectors;
|
|
#endif
|
|
|
|
data[0].vx = vJPos[pBone->id & 0x7f].vx + pDrawingPed->position.vx - camera_position.vx;
|
|
data[0].vy = vJPos[pBone->id & 0x7f].vy + pDrawingPed->position.vy - camera_position.vy;
|
|
data[0].vz = vJPos[pBone->id & 0x7f].vz + pDrawingPed->position.vz - camera_position.vz;
|
|
|
|
data[1].vx = vJPos[pBone->pParent->id & 0x7f].vx + pDrawingPed->position.vx - camera_position.vx;
|
|
data[1].vy = vJPos[pBone->pParent->id & 0x7f].vy + pDrawingPed->position.vy - camera_position.vy;
|
|
data[1].vz = vJPos[pBone->pParent->id & 0x7f].vz + pDrawingPed->position.vz - camera_position.vz;
|
|
|
|
gte_ldv0(&data[0]);
|
|
gte_ldv1(&data[1]);
|
|
|
|
gte_rtpt();
|
|
gte_stsxy0(t0);
|
|
gte_stsxy1(t1);
|
|
|
|
gte_stsz3(&z, &z1, &z2);
|
|
|
|
gCurrentZ = z;
|
|
|
|
DrawBodySprite(pDrawingPed, pBone->id, t0, t1, z, z1);
|
|
}
|
|
|
|
int bAllreadyRotated = 0;
|
|
|
|
// [D] [T]
|
|
void newShowTanner(LPPEDESTRIAN pDrawingPed)
|
|
{
|
|
int i, j;
|
|
int draw;
|
|
|
|
#ifdef PSX
|
|
VECTOR* spad = (VECTOR*)((u_char*)getScratchAddr(0) + 0x100);
|
|
#else
|
|
VECTOR spad[64];
|
|
#endif
|
|
|
|
VECTOR* playerPos = &spad[0];
|
|
VECTOR* cameraPos = &spad[1];
|
|
VECTOR* vJPos = &spad[2];
|
|
|
|
playerPos->vx = pDrawingPed->position.vx;
|
|
playerPos->vy = pDrawingPed->position.vy - 15; // [A] elevate Tanner model a little bit so his legs are not in the ground (when Z-buffer enabled)
|
|
playerPos->vz = pDrawingPed->position.vz;
|
|
|
|
cameraPos->vx = camera_position.vx;
|
|
cameraPos->vy = camera_position.vy;
|
|
cameraPos->vz = camera_position.vz;
|
|
|
|
vJPos[ROOT].vx = Skel[ROOT].pvOrigPos->vx;
|
|
vJPos[ROOT].vy = -Skel[ROOT].pvOrigPos->vy;
|
|
vJPos[ROOT].vz = Skel[ROOT].pvOrigPos->vz;
|
|
|
|
VECTOR v = { 0, 0, 0 };
|
|
|
|
gte_SetTransVector(&v);
|
|
|
|
// do not draw the root
|
|
Skel[ROOT].id = (LIMBS)(Skel[ROOT].id | 0x80);
|
|
|
|
draw = (pDrawingPed->padId > -1 && pDrawingPed->padId == CurrentPlayerView)
|
|
? player[pDrawingPed->padId].cameraView != 2
|
|
: 1;
|
|
|
|
for (i = 0; i < 5; i++)
|
|
{
|
|
for (j = 1; j < 8; j++)
|
|
{
|
|
int id;
|
|
|
|
id = lRoutes[i][j];
|
|
|
|
if (id == ROOT)
|
|
break;
|
|
|
|
BONE* pBone = &Skel[id];
|
|
|
|
if (pBone->id < 0x7f)
|
|
{
|
|
int lval;
|
|
|
|
lval = lRoutes[i][j - 1];
|
|
|
|
vJPos[pBone->id].vx = vJPos[lval].vx + pBone->vCurrPos.vx;
|
|
vJPos[pBone->id].vy = vJPos[lval].vy + pBone->vCurrPos.vy;
|
|
vJPos[pBone->id].vz = vJPos[lval].vz + pBone->vCurrPos.vz;
|
|
|
|
if (pDrawingPed->pedType == TANNER_MODEL && pBone->id == HEAD)
|
|
pDrawingPed->head_pos = vJPos[lval].vy;
|
|
|
|
if (pBone->pModel != NULL
|
|
&& !bDoingShadow
|
|
&& pDrawingPed->pedType < OTHER_SPRITE
|
|
&& draw)
|
|
{
|
|
MODEL* model = *pBone->pModel;
|
|
|
|
for (int c = 0; c < model->num_vertices; c++)
|
|
{
|
|
SVECTOR* mVerts = (SVECTOR*)model->vertices + c;
|
|
|
|
mVerts->vx += (vJPos[lval].vx + playerPos->vx - cameraPos->vx);
|
|
mVerts->vy += (vJPos[lval].vy + playerPos->vy - cameraPos->vy);
|
|
mVerts->vz += (vJPos[lval].vz + playerPos->vz - cameraPos->vz);
|
|
}
|
|
}
|
|
|
|
pBone->id = (LIMBS)(pBone->id | 0x80);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(bDoingShadow || draw)
|
|
{
|
|
if (pDrawingPed->pedType < OTHER_SPRITE)
|
|
{
|
|
// draw LOWERBACK - RTOE
|
|
for (i = 1; i < NUM_BONES - 1; i++)
|
|
{
|
|
int id;
|
|
BONE* pBone;
|
|
|
|
pBone = &Skel[i];
|
|
id = pBone->id & 0x7f;
|
|
|
|
if (bDoingShadow)
|
|
{
|
|
if (id != LSHOULDER
|
|
&& id != RSHOULDER
|
|
&& id != HIPS
|
|
&& id != LOWERBACK
|
|
&& id != ROOT
|
|
&& id != JOINT
|
|
&& id != LHIP
|
|
&& id != RHIP)
|
|
{
|
|
DrawSprite(pDrawingPed, pBone, vJPos);
|
|
}
|
|
}
|
|
else if (pBone->pModel != NULL)
|
|
{
|
|
MODEL* model = *pBone->pModel;
|
|
|
|
int bias = 2;
|
|
|
|
if (id == JOINT_1)
|
|
bias = 1;
|
|
else if (id == HEAD)
|
|
bias = 0;
|
|
|
|
RenderModel(model, NULL, &v, bias, PLOT_NO_SHADE, 0, 0);
|
|
}
|
|
|
|
#if 0
|
|
// DEBUG DRAW SKELETON
|
|
{
|
|
extern void Debug_AddLine(VECTOR & pointA, VECTOR & pointB, CVECTOR & color);
|
|
extern void Debug_AddLineOfs(VECTOR & pointA, VECTOR & pointB, VECTOR & ofs, CVECTOR & color);
|
|
|
|
CVECTOR bbcv = { 0, 0, 250 };
|
|
CVECTOR rrcv = { 250, 0, 0 };
|
|
CVECTOR yycv = { 250, 250, 0 };
|
|
|
|
VECTOR v0 = {
|
|
vJPos[pBone->id & 0x7f].vx,
|
|
-vJPos[pBone->id & 0x7f].vy,
|
|
vJPos[pBone->id & 0x7f].vz
|
|
};
|
|
|
|
VECTOR v1 = {
|
|
vJPos[pBone->pParent->id & 0x7f].vx,
|
|
-vJPos[pBone->pParent->id & 0x7f].vy,
|
|
vJPos[pBone->pParent->id & 0x7f].vz
|
|
};
|
|
|
|
VECTOR ofs = *(VECTOR*)&pDrawingPed->position;
|
|
ofs.vy = -ofs.vy;
|
|
//ofs.vy += 270;
|
|
|
|
Debug_AddLineOfs(v0, v1, ofs, bbcv);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// draw LOWERBACK - RTOE
|
|
for (i = 1; i < NUM_BONES - 1; i++)
|
|
{
|
|
BONE* pBone = &Skel[i];
|
|
|
|
int id = pBone->id & 0x7f;
|
|
|
|
if (id != LSHOULDER
|
|
&& id != RSHOULDER
|
|
&& id != HEAD
|
|
&& id != HIPS
|
|
&& id != LOWERBACK
|
|
&& id != ROOT
|
|
&& id != JOINT
|
|
&& id != LHIP
|
|
&& id != RHIP)
|
|
{
|
|
DrawSprite(pDrawingPed, pBone, vJPos);
|
|
}
|
|
}
|
|
|
|
// draw HEAD
|
|
BONE* pBone = &Skel[HEAD];
|
|
|
|
if (switch_detail_distance >> 2 < gCurrentZ)
|
|
{
|
|
DrawSprite(pDrawingPed, pBone, vJPos);
|
|
}
|
|
else
|
|
{
|
|
SVECTOR v1, v2;
|
|
|
|
v1.vx = vJPos[pBone->id & 0x7f].vx;
|
|
v1.vy = vJPos[pBone->id & 0x7f].vy;
|
|
v1.vz = vJPos[pBone->id & 0x7f].vz;
|
|
|
|
v2.vx = vJPos[pBone->pParent->id & 0x7f].vx;
|
|
v2.vy = vJPos[pBone->pParent->id & 0x7f].vy;
|
|
v2.vz = vJPos[pBone->pParent->id & 0x7f].vz;
|
|
|
|
bAllreadyRotated = 1;
|
|
DoCivHead(pDrawingPed, &v2, &v1);
|
|
bAllreadyRotated = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// clear all id flags
|
|
for (i = 0; i < NUM_BONES; i++)
|
|
Skel[i].id = (LIMBS)(Skel[i].id & 0x7f);
|
|
}
|
|
|
|
// [D] [T]
|
|
SVECTOR* GetModelVertPtr(LPPEDESTRIAN pDrawingPed, int boneId, int modelType)
|
|
{
|
|
int startVertex;
|
|
|
|
if (pDrawingPed->pedType != OTHER_MODEL)
|
|
{
|
|
if (cTannerVNumbers[boneId & 0x7f] != -1)
|
|
return vTannerList + cTannerVNumbers[boneId & 0x7f];
|
|
|
|
return NULL;
|
|
}
|
|
|
|
switch (boneId)
|
|
{
|
|
case JOINT_1:
|
|
startVertex = cJerichoVNumbers[0];
|
|
break;
|
|
case HEAD:
|
|
startVertex = cJerichoVNumbers[1];
|
|
break;
|
|
case LELBOW:
|
|
startVertex = cJerichoVNumbers[2];
|
|
break;
|
|
case LHAND:
|
|
startVertex = cJerichoVNumbers[3];
|
|
break;
|
|
case RELBOW:
|
|
startVertex = cJerichoVNumbers[4];
|
|
break;
|
|
case RHAND:
|
|
startVertex = cJerichoVNumbers[5];
|
|
break;
|
|
default:
|
|
return vTannerList + cTannerVNumbers[boneId & 0x7f];
|
|
}
|
|
|
|
return vJerichoList + startVertex;
|
|
}
|
|
|
|
// [D] [T]
|
|
void newRotateBones(LPPEDESTRIAN pDrawingPed, BONE* poBone)
|
|
{
|
|
SVECTOR* pVerts;
|
|
MODEL* pModel;
|
|
MATRIX mStore[32];
|
|
int i, j;
|
|
|
|
MATRIX _sMatrix;
|
|
MATRIX _pMatrix;
|
|
MATRIX _oMatrix;
|
|
|
|
SVECTOR _svBone[2];
|
|
SVECTOR _pD[80];
|
|
VECTOR _vBoneRotated;
|
|
|
|
_pMatrix.t[0] = Skel[0].pvOrigPos->vx;
|
|
_pMatrix.t[1] = Skel[0].pvOrigPos->vy;
|
|
_pMatrix.t[2] = Skel[0].pvOrigPos->vz;
|
|
|
|
// [A] it just happened to be bugged and weird implementation of YXZ rotation
|
|
// replaced with regular RotMatrixYXZ
|
|
SVECTOR r;
|
|
r.vx = pDrawingPed->dir.vx & 0xfff;
|
|
r.vy = pDrawingPed->dir.vy & 0xfff;
|
|
r.vz = pDrawingPed->dir.vz & 0xfff;
|
|
|
|
RotMatrixYXZ(&r, &_pMatrix);
|
|
|
|
_svBone[0].vx = Skel[0].vOffset.vx;
|
|
_svBone[0].vy = Skel[0].vOffset.vy;
|
|
_svBone[0].vz = Skel[0].vOffset.vz;
|
|
|
|
mStore[0] = _pMatrix;
|
|
|
|
for (i = 0; i < 5; i++)
|
|
{
|
|
for (j = 1; j < 8; j++)
|
|
{
|
|
int id = lRoutes[i][j];
|
|
|
|
if (id == ROOT)
|
|
break;
|
|
|
|
BONE* pBone = &Skel[id];
|
|
|
|
_svBone[0].vx = pBone->vOffset.vx;
|
|
_svBone[0].vy = pBone->vOffset.vy;
|
|
_svBone[0].vz = pBone->vOffset.vz;
|
|
|
|
if (bReverseYRotation == 0 || pBone->pParent->id != ROOT)
|
|
{
|
|
_svBone[1].vx = -pBone->pParent->pvRotation->vx;
|
|
_svBone[1].vy = pBone->pParent->pvRotation->vy;
|
|
_svBone[1].vz = pBone->pParent->pvRotation->vz;
|
|
}
|
|
else
|
|
{
|
|
_svBone[1].vx = pBone->pParent->pvRotation->vx;
|
|
_svBone[1].vy = -pBone->pParent->pvRotation->vy;
|
|
_svBone[1].vz = pBone->pParent->pvRotation->vz;
|
|
}
|
|
|
|
if (id == HEAD)
|
|
_svBone[1].vy -= pDrawingPed->head_rot;
|
|
|
|
RotMatrixZYX_gte(&_svBone[1], &_sMatrix);
|
|
|
|
_sMatrix.t[0] = _svBone[0].vx;
|
|
_sMatrix.t[1] = _svBone[0].vy;
|
|
_sMatrix.t[2] = _svBone[0].vz;
|
|
|
|
_pMatrix = mStore[pBone->pParent->id & 0x7f];
|
|
|
|
gte_MulMatrix0(&_pMatrix, &_sMatrix, &_oMatrix);
|
|
gte_SetRotMatrix(&_oMatrix);
|
|
|
|
gte_ldv0(&_svBone[0]);
|
|
gte_rtv0();
|
|
|
|
gte_stlvnl(&_vBoneRotated);
|
|
|
|
pBone->vCurrPos.vx = _vBoneRotated.vx;
|
|
pBone->vCurrPos.vy = _vBoneRotated.vy;
|
|
pBone->vCurrPos.vz = _vBoneRotated.vz;
|
|
|
|
if (pBone->id < 0x7f)
|
|
{
|
|
pVerts = GetModelVertPtr(pDrawingPed, pBone->id, 0);
|
|
|
|
if ((pDrawingPed->pedType < OTHER_SPRITE || pBone->id == HEAD)
|
|
&& pBone->pModel != NULL
|
|
&& pVerts != NULL)
|
|
{
|
|
pModel = *pBone->pModel;
|
|
|
|
SVECTOR* pmVerts = (SVECTOR*)pModel->vertices;
|
|
int numVerts = pModel->num_vertices;
|
|
|
|
for (int c = 0; c < numVerts; c++)
|
|
{
|
|
_pD[c].vx = pVerts[c].vx + _svBone[0].vx;
|
|
_pD[c].vy = pVerts[c].vy + _svBone[0].vy;
|
|
_pD[c].vz = pVerts[c].vz + _svBone[0].vz;
|
|
}
|
|
|
|
for (int c = 0; c < numVerts; c++)
|
|
{
|
|
gte_ldv0(&_pD[c]);
|
|
|
|
gte_rtv0();
|
|
|
|
gte_stlvnl(&_vBoneRotated);
|
|
|
|
pmVerts[c].vx = _vBoneRotated.vx;
|
|
pmVerts[c].vy = _vBoneRotated.vy;
|
|
pmVerts[c].vz = _vBoneRotated.vz;
|
|
}
|
|
}
|
|
}
|
|
|
|
mStore[id] = _oMatrix;
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
// [D] [T]
|
|
void DrawCiv(LPPEDESTRIAN pPed)
|
|
{
|
|
SVECTOR* vert2;
|
|
SVECTOR* vert1;
|
|
short size;
|
|
int shift;
|
|
int boneId;
|
|
int frame;
|
|
int i, j;
|
|
int phase;
|
|
SVECTOR pos;
|
|
VECTOR pos1;
|
|
SVECTOR rot;
|
|
MATRIX workmatrix;
|
|
CVECTOR cv;
|
|
VECTOR ppos;
|
|
int bHeadModel;
|
|
|
|
DVECTOR sxyList[40];
|
|
int szList[40];
|
|
SVECTOR srLerpData[40];
|
|
|
|
bHeadModel = 0;
|
|
|
|
frame = pPed->frame1 / 2;
|
|
|
|
vert1 = (SVECTOR*)pPed->motion;
|
|
|
|
// [A] alpha 1.6 bug fix
|
|
if (!vert1)
|
|
return;
|
|
|
|
vert2 = vert1 + frame * 30;
|
|
|
|
shift = (pPed->flags >> 15) & 0xFF; // HMMM?
|
|
|
|
if (pPed->frame1 & 1)
|
|
{
|
|
if (pPed->frame1 < 30)
|
|
vert1 += (frame + 1) * 30;
|
|
|
|
// interpolate between frames
|
|
for (i = 0; i < 31; i++)
|
|
{
|
|
srLerpData[i].vx = vert1->vx + vert2->vx >> 1;
|
|
srLerpData[i].vy = vert1->vy + vert2->vy >> shift + 1;
|
|
srLerpData[i].vz = vert1->vz + vert2->vz >> 1;
|
|
|
|
vert1++;
|
|
vert2++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < 31; i++)
|
|
{
|
|
srLerpData[i].vx = vert2->vx;
|
|
srLerpData[i].vy = vert2->vy >> shift;
|
|
srLerpData[i].vz = vert2->vz;
|
|
|
|
vert2++;
|
|
}
|
|
}
|
|
|
|
pos.vx = pPed->position.vx - camera_position.vx;
|
|
pos.vy = pPed->position.vy - camera_position.vy;
|
|
pos.vz = pPed->position.vz - camera_position.vz;
|
|
|
|
gte_SetRotMatrix(&inv_camera_matrix);
|
|
gte_ldv0(&pos);
|
|
gte_rtv0();
|
|
|
|
gte_stlvnl(&pos1);
|
|
gte_SetTransVector(&pos1);
|
|
|
|
// [A] it just happened to be bugged and weird implementation of YXZ rotation
|
|
// replaced with regular RotMatrixYXZ
|
|
rot.vx = pPed->dir.vx & 0xfff;
|
|
rot.vy = pPed->dir.vy & 0xfff;
|
|
rot.vz = pPed->dir.vz & 0xfff;
|
|
|
|
RotMatrixYXZ(&rot, &workmatrix);
|
|
|
|
gte_MulMatrix0(&inv_camera_matrix, &workmatrix, &workmatrix);
|
|
gte_SetRotMatrix(&workmatrix);
|
|
|
|
gte_ldv3(&srLerpData[0], &srLerpData[1], &srLerpData[2]);
|
|
gte_rtpt();
|
|
gte_stsz(&gCurrentZ);
|
|
|
|
szList[0] = gCurrentZ;
|
|
|
|
if (gCurrentZ > switch_detail_distance)
|
|
return;
|
|
|
|
// translate bones to screen and draw sprites
|
|
j = 0;
|
|
for (i = 0; i < 15; i++)
|
|
{
|
|
if (j < 30)
|
|
{
|
|
gte_stsxy3(&sxyList[j], &sxyList[j+1], &sxyList[j+2]);
|
|
gte_stsz3(&szList[j], &szList[j+1], &szList[j+2]);
|
|
}
|
|
|
|
if (j < 27)
|
|
{
|
|
j += 3;
|
|
|
|
gte_ldv3(&srLerpData[j], &srLerpData[j+1], &srLerpData[j+2]);
|
|
gte_rtpt();
|
|
}
|
|
|
|
boneId = boneIdvals[i];
|
|
|
|
if (boneId == HEAD && szList[0] <= switch_detail_distance / 2)
|
|
bHeadModel = 1;
|
|
else
|
|
DrawBodySprite(pPed, boneId, (VERTTYPE*)&sxyList[i*2], (VERTTYPE*)&sxyList[i*2 + 1], szList[i*2], szList[i*2+1]);
|
|
}
|
|
|
|
// show head
|
|
if (bHeadModel)
|
|
{
|
|
bAllreadyRotated = 0;
|
|
DoCivHead(pPed, &srLerpData[5], &srLerpData[4]);
|
|
|
|
ppos.vx = 0;
|
|
ppos.vy = 0;
|
|
ppos.vz = 0;
|
|
|
|
gte_SetTransVector(&ppos);
|
|
}
|
|
|
|
// make shadow
|
|
ppos.vx = pPed->position.vx;
|
|
ppos.vy = pPed->position.vy;
|
|
ppos.vz = pPed->position.vz;
|
|
|
|
phase = (pPed->frame1 & 15) * 2;
|
|
|
|
cv.b = 40;
|
|
cv.g = 40;
|
|
cv.r = 40;
|
|
|
|
ppos.vy = (10 - MapHeight(&ppos)) - camera_position.vy;
|
|
ppos.vx = ppos.vx - camera_position.vx;
|
|
ppos.vz = ppos.vz - camera_position.vz;
|
|
|
|
if (phase < 8)
|
|
size = phase + 80;
|
|
else
|
|
size = -phase + 112;
|
|
|
|
RoundShadow(&ppos, &cv, size);
|
|
}
|
|
|
|
// [D] [T]
|
|
void SetSkelModelPointers(int type)
|
|
{
|
|
if (type == OTHER_MODEL)
|
|
{
|
|
Skel[JOINT_1].pModel = &pmJerichoModels[0];
|
|
Skel[HEAD].pModel = &pmJerichoModels[1];
|
|
Skel[LELBOW].pModel = &pmJerichoModels[2];
|
|
Skel[LHAND].pModel = &pmJerichoModels[3];
|
|
Skel[RELBOW].pModel = &pmJerichoModels[4];
|
|
Skel[RHAND].pModel = &pmJerichoModels[5];
|
|
Skel[LHIP].pModel = NULL;
|
|
|
|
bodyShiftValue = BODY_OFFSET + JERICHO_BODY_OFFSET;
|
|
torsoShiftValue = TORSO_OFFSET + JERICHO_TORSO_OFFSET;
|
|
}
|
|
else
|
|
{
|
|
Skel[JOINT_1].pModel = &pmTannerModels[0];
|
|
Skel[HEAD].pModel = &pmTannerModels[1];
|
|
Skel[LELBOW].pModel = &pmTannerModels[8];
|
|
Skel[LHAND].pModel = &pmTannerModels[9];
|
|
Skel[RELBOW].pModel = &pmTannerModels[2];
|
|
Skel[RHAND].pModel = &pmTannerModels[3];
|
|
Skel[LHIP].pModel = &pmTannerModels[15]; // [A] Tanner looks better with no model here but let's keep it
|
|
|
|
bodyShiftValue = BODY_OFFSET;
|
|
torsoShiftValue = TORSO_OFFSET;
|
|
}
|
|
}
|
|
|
|
|
|
int iCurrBone = 0;
|
|
|
|
// [D] [T]
|
|
void DrawTanner(LPPEDESTRIAN pPed)
|
|
{
|
|
int iVar1;
|
|
VECTOR v;
|
|
CVECTOR cV;
|
|
|
|
bDoingShadow = 0;
|
|
|
|
SetSkelModelPointers(pPed->pedType);
|
|
SetupTannerSkeleton(pPed);
|
|
|
|
newRotateBones(pPed, &Skel[LOWERBACK]);
|
|
|
|
// [A] I don't know but it works
|
|
gte_SetRotMatrix(&inv_camera_matrix);
|
|
|
|
iCurrBone = 0;
|
|
newShowTanner(pPed);
|
|
|
|
v.vx = pPed->position.vx;
|
|
v.vy = -pPed->position.vy;
|
|
v.vz = pPed->position.vz;
|
|
|
|
v.vy = -camera_position.vy - MapHeight(&v);// - camera_position.vy;
|
|
|
|
v.vx = (pPed->position.vx - camera_position.vx) + Skel[ROOT].pvOrigPos->vx;
|
|
v.vz = (pPed->position.vz - camera_position.vz) + Skel[ROOT].pvOrigPos->vz;
|
|
//v.vy = -camera_position.vy - MapHeight((VECTOR*)&pPed->position);
|
|
|
|
bDoingShadow = 1;
|
|
|
|
if (pPed->padId == 0)
|
|
{
|
|
if (gTimeOfDay == 3)
|
|
{
|
|
cV.b = 12;
|
|
cV.g = 12;
|
|
cV.r = 12;
|
|
TannerShadow(pPed, &v, moon_position + GameLevel, &cV, pPed->dir.vy);
|
|
}
|
|
else
|
|
{
|
|
cV.b = 32;
|
|
cV.g = 32;
|
|
cV.r = 32;
|
|
TannerShadow(pPed, &v, sun_position + GameLevel, &cV, pPed->dir.vy);
|
|
}
|
|
}
|
|
bDoingShadow = 0;
|
|
}
|
|
|
|
// [D] [T]
|
|
int DrawCharacter(LPPEDESTRIAN pPed)
|
|
{
|
|
int fr;
|
|
short size;
|
|
int phase;
|
|
|
|
CVECTOR cV;
|
|
VECTOR v;
|
|
CVECTOR cv;
|
|
VECTOR pos;
|
|
|
|
SetSkelModelPointers(pPed->pedType);
|
|
SetupTannerSkeleton(pPed);
|
|
|
|
newRotateBones(pPed, &Skel[LOWERBACK]);
|
|
|
|
gte_SetRotMatrix(&inv_camera_matrix);
|
|
|
|
iCurrBone = 0;
|
|
newShowTanner(pPed);
|
|
|
|
if (pUsedPeds->pNext == NULL && pPed->pedType == TANNER_MODEL)
|
|
{
|
|
v.vx = (pPed->position.vx - camera_position.vx) + Skel[ROOT].pvOrigPos->vx;
|
|
v.vz = (pPed->position.vz - camera_position.vz) + Skel[ROOT].pvOrigPos->vz;
|
|
|
|
bDoingShadow = 1;
|
|
v.vy = -camera_position.vy - MapHeight((VECTOR*)&pPed->position);
|
|
|
|
if (gTimeOfDay == 3)
|
|
{
|
|
cV.b = cV.g = cV.r = 12;
|
|
TannerShadow(pPed, &v, moon_position + GameLevel, &cV, pPed->dir.vy);
|
|
}
|
|
else
|
|
{
|
|
cV.b = cV.g = cV.r = 32;
|
|
TannerShadow(pPed, &v, sun_position + GameLevel, &cV, pPed->dir.vy);
|
|
}
|
|
|
|
bDoingShadow = 0;
|
|
}
|
|
else if (pPed->pedType == CIVILIAN)
|
|
{
|
|
pos.vx = pPed->position.vx;
|
|
pos.vy = pPed->position.vy;
|
|
pos.vz = pPed->position.vz;
|
|
|
|
fr = pPed->frame1 & 7;
|
|
phase = fr * 2;
|
|
|
|
pos.vy = (30 - MapHeight(&pos)) - camera_position.vy;
|
|
|
|
pos.vx -= camera_position.vx;
|
|
pos.vz -= camera_position.vz;
|
|
|
|
if (phase < 8)
|
|
size = phase + 80;
|
|
else
|
|
size = -phase + 96;
|
|
|
|
cv.b = cv.g = cv.r = 40;
|
|
|
|
RoundShadow(&pos, &cv, size);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
POLY_FT4 ft4TannerShadow[2];
|
|
TILE tileTannerClear[2];
|
|
extern TEXTURE_DETAILS tannerShadow_texture;
|
|
RECT16 rectTannerWindow;
|
|
|
|
// [D] [T]
|
|
void InitTannerShadow(void)
|
|
{
|
|
u_char brightness;
|
|
TILE* tile;
|
|
POLY_FT4* poly;
|
|
int i;
|
|
|
|
if (gTimeOfDay == 3)
|
|
brightness = 12;
|
|
else
|
|
brightness = 32;
|
|
|
|
poly = ft4TannerShadow;
|
|
tile = tileTannerClear;
|
|
|
|
rectTannerWindow.w = 64;
|
|
rectTannerWindow.h = 128;
|
|
rectTannerWindow.x = tpagepos[nperms + 1].x;
|
|
rectTannerWindow.y = tpagepos[nperms + 1].y + 128;
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
int offs = 0;
|
|
if(GameLevel == 2) // [A] bug fix for vegas
|
|
offs = 18;
|
|
|
|
poly->u0 = tannerShadow_texture.coords.u1 / 4 - 1;
|
|
poly->v0 = tannerShadow_texture.coords.v1 + offs;
|
|
|
|
poly->u1 = tannerShadow_texture.coords.u0 / 4 + 1;
|
|
poly->v1 = tannerShadow_texture.coords.v0 + offs;
|
|
|
|
poly->u2 = tannerShadow_texture.coords.u3 / 4 - 1;
|
|
poly->v2 = tannerShadow_texture.coords.v3 + offs - 18;
|
|
|
|
poly->u3 = tannerShadow_texture.coords.u2 / 4 + 1;
|
|
poly->v3 = tannerShadow_texture.coords.v2 + offs - 18;
|
|
|
|
poly->tpage = getTPage(2, 0, rectTannerWindow.x, rectTannerWindow.y);
|
|
|
|
setPolyFT4(poly);
|
|
setSemiTrans(poly, 1);
|
|
|
|
poly->r0 = poly->g0 = poly->b0 = brightness;
|
|
poly++;
|
|
|
|
setTile(tile);
|
|
|
|
tile->x0 = 0;
|
|
tile->y0 = 0;
|
|
tile->w = 64;
|
|
tile->h = 128;
|
|
tile->r0 = 0;
|
|
tile->g0 = 0;
|
|
tile->b0 = 0;
|
|
tile++;
|
|
}
|
|
}
|
|
|
|
// [D] [T]
|
|
void TannerShadow(LPPEDESTRIAN pDrawingPed, VECTOR* pPedPos, SVECTOR* pLightPos, CVECTOR* col, short angle)
|
|
{
|
|
DR_ENV* dr_env;
|
|
SVECTOR vert[4];
|
|
VECTOR d;
|
|
DRAWENV drEnv;
|
|
|
|
VECTOR cp;
|
|
SVECTOR ca;
|
|
|
|
VECTOR myVector;
|
|
int z0, z1, z2, z3;
|
|
int i;
|
|
int cn, sn;
|
|
int vx, vz;
|
|
|
|
int Tangle;
|
|
|
|
#ifndef PSX
|
|
if (gDemoLevel)
|
|
return;
|
|
#endif
|
|
|
|
#ifdef __EMSCRIPTEN__
|
|
// since any WebGL isn't able to make it drawn...
|
|
return;
|
|
#endif
|
|
|
|
if (NumPlayers > 1)
|
|
return;
|
|
|
|
memset((u_char*)&d, 0, sizeof(VECTOR));
|
|
|
|
SetDefDrawEnv(&drEnv, 0, current->draw.clip.y, 320, 256);
|
|
|
|
dr_env = (DR_ENV*)current->primptr;
|
|
SetDrawEnv(dr_env, &drEnv);
|
|
|
|
addPrim(current->ot + OTSIZE - 1, dr_env);
|
|
current->primptr += sizeof(DR_ENV);
|
|
|
|
Tangle = ratan2(-pLightPos->vx, pLightPos->vz);
|
|
|
|
SetVec(&vert[0], -128, 0, -320);
|
|
SetVec(&vert[1], 128, 0, -320);
|
|
SetVec(&vert[2], -128, 0, 40);
|
|
SetVec(&vert[3], 128, 0, 40);
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
cn = rcos(Tangle); sn = rsin(Tangle);
|
|
|
|
vx = vert[i].vx; vz = vert[i].vz;
|
|
|
|
vert[i].vx = FIXED(vx * cn) - FIXED(vz * sn);
|
|
vert[i].vz = FIXED(vx * sn) + FIXED(vz * cn);
|
|
|
|
VecAdd(&vert[i], &vert[i], pPedPos);
|
|
}
|
|
|
|
gte_SetRotMatrix(&inv_camera_matrix);
|
|
gte_SetTransVector(&d);
|
|
|
|
gte_ldv3(&vert[0], &vert[1], &vert[2]);
|
|
gte_rtpt();
|
|
|
|
gte_stsxy3(&ft4TannerShadow[current->id].x0, &ft4TannerShadow[current->id].x1, &ft4TannerShadow[current->id].x2);
|
|
gte_stsz3(&z0, &z1, &z2);
|
|
|
|
gte_ldv0(&vert[3]);
|
|
|
|
gte_rtps();
|
|
|
|
gte_stsxy(&ft4TannerShadow[current->id].x3);
|
|
gte_stsz(&z3);
|
|
|
|
if (z0 < z1)
|
|
z0 = (z0 + z1) / 2;
|
|
else
|
|
z1 = (z0 + z1) / 2;
|
|
|
|
if (z2 < z3)
|
|
z2 = (z2 + z3) / 2;
|
|
else
|
|
z3 = (z2 + z3) / 2;
|
|
|
|
if (z0 > 28)
|
|
z0 = z0 - 20;
|
|
else
|
|
z0 = 8;
|
|
|
|
if (z1 > 28)
|
|
z1 = z1 - 20;
|
|
else
|
|
z1 = 8;
|
|
|
|
if (z2 > 28)
|
|
z2 = z2 - 20;
|
|
else
|
|
z2 = 8;
|
|
|
|
if (z3 > 28)
|
|
z3 = z3 - 20;
|
|
else
|
|
z3 = 8;
|
|
|
|
addPrim(current->ot + (z0 * 2 + z3 * 6 >> 6), &ft4TannerShadow[current->id]);
|
|
//SubdivShadow(z0, z1, z2, z3, ft4TannerShadow + current->id);
|
|
|
|
{
|
|
// store vectors
|
|
cp = camera_position;
|
|
ca = camera_angle;
|
|
z1 = scr_z;
|
|
|
|
// setup new camera
|
|
SetVec(&camera_position,
|
|
pDrawingPed->position.vx + (pLightPos->vx * 90 >> 0xc),
|
|
pDrawingPed->position.vy + (pLightPos->vy * 90 >> 0xc),
|
|
pDrawingPed->position.vz + (pLightPos->vz * 90 >> 0xc));
|
|
|
|
SetVec(&myVector, pDrawingPed->position.vx, pDrawingPed->position.vy, pDrawingPed->position.vz);
|
|
PointAtTarget(&camera_position, &myVector, &camera_angle);
|
|
|
|
// build matrix
|
|
gte_SetGeomOffset(32, 60);
|
|
SetGeomScreen(scr_z = 200);
|
|
BuildWorldMatrix();
|
|
|
|
// clear to black and draw Tanner sprites
|
|
newShowTanner(pDrawingPed);
|
|
addPrim(current->ot + OTSIZE - 1, &tileTannerClear[current->id]);
|
|
|
|
// restore vectors
|
|
camera_position = cp;
|
|
camera_angle = ca;
|
|
scr_z = z1;
|
|
|
|
// build matix
|
|
gte_SetGeomOffset(160, 128);
|
|
SetGeomScreen(scr_z);
|
|
BuildWorldMatrix();
|
|
}
|
|
|
|
SetDefDrawEnv(&drEnv, rectTannerWindow.x, rectTannerWindow.y, rectTannerWindow.w, rectTannerWindow.h);
|
|
drEnv.dfe = 0; // we're drawing into VRAM - don't draw on screen
|
|
drEnv.dtd = 0; // [A] no need in dithering
|
|
|
|
dr_env = (DR_ENV*)current->primptr;
|
|
SetDrawEnv(dr_env, &drEnv);
|
|
|
|
addPrim(current->ot + OTSIZE - 1, dr_env);
|
|
current->primptr += sizeof(DR_ENV);
|
|
}
|
|
|
|
// [A] - totally custom function but it works pretty much same as original
|
|
void DoCivHead(LPPEDESTRIAN pPed, SVECTOR* vert1, SVECTOR* vert2)
|
|
{
|
|
SVECTOR spos;
|
|
VECTOR pos;
|
|
SVECTOR headpos;
|
|
MATRIX* pHeadRot;
|
|
int oldcombointensity;
|
|
|
|
if (gPed1HeadModelPtr == NULL)
|
|
return;
|
|
|
|
pHeadRot = (MATRIX*)&matrixtable[((pPed->dir.vy - pPed->head_rot) / 64) & 0x3F];
|
|
|
|
if (bAllreadyRotated) // not needed to rotate vert1
|
|
{
|
|
headpos.vx = vert1->vx;
|
|
headpos.vy = vert1->vy;
|
|
headpos.vz = vert1->vz;
|
|
}
|
|
else
|
|
{
|
|
gte_SetRotMatrix(&matrixtable[((pPed->dir.vy) / 64) & 0x3F]);
|
|
|
|
gte_ldv0(vert1);
|
|
gte_rtv0();
|
|
|
|
gte_stsv(&headpos);
|
|
}
|
|
|
|
spos.vx = headpos.vx + pPed->position.vx - camera_position.vx;
|
|
spos.vy = headpos.vy + pPed->position.vy - camera_position.vy;
|
|
spos.vz = headpos.vz + pPed->position.vz - camera_position.vz;
|
|
|
|
gte_SetRotMatrix(&inv_camera_matrix);
|
|
gte_ldv0(&spos);
|
|
gte_rtv0();
|
|
|
|
gte_stlvnl(&pos);
|
|
|
|
gte_SetTransVector(&pos);
|
|
|
|
int flags = PLOT_NO_SHADE;
|
|
|
|
if (pPed->pallet & 0xf)
|
|
{
|
|
flags |= PLOT_CUSTOM_PALETTE; // set custom palette flag
|
|
plotContext.clut = civ_clut[0][texturePedHead.texture_number][pPed->pallet & 0xf] << 0x10;
|
|
}
|
|
|
|
oldcombointensity = combointensity;
|
|
|
|
if (gNight)
|
|
combointensity = 0x404040;
|
|
|
|
RenderModel(gPed1HeadModelPtr, pHeadRot, &pos, 1, flags, 0, 0);
|
|
|
|
combointensity = oldcombointensity;
|
|
}
|
|
|
|
|