mirror of
https://github.com/snesrev/zelda3.git
synced 2025-12-25 02:14:49 -05:00
324 lines
11 KiB
C
324 lines
11 KiB
C
#include "poly.h"
|
|
#include "zelda_rtl.h"
|
|
#include "variables.h"
|
|
|
|
static const int8 kPolySinCos[320] = {
|
|
0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23,
|
|
24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44,
|
|
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59,
|
|
59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60,
|
|
59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46,
|
|
45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26,
|
|
24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2,
|
|
0, -2, -3, -5, -6, -8, -9, -11, -12, -14, -16, -17, -19, -20, -22, -23,
|
|
-24, -26, -27, -29, -30, -32, -33, -34, -36, -37, -38, -39, -41, -42, -43, -44,
|
|
-45, -46, -47, -48, -49, -50, -51, -52, -53, -54, -55, -56, -56, -57, -58, -59,
|
|
-59, -60, -60, -61, -61, -62, -62, -62, -63, -63, -63, -64, -64, -64, -64, -64,
|
|
-64, -64, -64, -64, -64, -64, -63, -63, -63, -62, -62, -62, -61, -61, -60, -60,
|
|
-59, -59, -58, -57, -56, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46,
|
|
-45, -44, -43, -42, -41, -39, -38, -37, -36, -34, -33, -32, -30, -29, -27, -26,
|
|
-24, -23, -22, -20, -19, -17, -16, -14, -12, -11, -9, -8, -6, -5, -3, -2,
|
|
0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23,
|
|
24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44,
|
|
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59,
|
|
59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64,
|
|
};
|
|
typedef struct Vertex3 {
|
|
int8 x, y, z;
|
|
} Vertex3;
|
|
static const Vertex3 kPoly0_Vtx[6] = {
|
|
{ 0, 65, 0},
|
|
{ 0, -65, 0},
|
|
{ 0, 0, -40},
|
|
{-40, 0, 0},
|
|
{ 0, 0, 40},
|
|
{ 40, 0, 0},
|
|
};
|
|
static const uint8 kPoly0_Polys[40] = {
|
|
3, 0, 5, 2, 4,
|
|
3, 0, 2, 3, 1,
|
|
3, 0, 3, 4, 2,
|
|
3, 0, 4, 5, 3,
|
|
3, 1, 2, 5, 4,
|
|
3, 1, 3, 2, 1,
|
|
3, 1, 4, 3, 2,
|
|
3, 1, 5, 4, 3,
|
|
};
|
|
static const Vertex3 kPoly1_Vtx[6] = {
|
|
{ 0, 40, 10},
|
|
{ 40, -40, 10},
|
|
{-40, -40, 10},
|
|
{ 0, 40, -10},
|
|
{-40, -40, -10},
|
|
{ 40, -40, -10},
|
|
};
|
|
static const uint8 kPoly1_Polys[28] = {
|
|
3, 0, 1, 2, 7,
|
|
3, 3, 4, 5, 6,
|
|
4, 0, 3, 5, 1, 5,
|
|
4, 1, 5, 4, 2, 4,
|
|
4, 3, 0, 2, 4, 3,
|
|
};
|
|
typedef struct PolyConfig {
|
|
uint8 num_vtx, num_poly;
|
|
uint16 vtx_val, polys_val;
|
|
const Vertex3 *vertex;
|
|
const uint8 *poly;
|
|
} PolyConfig;
|
|
static const PolyConfig kPolyConfigs[2] = {
|
|
{6, 8, 0xff98, 0xffaa, kPoly0_Vtx, kPoly0_Polys},
|
|
{6, 5, 0xffd2, 0xffe4, kPoly1_Vtx, kPoly1_Polys},
|
|
};
|
|
static const uint32 kPoly_RasterColors[16] = {
|
|
0x00, 0xff, 0xff00, 0xffff,
|
|
0xff0000, 0xff00ff, 0xffff00, 0xffffff,
|
|
0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
|
|
0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff,
|
|
};
|
|
static const uint16 kPoly_LeftSideMask[8] = {0xffff, 0x7f7f, 0x3f3f, 0x1f1f, 0xf0f, 0x707, 0x303, 0x101};
|
|
static const uint16 kPoly_RightSideMask[8] = {0x8080, 0xc0c0, 0xe0e0, 0xf0f0, 0xf8f8, 0xfcfc, 0xfefe, 0xffff};
|
|
uint16 Poly_Divide(uint16 a, uint16 b) {
|
|
poly_tmp1 = sign16(a) ? -a : a;
|
|
poly_tmp0 = b;
|
|
while (poly_tmp0 >= 256)
|
|
poly_tmp0 >>= 1, poly_tmp1 >>= 1;
|
|
int q = poly_tmp1 / poly_tmp0;
|
|
return sign16(a) ? -q : q;
|
|
}
|
|
|
|
void Poly_RunFrame() {
|
|
Polyhedral_EmptyBitMapBuffer();
|
|
Polyhedral_SetShapePointer();
|
|
Polyhedral_SetRotationMatrix();
|
|
Polyhedral_OperateRotation();
|
|
Polyhedral_DrawPolyhedron();
|
|
}
|
|
|
|
void Polyhedral_SetShapePointer() { // 89f83d
|
|
poly_var1 = poly_config1 * 2 + 0x80;
|
|
poly_tmp0 = poly_which_model * 2;
|
|
|
|
const PolyConfig *poly_config = &kPolyConfigs[poly_which_model];
|
|
poly_config_num_vertex = poly_config->num_vtx;
|
|
poly_config_num_polys = poly_config->num_poly;
|
|
poly_fromlut_ptr2 = poly_config->vtx_val;
|
|
poly_fromlut_ptr4 = poly_config->polys_val;
|
|
}
|
|
|
|
void Polyhedral_SetRotationMatrix() { // 89f864
|
|
poly_sin_a = kPolySinCos[poly_a];
|
|
poly_cos_a = kPolySinCos[poly_a + 64];
|
|
poly_sin_b = kPolySinCos[poly_b];
|
|
poly_cos_b = kPolySinCos[poly_b + 64];
|
|
poly_e0 = (int16)poly_sin_b * (int8)poly_sin_a >> 8 << 2;
|
|
poly_e1 = (int16)poly_cos_b * (int8)poly_cos_a >> 8 << 2;
|
|
poly_e2 = (int16)poly_cos_b * (int8)poly_sin_a >> 8 << 2;
|
|
poly_e3 = (int16)poly_sin_b * (int8)poly_cos_a >> 8 << 2;
|
|
}
|
|
|
|
void Polyhedral_OperateRotation() { // 89f8fb
|
|
const PolyConfig *poly_config = &kPolyConfigs[poly_which_model];
|
|
const int8 *src = &poly_config->vertex[0].x;
|
|
int i = poly_config_num_vertex;
|
|
src += i * 3;
|
|
do {
|
|
src -= 3, i -= 1;
|
|
poly_fromlut_x = src[2];
|
|
poly_fromlut_y = src[1];
|
|
poly_fromlut_z = src[0];
|
|
Polyhedral_RotatePoint();
|
|
Polyhedral_ProjectPoint();
|
|
poly_arr_x[i] = poly_base_x + poly_f0;
|
|
poly_arr_y[i] = poly_base_y - poly_f1;
|
|
} while (i);
|
|
}
|
|
|
|
void Polyhedral_RotatePoint() { // 89f931
|
|
int x = (int8)poly_fromlut_x;
|
|
int y = (int8)poly_fromlut_y;
|
|
int z = (int8)poly_fromlut_z;
|
|
|
|
poly_f0 = (int16)poly_cos_b * z - (int16)poly_sin_b * x;
|
|
poly_f1 = (int16)poly_e0 * z + (int16)poly_cos_a * y + (int16)poly_e2 * x;
|
|
poly_f2 = ((int16)poly_e3 * z >> 8) - ((int16)poly_sin_a * y >> 8) + ((int16)poly_e1 * x >> 8) + poly_var1;
|
|
}
|
|
|
|
void Polyhedral_ProjectPoint() { // 89f9d6
|
|
poly_f0 = Poly_Divide(poly_f0, poly_f2);
|
|
poly_f1 = Poly_Divide(poly_f1, poly_f2);
|
|
}
|
|
|
|
void Polyhedral_DrawPolyhedron() { // 89fa4f
|
|
const PolyConfig *poly_config = &kPolyConfigs[poly_which_model];
|
|
const uint8 *src = poly_config->poly;
|
|
do {
|
|
poly_num_vertex_in_poly = *src++;
|
|
BYTE(poly_tmp0) = poly_num_vertex_in_poly;
|
|
poly_xy_coords[0] = poly_num_vertex_in_poly * 2;
|
|
|
|
int i = 1;
|
|
do {
|
|
int j = *src++;
|
|
poly_xy_coords[i + 0] = poly_arr_x[j];
|
|
poly_xy_coords[i + 1] = poly_arr_y[j];
|
|
i += 2;
|
|
} while (--BYTE(poly_tmp0));
|
|
|
|
poly_raster_color_config = *src++;
|
|
int order = Polyhedral_CalculateCrossProduct();
|
|
if (order > 0) {
|
|
Polyhedral_SetForegroundColor();
|
|
Polyhedral_DrawFace();
|
|
}
|
|
} while (--poly_config_num_polys);
|
|
}
|
|
|
|
void Polyhedral_SetForegroundColor() { // 89faca
|
|
uint8 t = poly_which_model ? (poly_config1 >> 5) : 0;
|
|
uint8 a = (poly_tmp0 << (t + 1)) >> 8;
|
|
Polyhedral_SetColorMask(a <= 1 ? 1 : a >= 7 ? 7 : a);
|
|
}
|
|
|
|
int16 Polyhedral_CalculateCrossProduct() { // 89fb24
|
|
int16 a = poly_xy_coords[3] - poly_xy_coords[1];
|
|
poly_tmp0 = a * (int8)(poly_xy_coords[6] - poly_xy_coords[4]);
|
|
a = poly_xy_coords[5] - poly_xy_coords[3];
|
|
poly_tmp0 -= a * (int8)(poly_xy_coords[4] - poly_xy_coords[2]);
|
|
return poly_tmp0;
|
|
}
|
|
|
|
void Polyhedral_SetColorMask(int c) { // 89fcae
|
|
uint32 v = kPoly_RasterColors[c];
|
|
poly_raster_color0 = v;
|
|
poly_raster_color1 = v >> 16;
|
|
}
|
|
|
|
void Polyhedral_EmptyBitMapBuffer() { // 89fd04
|
|
memset(polyhedral_buffer, 0, 0x800);
|
|
}
|
|
|
|
void Polyhedral_DrawFace() { // 89fd1e
|
|
int n = poly_xy_coords[0];
|
|
uint8 min_y = poly_xy_coords[n];
|
|
int min_idx = n;
|
|
while (n -= 2) {
|
|
if (poly_xy_coords[n] < min_y)
|
|
min_y = poly_xy_coords[n], min_idx = n;
|
|
}
|
|
poly_raster_dst_ptr = 0xe800 + (((min_y & 0x38) ^ (min_y & 0x20 ? 0x24 : 0)) << 6) + (min_y & 7) * 2;
|
|
poly_cur_vertex_idx0 = poly_cur_vertex_idx1 = min_idx;
|
|
poly_total_num_steps = poly_xy_coords[0] >> 1;
|
|
poly_y0_cur = poly_y1_cur = poly_xy_coords[min_idx];
|
|
poly_x0_cur = poly_x1_cur = poly_xy_coords[min_idx - 1];
|
|
if (Polyhedral_SetLeft() || Polyhedral_SetRight())
|
|
return;
|
|
for (;;) {
|
|
Polyhedral_FillLine();
|
|
if (BYTE(poly_raster_dst_ptr) != 0xe) {
|
|
poly_raster_dst_ptr += 2;
|
|
} else {
|
|
uint8 a = HIBYTE(poly_raster_dst_ptr) + 2;
|
|
poly_raster_dst_ptr = (a ^ ((a & 8) ? 0 : 0x19)) << 8;
|
|
}
|
|
if (poly_y0_cur == poly_y0_trig) {
|
|
poly_x0_cur = poly_x0_target;
|
|
if (Polyhedral_SetLeft())
|
|
return;
|
|
}
|
|
poly_y0_cur++;
|
|
if (poly_y1_cur == poly_y1_trig) {
|
|
poly_x1_cur = poly_x1_target;
|
|
if (Polyhedral_SetRight())
|
|
return;
|
|
}
|
|
poly_y1_cur++;
|
|
poly_x0_frac += poly_x0_step;
|
|
poly_x1_frac += poly_x1_step;
|
|
}
|
|
}
|
|
|
|
void Polyhedral_FillLine() { // 89fdcf
|
|
uint16 left = kPoly_LeftSideMask[(poly_x0_frac >> 8) & 7];
|
|
uint16 right = kPoly_RightSideMask[(poly_x1_frac >> 8) & 7];
|
|
poly_tmp2 = (poly_x0_frac >> 8) & 0x38;
|
|
int d0 = ((poly_x1_frac >> 8) & 0x38);
|
|
uint16 *ptr = (uint16*)&g_ram[poly_raster_dst_ptr + d0 * 4];
|
|
if ((d0 -= poly_tmp2) == 0) {
|
|
poly_tmp1 = left & right;
|
|
ptr[0] ^= (ptr[0] ^ poly_raster_color0) & poly_tmp1;
|
|
ptr[8] ^= (ptr[8] ^ poly_raster_color1) & poly_tmp1;
|
|
return;
|
|
}
|
|
if (d0 < 0)
|
|
return;
|
|
int n = d0 >> 3;
|
|
ptr[0] ^= (ptr[0] ^ poly_raster_color0) & right;
|
|
ptr[8] ^= (ptr[8] ^ poly_raster_color1) & right;
|
|
ptr -= 0x10;
|
|
while (--n) {
|
|
ptr[0] = poly_raster_color0;
|
|
ptr[8] = poly_raster_color1;
|
|
ptr -= 0x10;
|
|
}
|
|
ptr[0] ^= (ptr[0] ^ poly_raster_color0) & left;
|
|
ptr[8] ^= (ptr[8] ^ poly_raster_color1) & left;
|
|
poly_tmp1 = left, poly_raster_numfull = 0;
|
|
}
|
|
|
|
bool Polyhedral_SetLeft() { // 89feb4
|
|
int i;
|
|
for (;;) {
|
|
if (sign8(--poly_total_num_steps))
|
|
return true;
|
|
i = poly_cur_vertex_idx0 - 2;
|
|
if (i == 0)
|
|
i = poly_xy_coords[0];
|
|
if (poly_xy_coords[i] < poly_y0_cur)
|
|
return true;
|
|
if (poly_xy_coords[i] != poly_y0_cur)
|
|
break;
|
|
poly_x0_cur = poly_xy_coords[i - 1];
|
|
poly_cur_vertex_idx0 = i;
|
|
}
|
|
poly_y0_trig = poly_xy_coords[i];
|
|
poly_x0_target = poly_xy_coords[i - 1];
|
|
poly_cur_vertex_idx0 = i;
|
|
int t = poly_x0_target - poly_x0_cur, u = t;
|
|
if (t < 0)
|
|
t = -t;
|
|
t = ((t & 0xff) << 8) / (uint8)(poly_y0_trig - poly_y0_cur);
|
|
poly_x0_frac = (poly_x0_cur << 8) | 0x80;
|
|
poly_x0_step = (u < 0) ? -t : t;
|
|
return false;
|
|
}
|
|
|
|
bool Polyhedral_SetRight() { // 89ff1e
|
|
int i;
|
|
for (;;) {
|
|
if (sign8(--poly_total_num_steps))
|
|
return true;
|
|
i = poly_cur_vertex_idx1;
|
|
if (i == poly_xy_coords[0])
|
|
i = 0;
|
|
i += 2;
|
|
if (poly_xy_coords[i] < poly_y1_cur)
|
|
return true;
|
|
if (poly_xy_coords[i] != poly_y1_cur)
|
|
break;
|
|
poly_x1_cur = poly_xy_coords[i - 1];
|
|
poly_cur_vertex_idx1 = i;
|
|
}
|
|
poly_y1_trig = poly_xy_coords[i];
|
|
poly_x1_target = poly_xy_coords[i - 1];
|
|
poly_cur_vertex_idx1 = i;
|
|
int t = poly_x1_target - poly_x1_cur, u = t;
|
|
if (t < 0)
|
|
t = -t;
|
|
t = ((t & 0xff) << 8) / (uint8)(poly_y1_trig - poly_y1_cur);
|
|
poly_x1_frac = (poly_x1_cur << 8) | 0x80;
|
|
poly_x1_step = (u < 0) ? -t : t;
|
|
return false;
|
|
}
|
|
|