243 lines
10 KiB
C
243 lines
10 KiB
C
/*
|
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
|
* running old operating systems and software designed for IBM
|
|
* PC systems and compatibles from 1981 through fairly recent
|
|
* system designs based on the PCI bus.
|
|
*
|
|
* This file is part of the 86Box distribution.
|
|
*
|
|
* 3DFX Voodoo emulation.
|
|
*
|
|
*
|
|
*
|
|
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
|
|
*
|
|
* Copyright 2008-2020 Sarah Walker.
|
|
*/
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <wchar.h>
|
|
#include <math.h>
|
|
#define HAVE_STDARG_H
|
|
#include <86box/86box.h>
|
|
#include "cpu.h"
|
|
#include <86box/machine.h>
|
|
#include <86box/device.h>
|
|
#include <86box/mem.h>
|
|
#include <86box/timer.h>
|
|
#include <86box/device.h>
|
|
#include <86box/plat.h>
|
|
#include <86box/thread.h>
|
|
#include <86box/video.h>
|
|
#include <86box/vid_svga.h>
|
|
#include <86box/vid_voodoo_common.h>
|
|
#include <86box/vid_voodoo_regs.h>
|
|
#include <86box/vid_voodoo_render.h>
|
|
#include <86box/vid_voodoo_setup.h>
|
|
|
|
#ifdef ENABLE_VOODOO_SETUP_LOG
|
|
int voodoo_setup_do_log = ENABLE_VOODOO_SETUP_LOG;
|
|
|
|
static void
|
|
voodoo_setup_log(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
if (voodoo_setup_do_log) {
|
|
va_start(ap, fmt);
|
|
pclog_ex(fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
}
|
|
#else
|
|
# define voodoo_setup_log(fmt, ...)
|
|
#endif
|
|
|
|
void
|
|
voodoo_triangle_setup(voodoo_t *voodoo)
|
|
{
|
|
float dxAB;
|
|
float dxBC;
|
|
float dyAB;
|
|
float dyBC;
|
|
float area;
|
|
int va = 0;
|
|
int vb = 1;
|
|
int vc = 2;
|
|
vert_t verts[3];
|
|
|
|
verts[0] = voodoo->verts[0];
|
|
verts[1] = voodoo->verts[1];
|
|
verts[2] = voodoo->verts[2];
|
|
|
|
if (verts[0].sVy < verts[1].sVy) {
|
|
if (verts[1].sVy < verts[2].sVy) {
|
|
/* V1>V0, V2>V1, V2>V1>V0*/
|
|
va = 0; /*OK*/
|
|
vb = 1;
|
|
vc = 2;
|
|
} else {
|
|
/* V1>V0, V1>V2*/
|
|
if (verts[0].sVy < verts[2].sVy) {
|
|
/* V1>V0, V1>V2, V2>V0, V1>V2>V0*/
|
|
va = 0;
|
|
vb = 2;
|
|
vc = 1;
|
|
} else {
|
|
/* V1>V0, V1>V2, V0>V2, V1>V0>V2*/
|
|
va = 2;
|
|
vb = 0;
|
|
vc = 1;
|
|
}
|
|
}
|
|
} else {
|
|
if (verts[1].sVy < verts[2].sVy) {
|
|
/* V0>V1, V2>V1*/
|
|
if (verts[0].sVy < verts[2].sVy) {
|
|
/* V0>V1, V2>V1, V2>V0, V2>V0>V1*/
|
|
va = 1;
|
|
vb = 0;
|
|
vc = 2;
|
|
} else {
|
|
/* V0>V1, V2>V1, V0>V2, V0>V2>V1*/
|
|
va = 1;
|
|
vb = 2;
|
|
vc = 0;
|
|
}
|
|
} else {
|
|
/*V0>V1>V2*/
|
|
va = 2;
|
|
vb = 1;
|
|
vc = 0;
|
|
}
|
|
}
|
|
|
|
dxAB = verts[0].sVx - verts[1].sVx;
|
|
dxBC = verts[1].sVx - verts[2].sVx;
|
|
dyAB = verts[0].sVy - verts[1].sVy;
|
|
dyBC = verts[1].sVy - verts[2].sVy;
|
|
|
|
area = dxAB * dyBC - dxBC * dyAB;
|
|
|
|
if (area == 0.0)
|
|
return;
|
|
|
|
if (voodoo->sSetupMode & SETUPMODE_CULLING_ENABLE) {
|
|
int cull_sign = voodoo->sSetupMode & SETUPMODE_CULLING_SIGN;
|
|
int sign = (area < 0.0);
|
|
|
|
if ((voodoo->sSetupMode & (SETUPMODE_CULLING_ENABLE | SETUPMODE_DISABLE_PINGPONG))
|
|
== SETUPMODE_CULLING_ENABLE
|
|
&& voodoo->cull_pingpong)
|
|
cull_sign = !cull_sign;
|
|
|
|
if (cull_sign && sign)
|
|
return;
|
|
if (!cull_sign && !sign)
|
|
return;
|
|
}
|
|
|
|
dxAB = verts[va].sVx - verts[vb].sVx;
|
|
dxBC = verts[vb].sVx - verts[vc].sVx;
|
|
dyAB = verts[va].sVy - verts[vb].sVy;
|
|
dyBC = verts[vb].sVy - verts[vc].sVy;
|
|
|
|
area = dxAB * dyBC - dxBC * dyAB;
|
|
|
|
dxAB /= area;
|
|
dxBC /= area;
|
|
dyAB /= area;
|
|
dyBC /= area;
|
|
|
|
voodoo->params.vertexAx = (int32_t) (int16_t) ((int32_t) (verts[va].sVx * 16.0f) & 0xffff);
|
|
voodoo->params.vertexAy = (int32_t) (int16_t) ((int32_t) (verts[va].sVy * 16.0f) & 0xffff);
|
|
voodoo->params.vertexBx = (int32_t) (int16_t) ((int32_t) (verts[vb].sVx * 16.0f) & 0xffff);
|
|
voodoo->params.vertexBy = (int32_t) (int16_t) ((int32_t) (verts[vb].sVy * 16.0f) & 0xffff);
|
|
voodoo->params.vertexCx = (int32_t) (int16_t) ((int32_t) (verts[vc].sVx * 16.0f) & 0xffff);
|
|
voodoo->params.vertexCy = (int32_t) (int16_t) ((int32_t) (verts[vc].sVy * 16.0f) & 0xffff);
|
|
|
|
if (voodoo->params.vertexAy > voodoo->params.vertexBy || voodoo->params.vertexBy > voodoo->params.vertexCy) {
|
|
voodoo_setup_log("triangle_setup wrong order %d %d %d\n", voodoo->params.vertexAy, voodoo->params.vertexBy, voodoo->params.vertexCy);
|
|
return;
|
|
}
|
|
|
|
if (voodoo->sSetupMode & SETUPMODE_RGB) {
|
|
voodoo->params.startR = (int32_t) (verts[va].sRed * 4096.0f);
|
|
voodoo->params.dRdX = (int32_t) (((verts[va].sRed - verts[vb].sRed) * dyBC - (verts[vb].sRed - verts[vc].sRed) * dyAB) * 4096.0f);
|
|
voodoo->params.dRdY = (int32_t) (((verts[vb].sRed - verts[vc].sRed) * dxAB - (verts[va].sRed - verts[vb].sRed) * dxBC) * 4096.0f);
|
|
voodoo->params.startG = (int32_t) (verts[va].sGreen * 4096.0f);
|
|
voodoo->params.dGdX = (int32_t) (((verts[va].sGreen - verts[vb].sGreen) * dyBC - (verts[vb].sGreen - verts[vc].sGreen) * dyAB) * 4096.0f);
|
|
voodoo->params.dGdY = (int32_t) (((verts[vb].sGreen - verts[vc].sGreen) * dxAB - (verts[va].sGreen - verts[vb].sGreen) * dxBC) * 4096.0f);
|
|
voodoo->params.startB = (int32_t) (verts[va].sBlue * 4096.0f);
|
|
voodoo->params.dBdX = (int32_t) (((verts[va].sBlue - verts[vb].sBlue) * dyBC - (verts[vb].sBlue - verts[vc].sBlue) * dyAB) * 4096.0f);
|
|
voodoo->params.dBdY = (int32_t) (((verts[vb].sBlue - verts[vc].sBlue) * dxAB - (verts[va].sBlue - verts[vb].sBlue) * dxBC) * 4096.0f);
|
|
}
|
|
if (voodoo->sSetupMode & SETUPMODE_ALPHA) {
|
|
voodoo->params.startA = (int32_t) (verts[va].sAlpha * 4096.0f);
|
|
voodoo->params.dAdX = (int32_t) (((verts[va].sAlpha - verts[vb].sAlpha) * dyBC - (verts[vb].sAlpha - verts[vc].sAlpha) * dyAB) * 4096.0f);
|
|
voodoo->params.dAdY = (int32_t) (((verts[vb].sAlpha - verts[vc].sAlpha) * dxAB - (verts[va].sAlpha - verts[vb].sAlpha) * dxBC) * 4096.0f);
|
|
}
|
|
if (voodoo->sSetupMode & SETUPMODE_Z) {
|
|
voodoo->params.startZ = (int32_t) (verts[va].sVz * 4096.0f);
|
|
voodoo->params.dZdX = (int32_t) (((verts[va].sVz - verts[vb].sVz) * dyBC - (verts[vb].sVz - verts[vc].sVz) * dyAB) * 4096.0f);
|
|
voodoo->params.dZdY = (int32_t) (((verts[vb].sVz - verts[vc].sVz) * dxAB - (verts[va].sVz - verts[vb].sVz) * dxBC) * 4096.0f);
|
|
}
|
|
if (voodoo->sSetupMode & SETUPMODE_Wb) {
|
|
voodoo->params.startW = (int64_t) (verts[va].sWb * 4294967296.0f);
|
|
voodoo->params.dWdX = (int64_t) (((verts[va].sWb - verts[vb].sWb) * dyBC - (verts[vb].sWb - verts[vc].sWb) * dyAB) * 4294967296.0f);
|
|
voodoo->params.dWdY = (int64_t) (((verts[vb].sWb - verts[vc].sWb) * dxAB - (verts[va].sWb - verts[vb].sWb) * dxBC) * 4294967296.0f);
|
|
voodoo->params.tmu[0].startW = voodoo->params.tmu[1].startW = voodoo->params.startW;
|
|
voodoo->params.tmu[0].dWdX = voodoo->params.tmu[1].dWdX = voodoo->params.dWdX;
|
|
voodoo->params.tmu[0].dWdY = voodoo->params.tmu[1].dWdY = voodoo->params.dWdY;
|
|
}
|
|
if (voodoo->sSetupMode & SETUPMODE_W0) {
|
|
voodoo->params.tmu[0].startW = (int64_t) (verts[va].sW0 * 4294967296.0f);
|
|
voodoo->params.tmu[0].dWdX = (int64_t) (((verts[va].sW0 - verts[vb].sW0) * dyBC - (verts[vb].sW0 - verts[vc].sW0) * dyAB) * 4294967296.0f);
|
|
voodoo->params.tmu[0].dWdY = (int64_t) (((verts[vb].sW0 - verts[vc].sW0) * dxAB - (verts[va].sW0 - verts[vb].sW0) * dxBC) * 4294967296.0f);
|
|
voodoo->params.tmu[1].startW = voodoo->params.tmu[0].startW;
|
|
voodoo->params.tmu[1].dWdX = voodoo->params.tmu[0].dWdX;
|
|
voodoo->params.tmu[1].dWdY = voodoo->params.tmu[0].dWdY;
|
|
}
|
|
if (voodoo->sSetupMode & SETUPMODE_S0_T0) {
|
|
voodoo->params.tmu[0].startS = (int64_t) (verts[va].sS0 * 4294967296.0f);
|
|
voodoo->params.tmu[0].dSdX = (int64_t) (((verts[va].sS0 - verts[vb].sS0) * dyBC - (verts[vb].sS0 - verts[vc].sS0) * dyAB) * 4294967296.0f);
|
|
voodoo->params.tmu[0].dSdY = (int64_t) (((verts[vb].sS0 - verts[vc].sS0) * dxAB - (verts[va].sS0 - verts[vb].sS0) * dxBC) * 4294967296.0f);
|
|
voodoo->params.tmu[0].startT = (int64_t) (verts[va].sT0 * 4294967296.0f);
|
|
voodoo->params.tmu[0].dTdX = (int64_t) (((verts[va].sT0 - verts[vb].sT0) * dyBC - (verts[vb].sT0 - verts[vc].sT0) * dyAB) * 4294967296.0f);
|
|
voodoo->params.tmu[0].dTdY = (int64_t) (((verts[vb].sT0 - verts[vc].sT0) * dxAB - (verts[va].sT0 - verts[vb].sT0) * dxBC) * 4294967296.0f);
|
|
voodoo->params.tmu[1].startS = voodoo->params.tmu[0].startS;
|
|
voodoo->params.tmu[1].dSdX = voodoo->params.tmu[0].dSdX;
|
|
voodoo->params.tmu[1].dSdY = voodoo->params.tmu[0].dSdY;
|
|
voodoo->params.tmu[1].startT = voodoo->params.tmu[0].startT;
|
|
voodoo->params.tmu[1].dTdX = voodoo->params.tmu[0].dTdX;
|
|
voodoo->params.tmu[1].dTdY = voodoo->params.tmu[0].dTdY;
|
|
}
|
|
if (voodoo->sSetupMode & SETUPMODE_W1) {
|
|
voodoo->params.tmu[1].startW = (int64_t) (verts[va].sW1 * 4294967296.0f);
|
|
voodoo->params.tmu[1].dWdX = (int64_t) (((verts[va].sW1 - verts[vb].sW1) * dyBC - (verts[vb].sW1 - verts[vc].sW1) * dyAB) * 4294967296.0f);
|
|
voodoo->params.tmu[1].dWdY = (int64_t) (((verts[vb].sW1 - verts[vc].sW1) * dxAB - (verts[va].sW1 - verts[vb].sW1) * dxBC) * 4294967296.0f);
|
|
}
|
|
if (voodoo->sSetupMode & SETUPMODE_S1_T1) {
|
|
voodoo->params.tmu[1].startS = (int64_t) (verts[va].sS1 * 4294967296.0f);
|
|
voodoo->params.tmu[1].dSdX = (int64_t) (((verts[va].sS1 - verts[vb].sS1) * dyBC - (verts[vb].sS1 - verts[vc].sS1) * dyAB) * 4294967296.0f);
|
|
voodoo->params.tmu[1].dSdY = (int64_t) (((verts[vb].sS1 - verts[vc].sS1) * dxAB - (verts[va].sS1 - verts[vb].sS1) * dxBC) * 4294967296.0f);
|
|
voodoo->params.tmu[1].startT = (int64_t) (verts[va].sT1 * 4294967296.0f);
|
|
voodoo->params.tmu[1].dTdX = (int64_t) (((verts[va].sT1 - verts[vb].sT1) * dyBC - (verts[vb].sT1 - verts[vc].sT1) * dyAB) * 4294967296.0f);
|
|
voodoo->params.tmu[1].dTdY = (int64_t) (((verts[vb].sT1 - verts[vc].sT1) * dxAB - (verts[va].sT1 - verts[vb].sT1) * dxBC) * 4294967296.0f);
|
|
}
|
|
|
|
voodoo->params.sign = (area < 0.0);
|
|
|
|
if (voodoo->ncc_dirty[0])
|
|
voodoo_update_ncc(voodoo, 0);
|
|
if (voodoo->ncc_dirty[1])
|
|
voodoo_update_ncc(voodoo, 1);
|
|
voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0;
|
|
|
|
voodoo_queue_triangle(voodoo, &voodoo->params);
|
|
}
|