mirror of
https://github.com/mupen64plus/mupen64plus-oldsvn.git
synced 2025-04-02 10:52:35 -04:00
1951 lines
No EOL
69 KiB
C++
1951 lines
No EOL
69 KiB
C++
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Copyright (C) 2009 icepir8 *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
//****************************************************************
|
|
//
|
|
// Glide64 - Glide Plugin for Nintendo 64 emulators (tested mostly with Project64)
|
|
// Project started on December 29th, 2001
|
|
//
|
|
// Rules & Instructions
|
|
// v1.01
|
|
//
|
|
// To modify Glide64:
|
|
// * Write your name and (optional)email, commented by your work, so I know who did it, and so that you can find which parts you modified when it comes time to send it to me.
|
|
// * Do NOT send me the whole project or file that you modified. Take out your modified code sections, and tell me where to put them. If people sent the whole thing, I would have many different versions, but no idea how to combine them all.
|
|
//
|
|
// To add new combine modes:
|
|
// * You MUST include an example of something that uses it
|
|
// * You MUST write down the names of the GCCMUX_ things
|
|
// (see combine.cpp for details)
|
|
//
|
|
// You may create, modify, steal, use in another plugin, or do whatever you want with this code, but you MUST credit people for their work, and not claim it as your own.
|
|
// Neither I, nor anyone who is working with me, take ANY responsibility for your actions or if this program causes harm to anything, including you and your computer, in any way, physically or mentally.
|
|
//
|
|
// Official Glide64 development channel: #Glide64 on DALnet
|
|
//
|
|
// Original author: Dave2001 (aka. CM256 or CodeMaster256), Dave2999@hotmail.com
|
|
// Other authors listed by the code that they submitted.
|
|
//
|
|
//****************************************************************
|
|
|
|
#include "Gfx #1.3.h"
|
|
#include "util.h"
|
|
#include "combine.h"
|
|
#include "3dmath.h"
|
|
#include "Debugger.h"
|
|
|
|
#define Vj rdp.vtxbuf2[j]
|
|
#define Vi rdp.vtxbuf2[i]
|
|
|
|
VERTEX *vtx_list1[32]; // vertex indexing
|
|
VERTEX *vtx_list2[32];
|
|
|
|
//
|
|
// util_init - initialize data for the functions in this file
|
|
//
|
|
|
|
void util_init ()
|
|
{
|
|
for (int i=0; i<32; i++)
|
|
{
|
|
vtx_list1[i] = &rdp.vtx1[i];
|
|
vtx_list2[i] = &rdp.vtx2[i];
|
|
}
|
|
}
|
|
|
|
//software backface culling. Gonetz
|
|
// mega modifications by Dave2001
|
|
BOOL cull_tri(VERTEX **v) // type changed to VERTEX** [Dave2001]
|
|
{
|
|
int i;
|
|
|
|
// Check if completely off the screen (quick frustrum clipping for 90 FOV)
|
|
if ((v[0]->x < -v[0]->z && v[1]->x < -v[1]->z && v[2]->x < -v[2]->z) ||
|
|
(v[0]->x > v[0]->z && v[1]->x > v[1]->z && v[2]->x > v[2]->z) ||
|
|
(v[0]->y < -v[0]->z && v[1]->y < -v[1]->z && v[2]->y < -v[2]->z) ||
|
|
(v[0]->y > v[0]->z && v[1]->y > v[1]->z && v[2]->y > v[2]->z) ||
|
|
(v[0]->z < 0.1f && v[1]->z < 0.1f && v[2]->z < 0.1f))
|
|
{
|
|
RDP (" clipped\n");
|
|
return TRUE;
|
|
}
|
|
|
|
// Triangle can't be culled, if it need clipping
|
|
BOOL draw = 0;
|
|
for (i=0; i<3; i++)
|
|
{
|
|
if (!v[i]->screen_translated)
|
|
{
|
|
v[i]->sx = rdp.view_trans[0] + v[i]->x_z * rdp.view_scale[0];
|
|
v[i]->sy = rdp.view_trans[1] + v[i]->y_z * rdp.view_scale[1];
|
|
v[i]->screen_translated = 1;
|
|
}
|
|
|
|
if (v[i]->z < 0.01f) //need clip_z. can't be culled now
|
|
draw = 1;
|
|
}
|
|
|
|
if (draw) return FALSE; // z-clipping, can't be culled by software
|
|
|
|
#define SW_CULLING
|
|
#ifdef SW_CULLING
|
|
//now we need to check, if triangle's vertices are in clockwise order
|
|
// Use precalculated x/z and y/z coordinates.
|
|
float x1 = v[0]->sx - v[1]->sx;
|
|
float y1 = v[0]->sy - v[1]->sy;
|
|
float x2 = v[2]->sx - v[1]->sx;
|
|
float y2 = v[2]->sy - v[1]->sy;
|
|
|
|
DWORD mode = (rdp.flags & CULLMASK) >> CULLSHIFT;
|
|
switch (mode)
|
|
{
|
|
case 1: // cull front
|
|
if ((x1*y2 - y1*x2) < 0.0f) //counter-clockwise, positive
|
|
{
|
|
RDP (" culled!\n");
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
case 2: // cull back
|
|
if ((x1*y2 - y1*x2) >= 0.0f) //clockwise, negative
|
|
{
|
|
RDP (" culled!\n");
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void DrawTri (VERTEX **vtx)
|
|
{
|
|
for (int i=0; i<3; i++)
|
|
{
|
|
VERTEX *v = vtx[i];
|
|
|
|
if (v->uv_calculated != rdp.tex_ctr)
|
|
{
|
|
v->uv_calculated = rdp.tex_ctr;
|
|
|
|
if (!(rdp.geom_mode & 0x00020000))
|
|
{
|
|
if (!(rdp.geom_mode & 0x00000200))
|
|
{
|
|
if (rdp.geom_mode & 0x00000004) // flat shading
|
|
{
|
|
int flag = (rdp.cmd1 >> 24) & 3;
|
|
v->a = v[flag].a;
|
|
v->b = v[flag].b;
|
|
v->g = v[flag].g;
|
|
v->r = v[flag].r;
|
|
}
|
|
else // prim color
|
|
{
|
|
v->a = (BYTE)((rdp.prim_color >> 24) & 0xFF);
|
|
v->b = (BYTE)(rdp.prim_color & 0xFF);
|
|
v->g = (BYTE)((rdp.prim_color >> 8) & 0xFF);
|
|
v->r = (BYTE)((rdp.prim_color >> 16) & 0xFF);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (rdp.cmb_flags & CMB_MULT)
|
|
{
|
|
if (rdp.col[0] > 1.0f) rdp.col[0] = 1.0f;
|
|
if (rdp.col[1] > 1.0f) rdp.col[1] = 1.0f;
|
|
if (rdp.col[2] > 1.0f) rdp.col[2] = 1.0f;
|
|
if (rdp.col[0] < 0.0f) rdp.col[0] = 0.0f;
|
|
if (rdp.col[1] < 0.0f) rdp.col[1] = 0.0f;
|
|
if (rdp.col[2] < 0.0f) rdp.col[2] = 0.0f;
|
|
v->r = (BYTE)(v->r * rdp.col[0]);
|
|
v->g = (BYTE)(v->g * rdp.col[1]);
|
|
v->b = (BYTE)(v->b * rdp.col[2]);
|
|
}
|
|
if (rdp.cmb_flags & CMB_A_MULT)
|
|
{
|
|
if (rdp.col[3] > 1.0f) rdp.col[3] = 1.0f;
|
|
if (rdp.col[3] < 0.0f) rdp.col[3] = 0.0f;
|
|
v->a = (BYTE)(v->a * rdp.col[3]);
|
|
}
|
|
|
|
if (rdp.cmb_flags & CMB_SET)
|
|
{
|
|
if (rdp.col[0] > 1.0f) rdp.col[0] = 1.0f;
|
|
if (rdp.col[1] > 1.0f) rdp.col[1] = 1.0f;
|
|
if (rdp.col[2] > 1.0f) rdp.col[2] = 1.0f;
|
|
if (rdp.col[0] < 0.0f) rdp.col[0] = 0.0f;
|
|
if (rdp.col[1] < 0.0f) rdp.col[1] = 0.0f;
|
|
if (rdp.col[2] < 0.0f) rdp.col[2] = 0.0f;
|
|
v->r = (BYTE)(255.0f * rdp.col[0]);
|
|
v->g = (BYTE)(255.0f * rdp.col[1]);
|
|
v->b = (BYTE)(255.0f * rdp.col[2]);
|
|
}
|
|
if (rdp.cmb_flags & CMB_A_SET)
|
|
{
|
|
if (rdp.col[3] > 1.0f) rdp.col[3] = 1.0f;
|
|
if (rdp.col[3] < 0.0f) rdp.col[3] = 0.0f;
|
|
v->a = (BYTE)(255.0f * rdp.col[3]);
|
|
}
|
|
|
|
// Fix texture coordinates
|
|
if ((rdp.geom_mode & 0x00060000) != 0x00060000)
|
|
{
|
|
if (rdp.tex >= 1 && rdp.cur_cache[0])
|
|
{
|
|
v->u0 = v->ou * rdp.tiles[rdp.cur_tile].s_scale;
|
|
v->v0 = v->ov * rdp.tiles[rdp.cur_tile].t_scale;
|
|
|
|
if (rdp.tiles[rdp.cur_tile].shift_s)
|
|
{
|
|
if (rdp.tiles[rdp.cur_tile].shift_s > 10)
|
|
v->u0 *= (float)(1 << (16 - rdp.tiles[rdp.cur_tile].shift_s));
|
|
else
|
|
v->u0 /= (float)(1 << rdp.tiles[rdp.cur_tile].shift_s);
|
|
}
|
|
if (rdp.tiles[rdp.cur_tile].shift_t)
|
|
{
|
|
if (rdp.tiles[rdp.cur_tile].shift_t > 10)
|
|
v->v0 *= (float)(1 << (16 - rdp.tiles[rdp.cur_tile].shift_t));
|
|
else
|
|
v->v0 /= (float)(1 << rdp.tiles[rdp.cur_tile].shift_t);
|
|
}
|
|
|
|
v->u0 -= rdp.tiles[rdp.cur_tile].f_ul_s;
|
|
v->v0 -= rdp.tiles[rdp.cur_tile].f_ul_t;
|
|
|
|
v->u0 -= rdp.cur_cache[0]->offset_s;
|
|
v->v0 -= rdp.cur_cache[0]->offset_t;
|
|
|
|
v->u0 += 0.5f;
|
|
v->v0 += 0.5f;
|
|
|
|
v->u0 *= rdp.cur_cache[0]->scale;
|
|
v->v0 *= rdp.cur_cache[0]->scale;
|
|
|
|
v->u0_z = v->u0 / v->z;
|
|
v->v0_z = v->v0 / v->z;
|
|
}
|
|
if (rdp.tex >= 2 && rdp.cur_cache[1])
|
|
{
|
|
v->u1 = v->ou * rdp.tiles[rdp.cur_tile].s_scale;
|
|
v->v1 = v->ov * rdp.tiles[rdp.cur_tile].t_scale;
|
|
|
|
if (rdp.tiles[rdp.cur_tile+1].shift_s)
|
|
{
|
|
if (rdp.tiles[rdp.cur_tile+1].shift_s > 10)
|
|
v->u1 *= (float)(1 << (16 - rdp.tiles[rdp.cur_tile+1].shift_s));
|
|
else
|
|
v->u1 /= (float)(1 << rdp.tiles[rdp.cur_tile+1].shift_s);
|
|
}
|
|
if (rdp.tiles[rdp.cur_tile+1].shift_t)
|
|
{
|
|
if (rdp.tiles[rdp.cur_tile+1].shift_t > 10)
|
|
v->v1 *= (float)(1 << (16 - rdp.tiles[rdp.cur_tile+1].shift_t));
|
|
else
|
|
v->v1 /= (float)(1 << rdp.tiles[rdp.cur_tile+1].shift_t);
|
|
}
|
|
|
|
v->u1 -= rdp.tiles[rdp.cur_tile+1].f_ul_s;
|
|
v->v1 -= rdp.tiles[rdp.cur_tile+1].f_ul_t;
|
|
|
|
v->u1 -= rdp.cur_cache[1]->offset_s;
|
|
v->v1 -= rdp.cur_cache[1]->offset_t;
|
|
|
|
v->u1 += 0.5f;
|
|
v->v1 += 0.5f;
|
|
|
|
v->u1 *= rdp.cur_cache[1]->scale;
|
|
v->v1 *= rdp.cur_cache[1]->scale;
|
|
|
|
v->u1_z = v->u1 / v->z;
|
|
v->v1_z = v->v1 / v->z;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If we are spherical mapping, we still must divide by z
|
|
if (rdp.tex >= 1)
|
|
{
|
|
v->u0_z = v->u0 / v->z;
|
|
v->v0_z = v->v0 / v->z;
|
|
}
|
|
if (rdp.tex >= 2)
|
|
{
|
|
v->u1_z = v->u1 / v->z;
|
|
v->v1_z = v->v1 / v->z;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
VERTEX v[3];
|
|
|
|
v[0] = *vtx[0];
|
|
v[1] = *vtx[1];
|
|
v[2] = *vtx[2];
|
|
|
|
clip_z (v);
|
|
|
|
for (i=0; i<rdp.n_global; i++)
|
|
{
|
|
// Calculate screen coords (precalculate if not z-clipped)
|
|
if (rdp.vtxbuf[i].not_zclipped)
|
|
{
|
|
rdp.vtxbuf[i].x = rdp.vtxbuf[i].sx;
|
|
rdp.vtxbuf[i].y = rdp.vtxbuf[i].sy;
|
|
rdp.vtxbuf[i].q = rdp.vtxbuf[i].ooz;
|
|
rdp.vtxbuf[i].u0 = rdp.vtxbuf[i].u0_z;
|
|
rdp.vtxbuf[i].v0 = rdp.vtxbuf[i].v0_z;
|
|
rdp.vtxbuf[i].u1 = rdp.vtxbuf[i].u1_z;
|
|
rdp.vtxbuf[i].v1 = rdp.vtxbuf[i].v1_z;
|
|
}
|
|
else
|
|
{
|
|
rdp.vtxbuf[i].x = rdp.view_trans[0] + rdp.vtxbuf[i].x / rdp.vtxbuf[i].z * rdp.view_scale[0];
|
|
rdp.vtxbuf[i].y = rdp.view_trans[1] + rdp.vtxbuf[i].y / rdp.vtxbuf[i].z * rdp.view_scale[1];
|
|
rdp.vtxbuf[i].q = 1.0f / rdp.vtxbuf[i].z;
|
|
if (rdp.tex >= 1)
|
|
{
|
|
rdp.vtxbuf[i].u0 *= rdp.vtxbuf[i].q;
|
|
rdp.vtxbuf[i].v0 *= rdp.vtxbuf[i].q;
|
|
}
|
|
if (rdp.tex >= 2)
|
|
{
|
|
rdp.vtxbuf[i].u1 *= rdp.vtxbuf[i].q;
|
|
rdp.vtxbuf[i].v1 *= rdp.vtxbuf[i].q;
|
|
}
|
|
}
|
|
|
|
// Don't remove clipping, or it will freeze
|
|
if (rdp.vtxbuf[i].x >= rdp.scissor.lr_x) rdp.clip |= CLIP_XMAX;
|
|
if (rdp.vtxbuf[i].x < rdp.scissor.ul_x) rdp.clip |= CLIP_XMIN;
|
|
if (rdp.vtxbuf[i].y >= rdp.scissor.lr_y) rdp.clip |= CLIP_YMAX;
|
|
if (rdp.vtxbuf[i].y < rdp.scissor.ul_y) rdp.clip |= CLIP_YMIN;
|
|
}
|
|
|
|
clip_tri ();
|
|
}
|
|
|
|
//
|
|
// clip_z - clips along the z-axis, also copies the vertex buffer for clip_tri
|
|
// * ALWAYS * processes it, even if it does not need z-clipping. It needs
|
|
// to copy the buffer anyway.
|
|
//
|
|
|
|
void clip_z (VERTEX v[3])
|
|
{
|
|
int i,j,index;
|
|
float percent;
|
|
|
|
// Set vertex buffers
|
|
rdp.vtxbuf = rdp.vtx1; // copy from v to rdp.vtx1
|
|
rdp.vtxbuf2 = v;
|
|
index = 0;
|
|
rdp.vtx_buffer = 0;
|
|
|
|
// Check the vertices for clipping
|
|
for (i=0; i<3; i++)
|
|
{
|
|
j = i+1;
|
|
if (j == 3) j = 0;
|
|
|
|
if (Vi.z >= 0.01f)
|
|
{
|
|
if (Vj.z >= 0.01f) // Both are in, save the last one
|
|
{
|
|
rdp.vtxbuf[index] = Vj;
|
|
rdp.vtxbuf[index++].not_zclipped = 1;
|
|
}
|
|
else // First is in, second is out, save intersection
|
|
{
|
|
percent = (-Vi.z) / (Vj.z - Vi.z);
|
|
rdp.vtxbuf[index].not_zclipped = 0;
|
|
rdp.vtxbuf[index].x = Vi.x + (Vj.x - Vi.x) * percent;
|
|
rdp.vtxbuf[index].y = Vi.y + (Vj.y - Vi.y) * percent;
|
|
rdp.vtxbuf[index].z = 0.01f;
|
|
rdp.vtxbuf[index].u0 = Vi.u0 + (Vj.u0 - Vi.u0) * percent;
|
|
rdp.vtxbuf[index].v0 = Vi.v0 + (Vj.v0 - Vi.v0) * percent;
|
|
rdp.vtxbuf[index].u1 = Vi.u1 + (Vj.u1 - Vi.u1) * percent;
|
|
rdp.vtxbuf[index].v1 = Vi.v1 + (Vj.v1 - Vi.v1) * percent;
|
|
rdp.vtxbuf[index].b = (BYTE)(Vi.b + (Vj.b - Vi.b) * percent);
|
|
rdp.vtxbuf[index].g = (BYTE)(Vi.g + (Vj.g - Vi.g) * percent);
|
|
rdp.vtxbuf[index].r = (BYTE)(Vi.r + (Vj.r - Vi.r) * percent);
|
|
rdp.vtxbuf[index++].a = (BYTE)(Vi.a + (Vj.a - Vi.a) * percent);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//if (Vj.z < 0.01f) // Both are out, save nothing
|
|
if (Vj.z >= 0.01f) // First is out, second is in, save intersection & in point
|
|
{
|
|
percent = (-Vj.z) / (Vi.z - Vj.z);
|
|
rdp.vtxbuf[index].not_zclipped = 0;
|
|
rdp.vtxbuf[index].x = Vj.x + (Vi.x - Vj.x) * percent;
|
|
rdp.vtxbuf[index].y = Vj.y + (Vi.y - Vj.y) * percent;
|
|
rdp.vtxbuf[index].z = 0.01f;
|
|
rdp.vtxbuf[index].u0 = Vj.u0 + (Vi.u0 - Vj.u0) * percent;
|
|
rdp.vtxbuf[index].v0 = Vj.v0 + (Vi.v0 - Vj.v0) * percent;
|
|
rdp.vtxbuf[index].u1 = Vj.u1 + (Vi.u1 - Vj.u1) * percent;
|
|
rdp.vtxbuf[index].v1 = Vj.v1 + (Vi.v1 - Vj.v1) * percent;
|
|
rdp.vtxbuf[index].b = (BYTE)(Vj.b + (Vi.b - Vj.b) * percent);
|
|
rdp.vtxbuf[index].g = (BYTE)(Vj.g + (Vi.g - Vj.g) * percent);
|
|
rdp.vtxbuf[index].r = (BYTE)(Vj.r + (Vi.r - Vj.r) * percent);
|
|
rdp.vtxbuf[index++].a = (BYTE)(Vj.a + (Vi.a - Vj.a) * percent);
|
|
|
|
// Save the in point
|
|
rdp.vtxbuf[index] = Vj;
|
|
rdp.vtxbuf[index++].not_zclipped = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
rdp.n_global = index;
|
|
|
|
rdp.vtxbuf2 = rdp.vtx2; // this needs to be buffer 2 so that it can swap later
|
|
}
|
|
|
|
void clip_tri ()
|
|
{
|
|
int i,j,index,n=rdp.n_global;
|
|
float percent;
|
|
|
|
// rdp.vtxbuf and rdp.vtxbuf2 were set by clip_z
|
|
|
|
// Check which clipping is needed
|
|
if (rdp.clip & CLIP_XMAX) // right of the screen
|
|
{
|
|
// Swap vertex buffers
|
|
VERTEX *tmp = rdp.vtxbuf2;
|
|
rdp.vtxbuf2 = rdp.vtxbuf;
|
|
rdp.vtxbuf = tmp;
|
|
rdp.vtx_buffer ^= 1;
|
|
index = 0;
|
|
|
|
// Check the vertices for clipping
|
|
for (i=0; i<n; i++)
|
|
{
|
|
j = i+1;
|
|
if (j == n) j = 0;
|
|
|
|
if (Vi.x < rdp.scissor.lr_x)
|
|
{
|
|
if (Vj.x < rdp.scissor.lr_x) // Both are in, save the last one
|
|
{
|
|
rdp.vtxbuf[index++] = Vj;
|
|
}
|
|
else // First is in, second is out, save intersection
|
|
{
|
|
percent = (rdp.scissor.lr_x - Vi.x) / (Vj.x - Vi.x);
|
|
rdp.vtxbuf[index].x = (float)rdp.scissor.lr_x;
|
|
rdp.vtxbuf[index].y = Vi.y + (Vj.y - Vi.y) * percent;
|
|
rdp.vtxbuf[index].q = Vi.q + (Vj.q - Vi.q) * percent;
|
|
rdp.vtxbuf[index].u0 = Vi.u0 + (Vj.u0 - Vi.u0) * percent;
|
|
rdp.vtxbuf[index].v0 = Vi.v0 + (Vj.v0 - Vi.v0) * percent;
|
|
rdp.vtxbuf[index].u1 = Vi.u1 + (Vj.u1 - Vi.u1) * percent;
|
|
rdp.vtxbuf[index].v1 = Vi.v1 + (Vj.v1 - Vi.v1) * percent;
|
|
rdp.vtxbuf[index].b = (BYTE)(Vi.b + (Vj.b - Vi.b) * percent);
|
|
rdp.vtxbuf[index].g = (BYTE)(Vi.g + (Vj.g - Vi.g) * percent);
|
|
rdp.vtxbuf[index].r = (BYTE)(Vi.r + (Vj.r - Vi.r) * percent);
|
|
rdp.vtxbuf[index++].a = (BYTE)(Vi.a + (Vj.a - Vi.a) * percent);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//if (Vj.x >= rdp.scissor.lr_x) // Both are out, save nothing
|
|
if (Vj.x < rdp.scissor.lr_x) // First is out, second is in, save intersection & in point
|
|
{
|
|
percent = (rdp.scissor.lr_x - Vj.x) / (Vi.x - Vj.x);
|
|
rdp.vtxbuf[index].x = (float)rdp.scissor.lr_x;
|
|
rdp.vtxbuf[index].y = Vj.y + (Vi.y - Vj.y) * percent;
|
|
rdp.vtxbuf[index].q = Vj.q + (Vi.q - Vj.q) * percent;
|
|
rdp.vtxbuf[index].u0 = Vj.u0 + (Vi.u0 - Vj.u0) * percent;
|
|
rdp.vtxbuf[index].v0 = Vj.v0 + (Vi.v0 - Vj.v0) * percent;
|
|
rdp.vtxbuf[index].u1 = Vj.u1 + (Vi.u1 - Vj.u1) * percent;
|
|
rdp.vtxbuf[index].v1 = Vj.v1 + (Vi.v1 - Vj.v1) * percent;
|
|
rdp.vtxbuf[index].b = (BYTE)(Vj.b + (Vi.b - Vj.b) * percent);
|
|
rdp.vtxbuf[index].g = (BYTE)(Vj.g + (Vi.g - Vj.g) * percent);
|
|
rdp.vtxbuf[index].r = (BYTE)(Vj.r + (Vi.r - Vj.r) * percent);
|
|
rdp.vtxbuf[index++].a = (BYTE)(Vj.a + (Vi.a - Vj.a) * percent);
|
|
|
|
// Save the in point
|
|
rdp.vtxbuf[index++] = Vj;
|
|
}
|
|
}
|
|
}
|
|
n = index;
|
|
}
|
|
if (rdp.clip & CLIP_XMIN) // left of the screen
|
|
{
|
|
// Swap vertex buffers
|
|
VERTEX *tmp = rdp.vtxbuf2;
|
|
rdp.vtxbuf2 = rdp.vtxbuf;
|
|
rdp.vtxbuf = tmp;
|
|
rdp.vtx_buffer ^= 1;
|
|
index = 0;
|
|
|
|
// Check the vertices for clipping
|
|
for (i=0; i<n; i++)
|
|
{
|
|
j = i+1;
|
|
if (j == n) j = 0;
|
|
|
|
if (Vi.x >= rdp.scissor.ul_x)
|
|
{
|
|
if (Vj.x >= rdp.scissor.ul_x) // Both are in, save the last one
|
|
{
|
|
rdp.vtxbuf[index++] = Vj;
|
|
}
|
|
else // First is in, second is out, save intersection
|
|
{
|
|
percent = (rdp.scissor.ul_x - Vi.x) / (Vj.x - Vi.x);
|
|
rdp.vtxbuf[index].x = (float)rdp.scissor.ul_x;
|
|
rdp.vtxbuf[index].y = Vi.y + (Vj.y - Vi.y) * percent;
|
|
rdp.vtxbuf[index].q = Vi.q + (Vj.q - Vi.q) * percent;
|
|
rdp.vtxbuf[index].u0 = Vi.u0 + (Vj.u0 - Vi.u0) * percent;
|
|
rdp.vtxbuf[index].v0 = Vi.v0 + (Vj.v0 - Vi.v0) * percent;
|
|
rdp.vtxbuf[index].u1 = Vi.u1 + (Vj.u1 - Vi.u1) * percent;
|
|
rdp.vtxbuf[index].v1 = Vi.v1 + (Vj.v1 - Vi.v1) * percent;
|
|
rdp.vtxbuf[index].b = (BYTE)(Vi.b + (Vj.b - Vi.b) * percent);
|
|
rdp.vtxbuf[index].g = (BYTE)(Vi.g + (Vj.g - Vi.g) * percent);
|
|
rdp.vtxbuf[index].r = (BYTE)(Vi.r + (Vj.r - Vi.r) * percent);
|
|
rdp.vtxbuf[index++].a = (BYTE)(Vi.a + (Vj.a - Vi.a) * percent);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//if (Vj.x < rdp.scissor.ul_x) // Both are out, save nothing
|
|
if (Vj.x >= rdp.scissor.ul_x) // First is out, second is in, save intersection & in point
|
|
{
|
|
percent = (rdp.scissor.ul_x - Vj.x) / (Vi.x - Vj.x);
|
|
rdp.vtxbuf[index].x = (float)rdp.scissor.ul_x;
|
|
rdp.vtxbuf[index].y = Vj.y + (Vi.y - Vj.y) * percent;
|
|
rdp.vtxbuf[index].q = Vj.q + (Vi.q - Vj.q) * percent;
|
|
rdp.vtxbuf[index].u0 = Vj.u0 + (Vi.u0 - Vj.u0) * percent;
|
|
rdp.vtxbuf[index].v0 = Vj.v0 + (Vi.v0 - Vj.v0) * percent;
|
|
rdp.vtxbuf[index].u1 = Vj.u1 + (Vi.u1 - Vj.u1) * percent;
|
|
rdp.vtxbuf[index].v1 = Vj.v1 + (Vi.v1 - Vj.v1) * percent;
|
|
rdp.vtxbuf[index].b = (BYTE)(Vj.b + (Vi.b - Vj.b) * percent);
|
|
rdp.vtxbuf[index].g = (BYTE)(Vj.g + (Vi.g - Vj.g) * percent);
|
|
rdp.vtxbuf[index].r = (BYTE)(Vj.r + (Vi.r - Vj.r) * percent);
|
|
rdp.vtxbuf[index++].a = (BYTE)(Vj.a + (Vi.a - Vj.a) * percent);
|
|
|
|
// Save the in point
|
|
rdp.vtxbuf[index++] = Vj;
|
|
}
|
|
}
|
|
}
|
|
n = index;
|
|
}
|
|
if (rdp.clip & CLIP_YMAX) // top of the screen
|
|
{
|
|
// Swap vertex buffers
|
|
VERTEX *tmp = rdp.vtxbuf2;
|
|
rdp.vtxbuf2 = rdp.vtxbuf;
|
|
rdp.vtxbuf = tmp;
|
|
rdp.vtx_buffer ^= 1;
|
|
index = 0;
|
|
|
|
// Check the vertices for clipping
|
|
for (i=0; i<n; i++)
|
|
{
|
|
j = i+1;
|
|
if (j == n) j = 0;
|
|
|
|
if (Vi.y < rdp.scissor.lr_y)
|
|
{
|
|
if (Vj.y < rdp.scissor.lr_y) // Both are in, save the last one
|
|
{
|
|
rdp.vtxbuf[index++] = Vj;
|
|
}
|
|
else // First is in, second is out, save intersection
|
|
{
|
|
percent = (rdp.scissor.lr_y - Vi.y) / (Vj.y - Vi.y);
|
|
rdp.vtxbuf[index].x = Vi.x + (Vj.x - Vi.x) * percent;
|
|
rdp.vtxbuf[index].y = (float)rdp.scissor.lr_y;
|
|
rdp.vtxbuf[index].q = Vi.q + (Vj.q - Vi.q) * percent;
|
|
rdp.vtxbuf[index].u0 = Vi.u0 + (Vj.u0 - Vi.u0) * percent;
|
|
rdp.vtxbuf[index].v0 = Vi.v0 + (Vj.v0 - Vi.v0) * percent;
|
|
rdp.vtxbuf[index].u1 = Vi.u1 + (Vj.u1 - Vi.u1) * percent;
|
|
rdp.vtxbuf[index].v1 = Vi.v1 + (Vj.v1 - Vi.v1) * percent;
|
|
rdp.vtxbuf[index].b = (BYTE)(Vi.b + (Vj.b - Vi.b) * percent);
|
|
rdp.vtxbuf[index].g = (BYTE)(Vi.g + (Vj.g - Vi.g) * percent);
|
|
rdp.vtxbuf[index].r = (BYTE)(Vi.r + (Vj.r - Vi.r) * percent);
|
|
rdp.vtxbuf[index++].a = (BYTE)(Vi.a + (Vj.a - Vi.a) * percent);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//if (Vj.y >= rdp.scissor.lr_y) // Both are out, save nothing
|
|
if (Vj.y < rdp.scissor.lr_y) // First is out, second is in, save intersection & in point
|
|
{
|
|
percent = (rdp.scissor.lr_y - Vj.y) / (Vi.y - Vj.y);
|
|
rdp.vtxbuf[index].x = Vj.x + (Vi.x - Vj.x) * percent;
|
|
rdp.vtxbuf[index].y = (float)rdp.scissor.lr_y;
|
|
rdp.vtxbuf[index].q = Vj.q + (Vi.q - Vj.q) * percent;
|
|
rdp.vtxbuf[index].u0 = Vj.u0 + (Vi.u0 - Vj.u0) * percent;
|
|
rdp.vtxbuf[index].v0 = Vj.v0 + (Vi.v0 - Vj.v0) * percent;
|
|
rdp.vtxbuf[index].u1 = Vj.u1 + (Vi.u1 - Vj.u1) * percent;
|
|
rdp.vtxbuf[index].v1 = Vj.v1 + (Vi.v1 - Vj.v1) * percent;
|
|
rdp.vtxbuf[index].b = (BYTE)(Vj.b + (Vi.b - Vj.b) * percent);
|
|
rdp.vtxbuf[index].g = (BYTE)(Vj.g + (Vi.g - Vj.g) * percent);
|
|
rdp.vtxbuf[index].r = (BYTE)(Vj.r + (Vi.r - Vj.r) * percent);
|
|
rdp.vtxbuf[index++].a = (BYTE)(Vj.a + (Vi.a - Vj.a) * percent);
|
|
|
|
// Save the in point
|
|
rdp.vtxbuf[index++] = Vj;
|
|
}
|
|
}
|
|
}
|
|
n = index;
|
|
}
|
|
if (rdp.clip & CLIP_YMIN) // bottom of the screen
|
|
{
|
|
// Swap vertex buffers
|
|
VERTEX *tmp = rdp.vtxbuf2;
|
|
rdp.vtxbuf2 = rdp.vtxbuf;
|
|
rdp.vtxbuf = tmp;
|
|
rdp.vtx_buffer ^= 1;
|
|
index = 0;
|
|
|
|
// Check the vertices for clipping
|
|
for (i=0; i<n; i++)
|
|
{
|
|
j = i+1;
|
|
if (j == n) j = 0;
|
|
|
|
if (Vi.y >= rdp.scissor.ul_y)
|
|
{
|
|
if (Vj.y >= rdp.scissor.ul_y) // Both are in, save the last one
|
|
{
|
|
rdp.vtxbuf[index++] = Vj;
|
|
}
|
|
else // First is in, second is out, save intersection
|
|
{
|
|
percent = (rdp.scissor.ul_y - Vi.y) / (Vj.y - Vi.y);
|
|
rdp.vtxbuf[index].x = Vi.x + (Vj.x - Vi.x) * percent;
|
|
rdp.vtxbuf[index].y = (float)rdp.scissor.ul_y;
|
|
rdp.vtxbuf[index].q = Vi.q + (Vj.q - Vi.q) * percent;
|
|
rdp.vtxbuf[index].u0 = Vi.u0 + (Vj.u0 - Vi.u0) * percent;
|
|
rdp.vtxbuf[index].v0 = Vi.v0 + (Vj.v0 - Vi.v0) * percent;
|
|
rdp.vtxbuf[index].u1 = Vi.u1 + (Vj.u1 - Vi.u1) * percent;
|
|
rdp.vtxbuf[index].v1 = Vi.v1 + (Vj.v1 - Vi.v1) * percent;
|
|
rdp.vtxbuf[index].b = (BYTE)(Vi.b + (Vj.b - Vi.b) * percent);
|
|
rdp.vtxbuf[index].g = (BYTE)(Vi.g + (Vj.g - Vi.g) * percent);
|
|
rdp.vtxbuf[index].r = (BYTE)(Vi.r + (Vj.r - Vi.r) * percent);
|
|
rdp.vtxbuf[index++].a = (BYTE)(Vi.a + (Vj.a - Vi.a) * percent);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//if (Vj.y < rdp.scissor.ul_y) // Both are out, save nothing
|
|
if (Vj.y >= rdp.scissor.ul_y) // First is out, second is in, save intersection & in point
|
|
{
|
|
percent = (rdp.scissor.ul_y - Vj.y) / (Vi.y - Vj.y);
|
|
rdp.vtxbuf[index].x = Vj.x + (Vi.x - Vj.x) * percent;
|
|
rdp.vtxbuf[index].y = (float)rdp.scissor.ul_y;
|
|
rdp.vtxbuf[index].q = Vj.q + (Vi.q - Vj.q) * percent;
|
|
rdp.vtxbuf[index].u0 = Vj.u0 + (Vi.u0 - Vj.u0) * percent;
|
|
rdp.vtxbuf[index].v0 = Vj.v0 + (Vi.v0 - Vj.v0) * percent;
|
|
rdp.vtxbuf[index].u1 = Vj.u1 + (Vi.u1 - Vj.u1) * percent;
|
|
rdp.vtxbuf[index].v1 = Vj.v1 + (Vi.v1 - Vj.v1) * percent;
|
|
rdp.vtxbuf[index].b = (BYTE)(Vj.b + (Vi.b - Vj.b) * percent);
|
|
rdp.vtxbuf[index].g = (BYTE)(Vj.g + (Vi.g - Vj.g) * percent);
|
|
rdp.vtxbuf[index].r = (BYTE)(Vj.r + (Vi.r - Vj.r) * percent);
|
|
rdp.vtxbuf[index++].a = (BYTE)(Vj.a + (Vi.a - Vj.a) * percent);
|
|
|
|
// Save the in point
|
|
rdp.vtxbuf[index++] = Vj;
|
|
}
|
|
}
|
|
}
|
|
n = index;
|
|
}
|
|
|
|
if (n < 3) return;
|
|
|
|
if (fullscreen)
|
|
{
|
|
if (settings.wireframe)
|
|
{
|
|
for (i=0; i<n; i++)
|
|
{
|
|
j = i+1;
|
|
if (j == n) j = 0;
|
|
grDrawLine (&rdp.vtxbuf[i], &rdp.vtxbuf[j]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
grDrawVertexArray (GR_TRIANGLE_FAN, n, rdp.vtx_buffer?(&vtx_list2):(&vtx_list1));
|
|
}
|
|
}
|
|
|
|
if (debug.capture) add_tri (rdp.vtxbuf, n);
|
|
}
|
|
|
|
void add_tri (VERTEX *v, int n)
|
|
{
|
|
//FRDP ("ENTER (%f, %f, %f), (%f, %f, %f), (%f, %f, %f)\n", v[0].x, v[0].y, v[0].z,
|
|
// v[1].x, v[1].y, v[1].z, v[2].x, v[2].y, v[2].z);
|
|
|
|
// Debug capture
|
|
if (debug.capture)
|
|
{
|
|
TRI_INFO *info = new TRI_INFO;
|
|
info->nv = n;
|
|
info->v = new VERTEX [n];
|
|
memcpy (info->v, v, sizeof(VERTEX)*n);
|
|
info->cycle_mode = rdp.cycle_mode;
|
|
info->cycle1 = rdp.cycle1;
|
|
info->cycle2 = rdp.cycle2;
|
|
info->uncombined = rdp.uncombined;
|
|
info->geom_mode = rdp.geom_mode;
|
|
info->render_mode = rdp.render_mode;
|
|
info->mode_h = rdp.mode_h;
|
|
info->tri_n = rdp.tri_n;
|
|
info->temp = rdp.temp;
|
|
|
|
for (int i=0; i<2; i++)
|
|
{
|
|
int j = rdp.cur_tile+i;
|
|
info->t[i].cur_cache = rdp.cur_cache_n[j];
|
|
info->t[i].format = rdp.tiles[j].format;
|
|
info->t[i].size = rdp.tiles[j].size;
|
|
info->t[i].width = rdp.tiles[j].width;
|
|
info->t[i].height = rdp.tiles[j].height;
|
|
info->t[i].line = rdp.tiles[j].line;
|
|
info->t[i].palette = rdp.tiles[j].palette;
|
|
info->t[i].clamp_s = rdp.tiles[j].clamp_s;
|
|
info->t[i].clamp_t = rdp.tiles[j].clamp_t;
|
|
info->t[i].mirror_s = rdp.tiles[j].mirror_s;
|
|
info->t[i].mirror_t = rdp.tiles[j].mirror_t;
|
|
info->t[i].shift_s = rdp.tiles[j].shift_s;
|
|
info->t[i].shift_t = rdp.tiles[j].shift_t;
|
|
info->t[i].mask_s = rdp.tiles[j].mask_s;
|
|
info->t[i].mask_t = rdp.tiles[j].mask_t;
|
|
info->t[i].ul_s = rdp.tiles[j].ul_s;
|
|
info->t[i].ul_t = rdp.tiles[j].ul_t;
|
|
info->t[i].lr_s = rdp.tiles[j].lr_s;
|
|
info->t[i].lr_t = rdp.tiles[j].lr_t;
|
|
info->t[i].t_ul_s = rdp.tiles[7].t_ul_s;
|
|
info->t[i].t_ul_t = rdp.tiles[7].t_ul_t;
|
|
info->t[i].t_lr_s = rdp.tiles[7].t_lr_s;
|
|
info->t[i].t_lr_t = rdp.tiles[7].t_lr_t;
|
|
info->t[i].scale_s = rdp.tiles[j].s_scale;
|
|
info->t[i].scale_t = rdp.tiles[j].t_scale;
|
|
}
|
|
|
|
info->fog_color = rdp.fog_color;
|
|
info->fill_color = rdp.fill_color;
|
|
info->prim_color = rdp.prim_color;
|
|
info->blend_color = rdp.blend_color;
|
|
info->env_color = rdp.env_color;
|
|
info->real_fog_color = rdp.real_fog_color;
|
|
info->real_fill_color = rdp.real_fill_color;
|
|
info->real_prim_color = rdp.real_prim_color;
|
|
info->real_blend_color = rdp.real_blend_color;
|
|
info->real_env_color = rdp.real_env_color;
|
|
info->prim_lodmin = rdp.prim_lodmin;
|
|
info->prim_lodfrac = rdp.prim_lodfrac;
|
|
|
|
info->pNext = debug.tri_list;
|
|
debug.tri_list = info;
|
|
|
|
if (debug.tri_last == NULL)
|
|
debug.tri_last = debug.tri_list;
|
|
}
|
|
}
|
|
|
|
//
|
|
// update - update states if they need it
|
|
//
|
|
|
|
void update ()
|
|
{
|
|
RDP ("-+ update called\n");
|
|
// Check for rendermode changes
|
|
// Z buffer
|
|
if (rdp.render_mode_changed & 0x00000C30)
|
|
{
|
|
FRDP (" |- render_mode_changed zbuf - decal: %s, update: %s, compare: %s\n",
|
|
str_yn[(rdp.render_mode&0x00000C00)?1:0],
|
|
str_yn[(rdp.render_mode&0x00000020)?1:0],
|
|
str_yn[(rdp.render_mode&0x00000010)?1:0]);
|
|
|
|
rdp.render_mode_changed &= ~0x00000C30;
|
|
rdp.update |= UPDATE_ZBUF_ENABLED;
|
|
|
|
// Decal?
|
|
if ((rdp.render_mode & 0x00000C00) == 0x00000C00)
|
|
rdp.flags |= ZBUF_DECAL;
|
|
else
|
|
rdp.flags &= ~ZBUF_DECAL;
|
|
|
|
// Update?
|
|
if (rdp.render_mode & 0x00000020)
|
|
rdp.flags |= ZBUF_UPDATE;
|
|
else
|
|
rdp.flags &= ~ZBUF_UPDATE;
|
|
|
|
// Compare?
|
|
if (rdp.render_mode & 0x00000010)
|
|
rdp.flags |= ZBUF_COMPARE;
|
|
else
|
|
rdp.flags &= ~ZBUF_COMPARE;
|
|
}
|
|
|
|
// Alpha compare
|
|
if (rdp.render_mode_changed & 0x00001000)
|
|
{
|
|
FRDP (" |- render_mode_changed alpha compare - on: %s\n",
|
|
str_yn[(rdp.render_mode&0x00001000)?1:0]);
|
|
rdp.render_mode_changed &= ~0x00001000;
|
|
rdp.update |= UPDATE_ALPHA_COMPARE;
|
|
|
|
if (rdp.render_mode & 0x00001000)
|
|
rdp.flags |= ALPHA_COMPARE;
|
|
else
|
|
rdp.flags &= ~ALPHA_COMPARE;
|
|
}
|
|
|
|
if (rdp.render_mode_changed & 0x00002000) // alpha cvg sel
|
|
{
|
|
FRDP (" |- render_mode_changed alpha cvg sel - on: %s\n",
|
|
str_yn[(rdp.render_mode&0x00002000)?1:0]);
|
|
rdp.render_mode_changed &= ~0x00002000;
|
|
rdp.update |= UPDATE_COMBINE;
|
|
}
|
|
|
|
// Force blend
|
|
if (rdp.render_mode_changed & 0xFFFF0000)
|
|
{
|
|
FRDP (" |- render_mode_changed force_blend - %08lx\n", rdp.render_mode&0xFFFF0000);
|
|
rdp.render_mode_changed &= 0x0000FFFF;
|
|
|
|
rdp.fbl_a0 = (BYTE)((rdp.render_mode>>30)&0x3);
|
|
rdp.fbl_b0 = (BYTE)((rdp.render_mode>>26)&0x3);
|
|
rdp.fbl_c0 = (BYTE)((rdp.render_mode>>22)&0x3);
|
|
rdp.fbl_d0 = (BYTE)((rdp.render_mode>>18)&0x3);
|
|
rdp.fbl_a1 = (BYTE)((rdp.render_mode>>28)&0x3);
|
|
rdp.fbl_b1 = (BYTE)((rdp.render_mode>>24)&0x3);
|
|
rdp.fbl_c1 = (BYTE)((rdp.render_mode>>20)&0x3);
|
|
rdp.fbl_d1 = (BYTE)((rdp.render_mode>>16)&0x3);
|
|
|
|
rdp.update |= UPDATE_COMBINE;
|
|
}
|
|
|
|
if (rdp.update & UPDATE_CLEAR_CACHE)
|
|
{
|
|
RDP (" |- clear_cache\n");
|
|
rdp.update ^= UPDATE_CLEAR_CACHE;
|
|
|
|
rdp.tmem_ptr[0] = offset_textures;
|
|
rdp.tmem_ptr[1] = offset_textures;
|
|
rdp.n_cached[0] = 0;
|
|
rdp.n_cached[1] = 0;
|
|
}
|
|
|
|
//if (fullscreen)
|
|
//{
|
|
// Combine MUST go before texture
|
|
if ((rdp.update & UPDATE_COMBINE) && rdp.allow_combine)
|
|
{
|
|
RDP (" |-+ update_combine\n");
|
|
rdp.update ^= UPDATE_COMBINE;
|
|
Combine ();
|
|
}
|
|
|
|
if (rdp.update & UPDATE_TEXTURE)
|
|
{
|
|
rdp.update ^= UPDATE_TEXTURE;
|
|
|
|
rdp.tex_ctr ++;
|
|
if (rdp.tex_ctr == 0xFFFFFFFF)
|
|
rdp.tex_ctr = 0;
|
|
|
|
for (int tmu=0; tmu<rdp.tex; tmu++)
|
|
{
|
|
FRDP (" |-+ update_texture #%d\n", tmu);
|
|
TexCache (tmu, tmu);
|
|
|
|
if (fullscreen)
|
|
{
|
|
int tile = rdp.cur_tile+tmu;
|
|
|
|
grTexFilterMode (tmu,
|
|
(settings.filtering==1)?GR_TEXTUREFILTER_BILINEAR:GR_TEXTUREFILTER_POINT_SAMPLED,
|
|
(settings.filtering==1)?GR_TEXTUREFILTER_BILINEAR:GR_TEXTUREFILTER_POINT_SAMPLED);
|
|
|
|
DWORD mode_s, mode_t;
|
|
|
|
if ((rdp.tiles[tile].clamp_s || rdp.tiles[tile].mask_s == 0) &&
|
|
rdp.tiles[tile].lr_s-rdp.tiles[tile].ul_s < 256)
|
|
mode_s = GR_TEXTURECLAMP_CLAMP;
|
|
else
|
|
{
|
|
if (rdp.tiles[tile].mirror_s)
|
|
mode_s = GR_TEXTURECLAMP_MIRROR_EXT;
|
|
else
|
|
mode_s = GR_TEXTURECLAMP_WRAP;
|
|
}
|
|
|
|
if ((rdp.tiles[tile].clamp_t || rdp.tiles[tile].mask_t == 0) &&
|
|
rdp.tiles[tile].lr_t-rdp.tiles[tile].ul_t < 256)
|
|
mode_t = GR_TEXTURECLAMP_CLAMP;
|
|
else
|
|
{
|
|
if (rdp.tiles[tile].mirror_t)
|
|
mode_t = GR_TEXTURECLAMP_MIRROR_EXT;
|
|
else
|
|
mode_t = GR_TEXTURECLAMP_WRAP;
|
|
}
|
|
|
|
grTexClampMode (tmu,
|
|
mode_s,
|
|
mode_t);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fullscreen)
|
|
{
|
|
// Z buffer
|
|
if (rdp.update & UPDATE_ZBUF_ENABLED)
|
|
{
|
|
// already logged above
|
|
rdp.update ^= UPDATE_ZBUF_ENABLED;
|
|
|
|
if (rdp.flags & ZBUF_DECAL)
|
|
{
|
|
grDepthBiasLevel (0x00);
|
|
grDepthMask(FXFALSE);
|
|
if ((rdp.flags & ZBUF_ENABLED) && (rdp.flags & ZBUF_COMPARE))
|
|
grDepthBufferFunction (GR_CMP_LESS);
|
|
else
|
|
grDepthBufferFunction (GR_CMP_ALWAYS);
|
|
}
|
|
else
|
|
{
|
|
grDepthBiasLevel (0x20);
|
|
if (rdp.flags & ZBUF_ENABLED)
|
|
{
|
|
if (rdp.flags & ZBUF_COMPARE)
|
|
grDepthBufferFunction (GR_CMP_LESS);
|
|
else
|
|
grDepthBufferFunction (GR_CMP_ALWAYS);
|
|
|
|
if (rdp.flags & ZBUF_UPDATE)
|
|
grDepthMask (FXTRUE);
|
|
else
|
|
grDepthMask (FXFALSE);
|
|
}
|
|
else
|
|
{
|
|
grDepthBufferFunction (GR_CMP_ALWAYS);
|
|
grDepthMask (FXFALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Alpha compare
|
|
if (rdp.update & UPDATE_ALPHA_COMPARE)
|
|
{
|
|
// already logged above
|
|
rdp.update ^= UPDATE_ALPHA_COMPARE;
|
|
|
|
if (rdp.flags & ALPHA_COMPARE)
|
|
{
|
|
grAlphaTestFunction (GR_CMP_GEQUAL);
|
|
grAlphaTestReferenceValue (/*(BYTE)(rdp.real_fill_color & 0xFF)*/0xFF);
|
|
}
|
|
else
|
|
{
|
|
if (rdp.acmp == 1)
|
|
{
|
|
grAlphaTestFunction (GR_CMP_GEQUAL);
|
|
grAlphaTestReferenceValue ((BYTE)(rdp.real_blend_color&0xFF));
|
|
}
|
|
else
|
|
{
|
|
grAlphaTestFunction (GR_CMP_ALWAYS);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cull mode (leave this in for z-clipped triangles)
|
|
if (rdp.update & UPDATE_CULL_MODE)
|
|
{
|
|
rdp.update ^= UPDATE_CULL_MODE;
|
|
DWORD mode = (rdp.flags & CULLMASK) >> CULLSHIFT;
|
|
FRDP (" |- cull_mode - mode: %s\n", str_cull[mode]);
|
|
switch (mode)
|
|
{
|
|
case 0: // cull none
|
|
case 3: // cull both
|
|
grCullMode(GR_CULL_DISABLE);
|
|
break;
|
|
case 1: // cull front
|
|
grCullMode(GR_CULL_POSITIVE);
|
|
break;
|
|
case 2: // cull back
|
|
grCullMode (GR_CULL_NEGATIVE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (rdp.update & UPDATE_VIEWPORT)
|
|
{
|
|
rdp.update ^= UPDATE_VIEWPORT;
|
|
|
|
DWORD min_x = (DWORD)max(rdp.view_trans[0] - rdp.view_scale[0], 0);
|
|
DWORD min_y = (DWORD)max(rdp.view_trans[1] - rdp.view_scale[1], 0);
|
|
DWORD max_x = (DWORD)min(rdp.view_trans[0] + rdp.view_scale[0], settings.res_x);
|
|
DWORD max_y = (DWORD)min(rdp.view_trans[1] + rdp.view_scale[1], settings.res_y);
|
|
FRDP (" |- viewport - (%d, %d, %d, %d)\n", min_x, min_y, max_x, max_y);
|
|
grClipWindow (min_x, min_y, max_x, max_y);
|
|
}
|
|
}
|
|
|
|
RDP (" + update end\n");
|
|
}
|
|
|
|
//
|
|
// TexCache - cache textures
|
|
//
|
|
|
|
BYTE texture[256*256*4]; // temporary texture
|
|
|
|
__inline DWORD segoffset (DWORD so)
|
|
{
|
|
return (rdp.segment[(so>>24)&0x0f] + (so&0x00ffffff));
|
|
}
|
|
|
|
void TexCache (int tmu, int tileoff)
|
|
{
|
|
int i=0;
|
|
DWORD x, y, lod, aspect;
|
|
DWORD eppl; // extra pixels per line
|
|
DWORD col, intensity, col2, a;
|
|
BYTE *btptr;
|
|
WORD *wtptr;
|
|
DWORD *dtptr;
|
|
CACHE_LUT *cache;
|
|
int rx, ry;
|
|
|
|
int td = rdp.cur_tile + tileoff;
|
|
|
|
//if (settings.wireframe)
|
|
// return;
|
|
|
|
DWORD addr = segoffset(rdp.timg[rdp.tiles[td].t_mem].addr) & 0x3FFFFF;
|
|
|
|
DWORD bpl; // bytes per line
|
|
|
|
// Get width and height
|
|
int mask_width = (rdp.tiles[td].mask_s)?(1 << rdp.tiles[td].mask_s):(rdp.tiles[td].lr_s-rdp.tiles[td].ul_s+1);
|
|
int mask_height = (rdp.tiles[td].mask_t)?(1 << rdp.tiles[td].mask_t):(rdp.tiles[td].lr_t-rdp.tiles[td].ul_t+1);
|
|
|
|
int tile_width = rdp.tiles[td].lr_s - rdp.tiles[td].ul_s + 1;
|
|
int tile_height = rdp.tiles[td].lr_t - rdp.tiles[td].ul_t + 1;
|
|
|
|
if (rdp.tiles[td].lr_s - rdp.tiles[td].ul_s >= 256)
|
|
rdp.tiles[td].width = mask_width;
|
|
else
|
|
rdp.tiles[td].width = max(tile_width, mask_width);
|
|
if (rdp.tiles[td].lr_t - rdp.tiles[td].ul_t >= 256)
|
|
rdp.tiles[td].height = mask_height;
|
|
else
|
|
rdp.tiles[td].height = max(tile_height, mask_height);
|
|
|
|
// Get bytes per line
|
|
if (rdp.timg[rdp.tiles[td].t_mem].set_by)
|
|
{
|
|
if (rdp.tiles[td].size)
|
|
bpl = rdp.timg[rdp.tiles[td].t_mem].width << (rdp.tiles[td].size - 1);
|
|
else
|
|
bpl = rdp.timg[rdp.tiles[td].t_mem].width;
|
|
}
|
|
else
|
|
{
|
|
if (rdp.timg[rdp.tiles[td].t_mem].dxt == 0)
|
|
bpl = rdp.tiles[td].line << 3;
|
|
else
|
|
bpl = rdp.timg[rdp.tiles[td].t_mem].dxt << 3;
|
|
|
|
if (rdp.tiles[td].size == 3)
|
|
bpl = rdp.tiles[td].line << 4;
|
|
}
|
|
|
|
if (rdp.tiles[td].width <= 0 ||
|
|
rdp.tiles[td].height <= 0 ||
|
|
rdp.tiles[td].width > 640 ||
|
|
rdp.tiles[td].height > 480 ||
|
|
bpl >= 4000 ||
|
|
rdp.tiles[td].size < 0 ||
|
|
rdp.tiles[td].size > 3)
|
|
{
|
|
RDP (" | |- ! TexCache disapproved\n");
|
|
return;
|
|
}
|
|
|
|
RDP (" | |-+ TexCache approved:\n");
|
|
FRDP (" | | |- addr: %08lx\n", addr);
|
|
FRDP (" | | |- bpl: %d\n", bpl);
|
|
FRDP (" | | |- width: %d\n", rdp.tiles[td].width);
|
|
FRDP (" | | +- height: %d\n", rdp.tiles[td].height);
|
|
RDP (" | |- Calculating CRC... ");
|
|
|
|
DWORD crc = 0;
|
|
|
|
// Do CRC check
|
|
DWORD off = addr;
|
|
if (rdp.tiles[td].size)
|
|
off += rdp.tiles[7].t_ul_t * bpl + (rdp.tiles[7].t_ul_s << (rdp.tiles[td].size-1));
|
|
else
|
|
off += rdp.tiles[7].t_ul_t * bpl + (rdp.tiles[7].t_ul_s >> 1);
|
|
int count;
|
|
DWORD wid;
|
|
if (rdp.tiles[td].size)
|
|
wid = (tile_width << (rdp.tiles[td].size-1)) >> 2;
|
|
else
|
|
wid = tile_width >> 3;
|
|
for (ry=0; ry<tile_height; ry++)
|
|
{
|
|
dtptr = ((DWORD*)gfx.RDRAM) + ((off+ry*bpl) >> 2);
|
|
count = wid;
|
|
while (count > 0)
|
|
{
|
|
crc += *(dtptr++);
|
|
crc += *(dtptr++);
|
|
crc += *(dtptr++);
|
|
crc += *(dtptr++);
|
|
count -= 4;
|
|
}
|
|
}
|
|
crc ^= rdp.timg[rdp.tiles[td].t_mem & 0x1FF].addr;
|
|
/*crc += (rdp.tiles[td].lr_s<<4) + (rdp.tiles[td].lr_t<<12);
|
|
if (rdp.timg[rdp.tiles[td].t_mem].set_by == 1)
|
|
crc += rdp.tiles[td].ul_s + (rdp.tiles[td].ul_t<<8);*/
|
|
crc += (rdp.tiles[7].t_lr_s<<4) + (rdp.tiles[7].t_lr_t<<12)
|
|
+ rdp.tiles[7].t_ul_s + (rdp.tiles[7].t_ul_t<<8);
|
|
|
|
RDP ("Done.\n");
|
|
|
|
DWORD pal_crc = 0;
|
|
if (rdp.tiles[td].format == 2)
|
|
{
|
|
if (rdp.tiles[td].size == 0)
|
|
pal_crc = rdp.pal_8_crc[rdp.tiles[td].palette];
|
|
else
|
|
pal_crc = rdp.pal_8_crc[16];
|
|
}
|
|
|
|
// Check wrapping/mirroring
|
|
DWORD flags = (rdp.tiles[td].mirror_s << 1) | rdp.tiles[td].mirror_t |
|
|
(rdp.render_mode & 0x00002000) |
|
|
(rdp.tiles[td].mask_s << 16) | (rdp.tiles[td].mask_t << 20);
|
|
|
|
RDP (" | |- Checking cache... ");
|
|
|
|
// Check if this texture was already cached
|
|
for (i=0; i<rdp.n_cached[tmu]; i++)
|
|
{
|
|
cache = &rdp.cache[tmu][i];
|
|
if (crc == cache->crc &&
|
|
rdp.tiles[td].width == cache->width &&
|
|
rdp.tiles[td].height == cache->height &&
|
|
rdp.tiles[td].format == cache->format &&
|
|
rdp.tiles[td].size == cache->size &&
|
|
rdp.tiles[td].palette == cache->palette &&
|
|
bpl == cache->bpl &&
|
|
pal_crc == cache->pal_crc &&
|
|
flags == cache->flags)
|
|
{
|
|
RDP ("Texture found in cache, exiting.\n");
|
|
if (fullscreen)
|
|
{
|
|
rdp.cur_cache_n[tmu] = i;
|
|
rdp.cur_cache[tmu] = cache;
|
|
rdp.cur_cache[tmu]->last_used = frame_count;
|
|
grTexSource (tmu,
|
|
(grTexMinAddress(tmu) + cache->tmem_addr),
|
|
GR_MIPMAPLEVELMASK_BOTH,
|
|
&cache->t_info);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
RDP ("Texture not found, creating new.\n");
|
|
|
|
// Otherwise, we need to cache it:
|
|
|
|
// Clear the cache if it's full
|
|
if (rdp.n_cached[tmu] >= MAX_CACHE)
|
|
{
|
|
rdp.tmem_ptr[tmu] = offset_textures;
|
|
rdp.n_cached[tmu] = 0;
|
|
}
|
|
|
|
// Get this cache object
|
|
cache = &rdp.cache[tmu][rdp.n_cached[tmu]];
|
|
rdp.cur_cache[tmu] = cache;
|
|
rdp.cur_cache_n[tmu] = rdp.n_cached[tmu];
|
|
|
|
// Set the data
|
|
cache->dxt = rdp.timg[rdp.tiles[td].t_mem].dxt;
|
|
cache->line = rdp.tiles[td].line;
|
|
cache->wid = rdp.timg[rdp.tiles[td].t_mem].width;
|
|
|
|
cache->addr = addr;
|
|
cache->crc = crc;
|
|
cache->palette = rdp.tiles[td].palette;
|
|
cache->pal_crc = pal_crc;
|
|
cache->width = rdp.tiles[td].width;
|
|
cache->height = rdp.tiles[td].height;
|
|
cache->format = rdp.tiles[td].format;
|
|
cache->size = rdp.tiles[td].size;
|
|
cache->flags = flags;
|
|
cache->tmem_addr = rdp.tmem_ptr[tmu];
|
|
cache->bpl = bpl;
|
|
cache->set_by = rdp.timg[rdp.tiles[td].t_mem].set_by;
|
|
cache->swapped = rdp.timg[rdp.tiles[td].t_mem].swapped;
|
|
cache->texrecting = rdp.texrecting;
|
|
cache->last_used = frame_count;
|
|
cache->offset_s = 0;//rdp.tiles[7].t_ul_s;
|
|
cache->offset_t = 0;//rdp.tiles[7].t_ul_t;
|
|
off = ((rdp.tiles[td].size != 0) ?
|
|
(rdp.timg[rdp.tiles[td].t_mem & 0x1FF].addr >> (rdp.tiles[td].size-1)) :
|
|
rdp.timg[rdp.tiles[td].t_mem & 0x1FF].addr);
|
|
if (rdp.tiles[td].size)
|
|
{
|
|
off += rdp.tiles[7].t_ul_t * (bpl >> (rdp.tiles[td].size-1)) +
|
|
rdp.tiles[7].t_ul_s;
|
|
}
|
|
else
|
|
{
|
|
// 4-bit uses byte pointer, so don't shift bpl
|
|
off += rdp.tiles[7].t_ul_t * bpl +
|
|
rdp.tiles[7].t_ul_s;
|
|
}
|
|
rdp.n_cached[tmu] ++;
|
|
|
|
/*if (rdp.texrecting && cache->width > 256)
|
|
{
|
|
cache->warpheight = cache->height;
|
|
cache->width /= 2;
|
|
cache->height *= 2;
|
|
cache->warpx = 2;
|
|
} else
|
|
{
|
|
cache->warpx = 1;
|
|
cache->warpheight = 0;
|
|
}*/
|
|
|
|
// temporary
|
|
cache->t_info.format = GR_TEXFMT_ARGB_1555;
|
|
|
|
// Calculate wrapping mask
|
|
DWORD wrap_mask_s, wrap_mask_t, mirror_bit_s, mirror_bit_t, mask_mask_t, mask_mask_s;
|
|
if (rdp.tiles[td].mask_s)
|
|
{
|
|
wrap_mask_s = 0xFFFF >> (16 - rdp.tiles[td].mask_s);
|
|
mirror_bit_s = 1 << rdp.tiles[td].mask_s;
|
|
mask_mask_s = 0xFFFF << rdp.tiles[td].mask_s;
|
|
}
|
|
else
|
|
{
|
|
wrap_mask_s = 0xFFFF;
|
|
mirror_bit_s = 0;
|
|
mask_mask_s = 0xFFFF;
|
|
}
|
|
|
|
if (rdp.tiles[td].mask_t)
|
|
{
|
|
wrap_mask_t = 0xFFFF >> (16 - rdp.tiles[td].mask_t);
|
|
mirror_bit_t = 1 << rdp.tiles[td].mask_t;
|
|
mask_mask_t = 0xFFFF << rdp.tiles[td].mask_t;
|
|
}
|
|
else
|
|
{
|
|
wrap_mask_t = 0xFFFF;
|
|
mirror_bit_t = 0;
|
|
mask_mask_s = 0xFFFF;
|
|
}
|
|
|
|
//LOG ("w: " << cache->width << ", h: " << cache->height << "\n");
|
|
|
|
// Calculate lod and aspect
|
|
DWORD size_x = cache->width;
|
|
DWORD size_y = cache->height;
|
|
|
|
// make size_x and size_y both powers of two
|
|
if (size_x > 256) size_x = 256;
|
|
if (size_y > 256) size_y = 256;
|
|
|
|
int shift;
|
|
for (shift=0; (1<<shift) < (int)size_x; shift++);
|
|
size_x = 1 << shift;
|
|
for (shift=0; (1<<shift) < (int)size_y; shift++);
|
|
size_y = 1 << shift;
|
|
|
|
// Calculate the maximum size
|
|
int size_max = max (size_x, size_y);
|
|
DWORD real_x=size_max, real_y=size_max;
|
|
switch (size_max)
|
|
{
|
|
case 1:
|
|
lod = GR_LOD_LOG2_1;
|
|
cache->scale = 256.0f;
|
|
break;
|
|
case 2:
|
|
lod = GR_LOD_LOG2_2;
|
|
cache->scale = 128.0f;
|
|
break;
|
|
case 4:
|
|
lod = GR_LOD_LOG2_4;
|
|
cache->scale = 64.0f;
|
|
break;
|
|
case 8:
|
|
lod = GR_LOD_LOG2_8;
|
|
cache->scale = 32.0f;
|
|
break;
|
|
case 16:
|
|
lod = GR_LOD_LOG2_16;
|
|
cache->scale = 16.0f;
|
|
break;
|
|
case 32:
|
|
lod = GR_LOD_LOG2_32;
|
|
cache->scale = 8.0f;
|
|
break;
|
|
case 64:
|
|
lod = GR_LOD_LOG2_64;
|
|
cache->scale = 4.0f;
|
|
break;
|
|
case 128:
|
|
lod = GR_LOD_LOG2_128;
|
|
cache->scale = 2.0f;
|
|
break;
|
|
//case 256:
|
|
default:
|
|
lod = GR_LOD_LOG2_256;
|
|
cache->scale = 1.0f;
|
|
break;
|
|
|
|
// No default here, can't be a non-power of two, see above
|
|
}
|
|
|
|
// Calculate the aspect ratio
|
|
if (size_x >= size_y)
|
|
{
|
|
int ratio = size_x / size_y;
|
|
switch (ratio)
|
|
{
|
|
case 1:
|
|
aspect = GR_ASPECT_LOG2_1x1;
|
|
cache->scale_x = 1.0f;
|
|
cache->scale_y = 1.0f;
|
|
break;
|
|
case 2:
|
|
aspect = GR_ASPECT_LOG2_2x1;
|
|
cache->scale_x = 1.0f;
|
|
cache->scale_y = 0.5f;
|
|
real_y >>= 1;
|
|
break;
|
|
case 4:
|
|
aspect = GR_ASPECT_LOG2_4x1;
|
|
cache->scale_x = 1.0f;
|
|
cache->scale_y = 0.25f;
|
|
real_y >>= 2;
|
|
break;
|
|
//case 8:
|
|
default:
|
|
aspect = GR_ASPECT_LOG2_8x1;
|
|
cache->scale_x = 1.0f;
|
|
cache->scale_y = 0.125f;
|
|
real_y >>= 3;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int ratio = size_y / size_x;
|
|
switch (ratio)
|
|
{
|
|
case 2:
|
|
aspect = GR_ASPECT_LOG2_1x2;
|
|
cache->scale_x = 0.5f;
|
|
cache->scale_y = 1.0f;
|
|
real_x >>= 1;
|
|
break;
|
|
case 4:
|
|
aspect = GR_ASPECT_LOG2_1x4;
|
|
cache->scale_x = 0.25f;
|
|
cache->scale_y = 1.0f;
|
|
real_x >>= 2;
|
|
break;
|
|
//case 8:
|
|
default:
|
|
aspect = GR_ASPECT_LOG2_1x8;
|
|
cache->scale_x = 0.125f;
|
|
cache->scale_y = 1.0f;
|
|
real_x >>= 3;
|
|
break;
|
|
}
|
|
}
|
|
|
|
DWORD min_x = min (real_x, cache->width);
|
|
DWORD min_y = min (real_y, cache->height);
|
|
|
|
// Set the extra pixels per line (if the texture is not log2 like mario64 face background)
|
|
eppl = real_x - min_x;
|
|
if (real_x != cache->width || real_y != cache->height)
|
|
{
|
|
//if (real_x > min_x)
|
|
// eppl = real_x - min_x;
|
|
cache->scale_x *= (float)cache->width / (float)real_x;
|
|
cache->scale_y *= (float)cache->height / (float)real_y;
|
|
}
|
|
|
|
RDP (" | |- Texture loading... ");
|
|
|
|
// Convert this texture
|
|
switch (cache->size)
|
|
{
|
|
case 0: // 4bit
|
|
switch (cache->format)
|
|
{
|
|
case 0: // RGBA
|
|
RDP_E ("** 4-bit RGBA\n");
|
|
break;
|
|
case 1: // YUV
|
|
RDP_E ("** 4-bit YUV\n");
|
|
break;
|
|
case 2: // CI
|
|
cache->t_info.format = GR_TEXFMT_ARGB_1555;
|
|
wtptr = (WORD*)texture;
|
|
if (min_x & 1) eppl ++; // all 4-bit textures in case of rounding up
|
|
for (y=0; y<min_y; y++)
|
|
{
|
|
for (x=0; x<min_x>>1; x++)
|
|
{
|
|
rx = x << 1;
|
|
ry = y;
|
|
if (rdp.tiles[td].mirror_s) rx = (rx&mirror_bit_s) +
|
|
((rx&mirror_bit_s)?-1:1) * (rx&wrap_mask_s) -
|
|
((rx&mirror_bit_s)?1:0);
|
|
else rx &= wrap_mask_s;
|
|
if (rdp.tiles[td].mirror_t) ry = (ry&mirror_bit_t) +
|
|
((ry&mirror_bit_t)?-1:1) * (ry&wrap_mask_t) -
|
|
((ry&mirror_bit_t)?1:0);
|
|
else
|
|
ry &= wrap_mask_t;
|
|
|
|
a = ((off+(rx>>1)+ry*bpl)^3);
|
|
if (cache->swapped && (y & 1)) a ^= 4;
|
|
col = ((BYTE*)gfx.RDRAM)[a&BMASK];
|
|
if (rdp.tiles[td].mirror_s && ((x<<1) & mirror_bit_s))
|
|
col2 = rdp.pal_8[(((rdp.tiles[td].palette<<4) + (col & 0x0F))^1)&0xFF];
|
|
else
|
|
col2 = rdp.pal_8[(((rdp.tiles[td].palette<<4) + (col >> 4))^1)&0xFF];
|
|
*(wtptr++) = (WORD)(((col2&0xFFFE)>>1) | ((col2&0x0001) << 15));
|
|
if (rdp.tiles[td].mirror_s && ((x<<1) & mirror_bit_s))
|
|
col2 = rdp.pal_8[(((rdp.tiles[td].palette<<4) + (col >> 4))^1)&0xFF];
|
|
else
|
|
col2 = rdp.pal_8[(((rdp.tiles[td].palette<<4) + (col & 0x0F))^1)&0xFF];
|
|
col = (WORD)(((col2&0xFFFE)>>1) | ((col2&0x0001) << 15));
|
|
*(wtptr++) = (WORD)col;
|
|
}
|
|
|
|
// fill the rest of the line
|
|
for (; x<real_x>>1; x++)
|
|
{
|
|
*(wtptr++) = (WORD)col;
|
|
*(wtptr++) = (WORD)col;
|
|
}
|
|
//wtptr += eppl;
|
|
}
|
|
for (; y<real_y; y++)
|
|
{
|
|
memcpy (wtptr, wtptr-real_x, real_x<<1);
|
|
wtptr += real_x;
|
|
}
|
|
break;
|
|
case 3: // IA
|
|
cache->t_info.format = GR_TEXFMT_ALPHA_INTENSITY_44;
|
|
btptr = (BYTE*)texture;
|
|
if (min_x & 1) eppl ++; // all 4-bit textures in case of rounding up
|
|
for (y=0; y<min_y; y++)
|
|
{
|
|
for (x=0; x<min_x>>1; x++)
|
|
{
|
|
rx = x << 1;
|
|
ry = y;
|
|
if (rdp.tiles[td].mirror_s) rx = (rx&mirror_bit_s) +
|
|
((rx&mirror_bit_s)?-1:1) * (rx&wrap_mask_s) -
|
|
((rx&mirror_bit_s)?1:0);
|
|
else rx &= wrap_mask_s;
|
|
if (rdp.tiles[td].mirror_t) ry = (ry&mirror_bit_t) +
|
|
((ry&mirror_bit_t)?-1:1) * (ry&wrap_mask_t) -
|
|
((ry&mirror_bit_t)?1:0);
|
|
else
|
|
ry &= wrap_mask_t;
|
|
|
|
a = ((off+(rx>>1)+ry*bpl)^3);
|
|
if (cache->swapped && (y & 1)) a ^= 4;
|
|
col = ((BYTE*)gfx.RDRAM)[a&BMASK];
|
|
if (rdp.tiles[td].mirror_s && ((x<<1) & mirror_bit_s))
|
|
*(btptr++) = (BYTE)(((col & 0x08)?0xF0:0x00) |
|
|
((col & 0x07) << 1) | ((col & 0x04) >> 2));
|
|
else
|
|
*(btptr++) = (BYTE)(((col & 0x10)?0xF0:0x00) |
|
|
((col & 0xE0) >> 4) | ((col & 0x80) >> 7));
|
|
if (rdp.tiles[td].mirror_s && ((x<<1) & mirror_bit_s))
|
|
col = (BYTE)(((col & 0x80)?0xF0:0x00) |
|
|
((col & 0x70) >> 3) | ((col & 0x40) >> 5));
|
|
else
|
|
col = (BYTE)(((col & 0x01)?0xF0:0x00) |
|
|
((col & 0x0E)) | ((col & 0x08) >> 3));
|
|
*(btptr++) = (BYTE)col;
|
|
}
|
|
|
|
// fill the rest of the line
|
|
for (; x<real_x>>1; x++)
|
|
{
|
|
*(btptr++) = (BYTE)col;
|
|
*(btptr++) = (BYTE)col;
|
|
}
|
|
//btptr += eppl;
|
|
}
|
|
for (; y<real_y; y++)
|
|
{
|
|
memcpy (btptr, btptr-real_x, real_x);
|
|
btptr += real_x;
|
|
}
|
|
break;
|
|
case 4: // I
|
|
cache->t_info.format = GR_TEXFMT_ALPHA_INTENSITY_44;
|
|
btptr = (BYTE*)texture;
|
|
if (min_x & 1) eppl ++; // all 4-bit textures in case of rounding up
|
|
for (y=0; y<min_y; y++)
|
|
{
|
|
for (x=0; x<min_x>>1; x++)
|
|
{
|
|
rx = x << 1;
|
|
ry = y;
|
|
if (rdp.tiles[td].mirror_s) rx = (rx&mirror_bit_s) +
|
|
((rx&mirror_bit_s)?-1:1) * (rx&wrap_mask_s) -
|
|
((rx&mirror_bit_s)?1:0);
|
|
else rx &= wrap_mask_s;
|
|
if (rdp.tiles[td].mirror_t) ry = (ry&mirror_bit_t) +
|
|
((ry&mirror_bit_t)?-1:1) * (ry&wrap_mask_t) -
|
|
((ry&mirror_bit_t)?1:0);
|
|
else
|
|
ry &= wrap_mask_t;
|
|
|
|
a = ((off+(rx>>1)+ry*bpl)^3);
|
|
if (cache->swapped && (y & 1)) a ^= 4;
|
|
col = ((BYTE*)gfx.RDRAM)[a&BMASK];
|
|
|
|
if (rdp.tiles[td].mirror_s && ((x<<1) & mirror_bit_s))
|
|
*(btptr++) = (BYTE)((col << 4) | (col & 0x0F));
|
|
else
|
|
*(btptr++) = (BYTE)((col & 0xF0) | (col >> 4));
|
|
if (rdp.tiles[td].mirror_s && ((x<<1) & mirror_bit_s))
|
|
col = (BYTE)((col & 0xF0) | (col >> 4));
|
|
else
|
|
col = (BYTE)((col << 4) | (col & 0x0F));
|
|
*(btptr++) = (BYTE)col;
|
|
}
|
|
|
|
// fill the rest of the line
|
|
for (; x<real_x>>1; x++)
|
|
{
|
|
*(btptr++) = (BYTE)col;
|
|
*(btptr++) = (BYTE)col;
|
|
}
|
|
//btptr += eppl;
|
|
}
|
|
for (; y<real_y; y++)
|
|
{
|
|
memcpy (btptr, btptr-real_x, real_x);
|
|
btptr += real_x;
|
|
}
|
|
break;
|
|
default:
|
|
RDP_E ("** 4-bit unknown\n");
|
|
}
|
|
break;
|
|
case 1: // 8bit
|
|
switch (cache->format)
|
|
{
|
|
case 0: // RGBA
|
|
cache->t_info.format = GR_TEXFMT_ARGB_1555;
|
|
wtptr = (WORD*)texture;
|
|
for (y=0; y<min_y; y++)
|
|
{
|
|
for (x=0; x<min_x; x++)
|
|
{
|
|
rx = x;
|
|
ry = y;
|
|
if (rdp.tiles[td].mirror_s) rx = (rx&mirror_bit_s) +
|
|
((rx&mirror_bit_s)?-1:1) * (rx&wrap_mask_s) -
|
|
((rx&mirror_bit_s)?1:0);
|
|
else rx &= wrap_mask_s;
|
|
if (rdp.tiles[td].mirror_t) ry = (ry&mirror_bit_t) +
|
|
((ry&mirror_bit_t)?-1:1) * (ry&wrap_mask_t) -
|
|
((ry&mirror_bit_t)?1:0);
|
|
else
|
|
ry &= wrap_mask_t;
|
|
|
|
a = ((off+rx+ry*bpl)^3);
|
|
if (cache->swapped && (y & 1)) a ^= 4;
|
|
col = rdp.pal_8[((BYTE*)gfx.RDRAM)[a&BMASK]^1];
|
|
col = (((col&0xFFFE) >> 1) | ((col&0x0001) << 15));
|
|
*(wtptr++) = (WORD)col;
|
|
}
|
|
|
|
// fill the rest of the line
|
|
for (; x<real_x; x++)
|
|
*(wtptr++) = (WORD)col;
|
|
//wtptr += eppl;
|
|
}
|
|
for (; y<real_y; y++)
|
|
{
|
|
memcpy (wtptr, wtptr-real_x, real_x*2);
|
|
wtptr += real_x;
|
|
}
|
|
break;
|
|
case 1: // YUV
|
|
RDP_E ("** 8-bit YUV\n");
|
|
break;
|
|
case 2: // CI
|
|
cache->t_info.format = GR_TEXFMT_ARGB_1555;
|
|
wtptr = (WORD*)texture;
|
|
for (y=0; y<min_y; y++)
|
|
{
|
|
for (x=0; x<min_x; x++)
|
|
{
|
|
rx = x;
|
|
ry = y;
|
|
if (rdp.tiles[td].mirror_s) rx = (rx&mirror_bit_s) +
|
|
((rx&mirror_bit_s)?-1:1) * (rx&wrap_mask_s) -
|
|
((rx&mirror_bit_s)?1:0);
|
|
else rx &= wrap_mask_s;
|
|
if (rdp.tiles[td].mirror_t) ry = (ry&mirror_bit_t) +
|
|
((ry&mirror_bit_t)?-1:1) * (ry&wrap_mask_t) -
|
|
((ry&mirror_bit_t)?1:0);
|
|
else
|
|
ry &= wrap_mask_t;
|
|
|
|
a = ((off+rx+ry*bpl)^3);
|
|
if (cache->swapped && (y & 1)) a ^= 4;
|
|
col = rdp.pal_8[((BYTE*)gfx.RDRAM)[a&BMASK]^1];
|
|
col = (WORD)(((col&0xFFFE) >> 1) | ((col&0x0001) << 15));
|
|
*(wtptr++) = (WORD)col;
|
|
}
|
|
|
|
// fill the rest of the line
|
|
for (; x<real_x; x++)
|
|
*(wtptr++) = (WORD)col;
|
|
//wtptr += eppl;
|
|
}
|
|
for (; y<real_y; y++)
|
|
{
|
|
memcpy (wtptr, wtptr-real_x, real_x*2);
|
|
wtptr += real_x;
|
|
}
|
|
break;
|
|
case 3: // IA
|
|
cache->t_info.format = GR_TEXFMT_ALPHA_INTENSITY_44;
|
|
btptr = (BYTE*)texture;
|
|
for (y=0; y<min_y; y++)
|
|
{
|
|
for (x=0; x<min_x; x++)
|
|
{
|
|
rx = x;
|
|
ry = y;
|
|
if (rdp.tiles[td].mirror_s) rx = (rx&mirror_bit_s) +
|
|
((rx&mirror_bit_s)?-1:1) * (rx&wrap_mask_s) -
|
|
((rx&mirror_bit_s)?1:0);
|
|
else rx &= wrap_mask_s;
|
|
if (rdp.tiles[td].mirror_t) ry = (ry&mirror_bit_t) +
|
|
((ry&mirror_bit_t)?-1:1) * (ry&wrap_mask_t) -
|
|
((ry&mirror_bit_t)?1:0);
|
|
else
|
|
ry &= wrap_mask_t;
|
|
|
|
a = ((off+rx+ry*bpl)^3);
|
|
if (cache->swapped && (y & 1)) a ^= 4;
|
|
col = ((BYTE*)gfx.RDRAM)[a&BMASK];
|
|
col = (BYTE)(col >> 4) | (BYTE)(col << 4);
|
|
*(btptr++) = (BYTE)col;
|
|
}
|
|
// fill the rest of the line
|
|
for (; x<real_x; x++)
|
|
*(btptr++) = (BYTE)col;
|
|
//btptr += eppl;
|
|
}
|
|
for (; y<real_y; y++)
|
|
{
|
|
memcpy (btptr, btptr-real_x, real_x);
|
|
btptr += real_x;
|
|
}
|
|
break;
|
|
case 4: // I
|
|
cache->t_info.format = GR_TEXFMT_ALPHA_8;
|
|
btptr = (BYTE*)texture;
|
|
for (y=0; y<min_y; y++)
|
|
{
|
|
for (x=0; x<min_x; x++)
|
|
{
|
|
rx = x;
|
|
ry = y;
|
|
if (rdp.tiles[td].mirror_s) rx = (rx&mirror_bit_s) +
|
|
((rx&mirror_bit_s)?-1:1) * (rx&wrap_mask_s) -
|
|
((rx&mirror_bit_s)?1:0);
|
|
else rx &= wrap_mask_s;
|
|
if (rdp.tiles[td].mirror_t) ry = (ry&mirror_bit_t) +
|
|
((ry&mirror_bit_t)?-1:1) * (ry&wrap_mask_t) -
|
|
((ry&mirror_bit_t)?1:0);
|
|
else
|
|
ry &= wrap_mask_t;
|
|
|
|
a = ((off+rx+ry*bpl)^3);
|
|
if (cache->swapped && (y & 1)) a ^= 4;
|
|
col = ((BYTE*)gfx.RDRAM)[a&BMASK];
|
|
*(btptr++) = (BYTE)col;
|
|
}
|
|
// fill the rest of the line
|
|
for (; x<real_x; x++)
|
|
*(btptr++) = (BYTE)col;
|
|
//btptr += eppl;
|
|
}
|
|
for (; y<real_y; y++)
|
|
{
|
|
memcpy (btptr, btptr-real_x, real_x);
|
|
btptr += real_x;
|
|
}
|
|
break;
|
|
default:
|
|
RDP_E ("** 8-bit unknown\n");
|
|
}
|
|
break;
|
|
case 2: // 16bit
|
|
switch (cache->format)
|
|
{
|
|
case 0: // RGBA
|
|
cache->t_info.format = GR_TEXFMT_ARGB_1555;
|
|
wtptr = (WORD*)texture;
|
|
for (y=0; y<min_y; y++)
|
|
{
|
|
for (x=0; x<min_x; x++)
|
|
{
|
|
rx = x;
|
|
ry = y;
|
|
if (rdp.tiles[td].mirror_s) rx = (rx&mirror_bit_s) +
|
|
((rx&mirror_bit_s)?-1:1) * (rx&wrap_mask_s) -
|
|
((rx&mirror_bit_s)?1:0);
|
|
else rx &= wrap_mask_s;
|
|
if (rdp.tiles[td].mirror_t) ry = (ry&mirror_bit_t) +
|
|
((ry&mirror_bit_t)?-1:1) * (ry&wrap_mask_t) -
|
|
((ry&mirror_bit_t)?1:0);
|
|
else
|
|
ry &= wrap_mask_t;
|
|
|
|
a = ((off+rx+ry*(bpl>>1))^1);
|
|
if (cache->swapped && (y & 1)) a ^= 2;
|
|
col = ((WORD*)gfx.RDRAM)[a&WMASK];
|
|
col = (WORD)(((col & 0xFFFE) >> 1) | ((col & 1) << 15));
|
|
*(wtptr++) = (WORD)col;
|
|
}
|
|
// fill the rest of the line
|
|
for (; x<real_x; x++)
|
|
*(wtptr++) = (WORD)col;
|
|
//wtptr += eppl;
|
|
}
|
|
for (; y<real_y; y++)
|
|
{
|
|
memcpy (wtptr, wtptr-real_x, real_x*2);
|
|
wtptr += real_x;
|
|
}
|
|
break;
|
|
case 1: // YUV
|
|
RDP_E ("** 16-bit YUV\n");
|
|
break;
|
|
case 2: // CI
|
|
RDP_E ("** 16-bit CI\n");
|
|
break;
|
|
case 3: // IA
|
|
cache->t_info.format = GR_TEXFMT_ARGB_4444;
|
|
wtptr = (WORD*)texture;
|
|
for (y=0; y<min_y; y++)
|
|
{
|
|
for (x=0; x<min_x; x++)
|
|
{
|
|
rx = x;
|
|
ry = y;
|
|
if (rdp.tiles[td].mirror_s) rx = (rx&mirror_bit_s) +
|
|
((rx&mirror_bit_s)?-1:1) * (rx&wrap_mask_s) -
|
|
((rx&mirror_bit_s)?1:0);
|
|
else rx &= wrap_mask_s;
|
|
if (rdp.tiles[td].mirror_t) ry = (ry&mirror_bit_t) +
|
|
((ry&mirror_bit_t)?-1:1) * (ry&wrap_mask_t) -
|
|
((ry&mirror_bit_t)?1:0);
|
|
else
|
|
ry &= wrap_mask_t;
|
|
|
|
a = ((off+rx+ry*(bpl>>1))^1);
|
|
if (cache->swapped && (y & 1)) a ^= 2;
|
|
col = ((WORD*)gfx.RDRAM)[a&WMASK];
|
|
intensity = col >> 12;
|
|
*(wtptr++) = (WORD)(intensity | (intensity << 4) | (intensity << 8) | ((col & 0xF0) << 8));
|
|
}
|
|
// fill the rest of the line
|
|
for (; x<real_x; x++)
|
|
*(wtptr++) = (WORD)col;
|
|
//wtptr += eppl;
|
|
}
|
|
for (; y<real_y; y++)
|
|
{
|
|
memcpy (wtptr, wtptr-real_x, real_x*2);
|
|
wtptr += real_x;
|
|
}
|
|
break;
|
|
case 4: // I
|
|
RDP_E ("** 16-bit I\n");
|
|
break;
|
|
default:
|
|
RDP_E ("** 16-bit unknown\n");
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 3: // 32bit
|
|
switch (cache->format)
|
|
{
|
|
case 0:
|
|
cache->t_info.format = GR_TEXFMT_ARGB_4444;
|
|
wtptr = (WORD*)texture;
|
|
for (y=0; y<min_y; y++)
|
|
{
|
|
for (x=0; x<min_x; x++)
|
|
{
|
|
rx = x;
|
|
ry = y;
|
|
if (rdp.tiles[td].mirror_s) rx = (rx&mirror_bit_s) +
|
|
((rx&mirror_bit_s)?-1:1) * (rx&wrap_mask_s) -
|
|
((rx&mirror_bit_s)?1:0);
|
|
else rx &= wrap_mask_s;
|
|
if (rdp.tiles[td].mirror_t) ry = (ry&mirror_bit_t) +
|
|
((ry&mirror_bit_t)?-1:1) * (ry&wrap_mask_t) -
|
|
((ry&mirror_bit_t)?1:0);
|
|
else
|
|
ry &= wrap_mask_t;
|
|
|
|
a = (off+rx+ry*(bpl>>2));
|
|
//if (cache->swapped && (y & 1)) a ^= 1;
|
|
col = ((DWORD*)gfx.RDRAM)[a&DMASK];
|
|
*(wtptr++) = (WORD)(((col & 0xF0000000) >> 20) |
|
|
((col & 0x00F00000) >> 16) |
|
|
((col & 0x0000F000) >> 12) |
|
|
((col & 0x000000F0) << 8));
|
|
}
|
|
// fill the rest of the line
|
|
for (; x<real_x; x++)
|
|
*(wtptr++) = (WORD)col;
|
|
//wtptr += eppl;
|
|
}
|
|
for (; y<real_y; y++)
|
|
{
|
|
memcpy (wtptr, wtptr-real_x, real_x*2);
|
|
wtptr += real_x;
|
|
}
|
|
break;
|
|
case 1:
|
|
RDP_E ("** 32-bit YUV\n");
|
|
break;
|
|
case 2:
|
|
RDP_E ("** 32-bit CI\n");
|
|
break;
|
|
case 3:
|
|
RDP_E ("** 32-bit IA\n");
|
|
break;
|
|
case 4:
|
|
RDP_E ("** 32-bit I\n");
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
RDP_E ("** Unknown texture size");
|
|
}
|
|
RDP ("Done.\n");
|
|
|
|
cache->realwidth = real_x;
|
|
cache->realheight = real_y;
|
|
cache->lod = lod;
|
|
cache->aspect = aspect;
|
|
|
|
//FRDP_E ("## TS: lod %d, aspect %d\n", lod, aspect);
|
|
|
|
if (fullscreen)
|
|
{
|
|
// Load the texture into texture memory
|
|
GrTexInfo *t_info = &cache->t_info;
|
|
t_info->data = texture;
|
|
//t_info->format = GR_TEXFMT_ARGB_1555;
|
|
t_info->smallLodLog2 = lod;
|
|
t_info->largeLodLog2 = lod;
|
|
t_info->aspectRatioLog2 = aspect;
|
|
|
|
DWORD texture_size = grTexTextureMemRequired (GR_MIPMAPLEVELMASK_BOTH, t_info);
|
|
|
|
// Check for 2mb boundary
|
|
if ((rdp.tmem_ptr[tmu] < TEXMEM_2MB_EDGE) && (rdp.tmem_ptr[tmu]+texture_size > TEXMEM_2MB_EDGE))
|
|
{
|
|
rdp.tmem_ptr[tmu] = TEXMEM_2MB_EDGE;
|
|
cache->tmem_addr = rdp.tmem_ptr[tmu];
|
|
}
|
|
|
|
// Check for end of memory (too many textures to fit, clear cache)
|
|
if (rdp.tmem_ptr[tmu]+texture_size >= grTexMaxAddress(tmu))
|
|
{
|
|
rdp.tmem_ptr[tmu] = offset_textures;
|
|
rdp.n_cached[tmu] = 0;
|
|
TexCache (tmu, tileoff);
|
|
return; // DON'T continue, update will have already done this
|
|
}
|
|
|
|
grTexDownloadMipMap (tmu,
|
|
grTexMinAddress(tmu) + rdp.tmem_ptr[tmu],
|
|
GR_MIPMAPLEVELMASK_BOTH,
|
|
t_info);
|
|
|
|
grTexSource (tmu,
|
|
grTexMinAddress(tmu) + rdp.tmem_ptr[tmu],
|
|
GR_MIPMAPLEVELMASK_BOTH,
|
|
t_info);
|
|
|
|
rdp.tmem_ptr[tmu] += texture_size;
|
|
}
|
|
|
|
RDP (" | + Texcache end\n");
|
|
} |