Path: blob/master/libmupen64plus/mupen64plus-video-glide64mk2/src/Glide64/DepthBufferRender.cpp
2 views
/*1* Glide64 - Glide video plugin for Nintendo 64 emulators.2* Copyright (c) 2002 Dave20013* Copyright (c) 2003-2009 Sergey 'Gonetz' Lipski4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA18*/1920//****************************************************************21//22// Glide64 - Glide Plugin for Nintendo 64 emulators23// Project started on December 29th, 200124//25// Authors:26// Dave2001, original author, founded the project in 2001, left it in 200227// Gugaman, joined the project in 2002, left it in 200228// Sergey 'Gonetz' Lipski, joined the project in 2002, main author since fall of 200229// Hiroshi 'KoolSmoky' Morii, joined the project in 200730//31//****************************************************************32//33// To modify Glide64:34// * 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.35// * 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.36//37//****************************************************************38//39// Software rendering into N64 depth buffer40// Idea and N64 depth value format by Orkin41// Polygon rasterization algorithm is taken from FATMAP2 engine by Mats Byggmastar, [email protected]42//43// Created by Gonetz, Dec 200444//45//****************************************************************4647#include "Gfx_1.3.h"48#include "rdp.h"49#include "DepthBufferRender.h"5051wxUint16 * zLUT = 0;5253void ZLUT_init()54{55if (zLUT)56return;57zLUT = new wxUint16[0x40000];58for(int i=0; i<0x40000; i++)59{60wxUint32 exponent = 0;61wxUint32 testbit = 1 << 17;62while((i & testbit) && (exponent < 7))63{64exponent++;65testbit = 1 << (17 - exponent);66}6768wxUint32 mantissa = (i >> (6 - (6 < exponent ? 6 : exponent))) & 0x7ff;69zLUT[i] = (wxUint16)(((exponent << 11) | mantissa) << 2);70}71}7273void ZLUT_release()74{75delete[] zLUT;76zLUT = 0;77}7879static vertexi * max_vtx; // Max y vertex (ending vertex)80static vertexi * start_vtx, * end_vtx; // First and last vertex in array81static vertexi * right_vtx, * left_vtx; // Current right and left vertex8283static int right_height, left_height;84static int right_x, right_dxdy, left_x, left_dxdy;85static int left_z, left_dzdy;8687__inline int imul16(int x, int y) // (x * y) >> 1688{89return (((long long)x) * ((long long)y)) >> 16;90}9192__inline int imul14(int x, int y) // (x * y) >> 1493{94return (((long long)x) * ((long long)y)) >> 14;95}96__inline int idiv16(int x, int y) // (x << 16) / y97{98//x = (((long long)x) << 16) / ((long long)y);99/*100eax = x;101ebx = y;102edx = x;103(x << 16) | ()104*/105#if !defined(__GNUC__) && !defined(NO_ASM)106__asm {107mov eax, x108mov ebx, y109mov edx,eax110sar edx,16111shl eax,16112idiv ebx113mov x, eax114}115#elif !defined(NO_ASM)116int reminder;117asm ("idivl %[divisor]"118: "=a" (x), "=d" (reminder)119: [divisor] "g" (y), "d" (x >> 16), "a" (x << 16));120#else121x = (((long long)x) << 16) / ((long long)y);122#endif123return x;124}125126__inline int iceil(int x)127{128x += 0xffff;129return (x >> 16);130}131132static void RightSection(void)133{134// Walk backwards trough the vertex array135136vertexi * v2, * v1 = right_vtx;137if(right_vtx > start_vtx) v2 = right_vtx-1;138else v2 = end_vtx; // Wrap to end of array139right_vtx = v2;140141// v1 = top vertex142// v2 = bottom vertex143144// Calculate number of scanlines in this section145146right_height = iceil(v2->y) - iceil(v1->y);147if(right_height <= 0) return;148149// Guard against possible div overflows150151if(right_height > 1) {152// OK, no worries, we have a section that is at least153// one pixel high. Calculate slope as usual.154155int height = v2->y - v1->y;156right_dxdy = idiv16(v2->x - v1->x, height);157}158else {159// Height is less or equal to one pixel.160// Calculate slope = width * 1/height161// using 18:14 bit precision to avoid overflows.162163int inv_height = (0x10000 << 14) / (v2->y - v1->y);164right_dxdy = imul14(v2->x - v1->x, inv_height);165}166167// Prestep initial values168169int prestep = (iceil(v1->y) << 16) - v1->y;170right_x = v1->x + imul16(prestep, right_dxdy);171}172173static void LeftSection(void)174{175// Walk forward trough the vertex array176177vertexi * v2, * v1 = left_vtx;178if(left_vtx < end_vtx) v2 = left_vtx+1;179else v2 = start_vtx; // Wrap to start of array180left_vtx = v2;181182// v1 = top vertex183// v2 = bottom vertex184185// Calculate number of scanlines in this section186187left_height = iceil(v2->y) - iceil(v1->y);188if(left_height <= 0) return;189190// Guard against possible div overflows191192if(left_height > 1) {193// OK, no worries, we have a section that is at least194// one pixel high. Calculate slope as usual.195196int height = v2->y - v1->y;197left_dxdy = idiv16(v2->x - v1->x, height);198left_dzdy = idiv16(v2->z - v1->z, height);199}200else {201// Height is less or equal to one pixel.202// Calculate slope = width * 1/height203// using 18:14 bit precision to avoid overflows.204205int inv_height = (0x10000 << 14) / (v2->y - v1->y);206left_dxdy = imul14(v2->x - v1->x, inv_height);207left_dzdy = imul14(v2->z - v1->z, inv_height);208}209210// Prestep initial values211212int prestep = (iceil(v1->y) << 16) - v1->y;213left_x = v1->x + imul16(prestep, left_dxdy);214left_z = v1->z + imul16(prestep, left_dzdy);215}216217218void Rasterize(vertexi * vtx, int vertices, int dzdx)219{220start_vtx = vtx; // First vertex in array221222// Search trough the vtx array to find min y, max y223// and the location of these structures.224225vertexi * min_vtx = vtx;226max_vtx = vtx;227228int min_y = vtx->y;229int max_y = vtx->y;230231vtx++;232233for(int n=1; n<vertices; n++) {234if(vtx->y < min_y) {235min_y = vtx->y;236min_vtx = vtx;237}238else239if(vtx->y > max_y) {240max_y = vtx->y;241max_vtx = vtx;242}243vtx++;244}245246// OK, now we know where in the array we should start and247// where to end while scanning the edges of the polygon248249left_vtx = min_vtx; // Left side starting vertex250right_vtx = min_vtx; // Right side starting vertex251end_vtx = vtx-1; // Last vertex in array252253// Search for the first usable right section254255do {256if(right_vtx == max_vtx) return;257RightSection();258} while(right_height <= 0);259260// Search for the first usable left section261262do {263if(left_vtx == max_vtx) return;264LeftSection();265} while(left_height <= 0);266267wxUint16 * destptr = (wxUint16*)(gfx.RDRAM+rdp.zimg);268int y1 = iceil(min_y);269if (y1 >= (int)rdp.scissor_o.lr_y) return;270int shift;271272for(;;)273{274int x1 = iceil(left_x);275if (x1 < (int)rdp.scissor_o.ul_x)276x1 = rdp.scissor_o.ul_x;277int width = iceil(right_x) - x1;278if (x1+width >= (int)rdp.scissor_o.lr_x)279width = rdp.scissor_o.lr_x - x1 - 1;280281if(width > 0 && y1 >= (int)rdp.scissor_o.ul_y) {282283// Prestep initial z284285int prestep = (x1 << 16) - left_x;286int z = left_z + imul16(prestep, dzdx);287288shift = x1 + y1*rdp.zi_width;289//draw to depth buffer290int trueZ;291int idx;292wxUint16 encodedZ;293for (int x = 0; x < width; x++)294{295trueZ = z/8192;296if (trueZ < 0) trueZ = 0;297else if (trueZ > 0x3FFFF) trueZ = 0x3FFFF;298encodedZ = zLUT[trueZ];299idx = (shift+x)^1;300if(encodedZ < destptr[idx])301destptr[idx] = encodedZ;302z += dzdx;303}304}305306//destptr += rdp.zi_width;307y1++;308if (y1 >= (int)rdp.scissor_o.lr_y) return;309310// Scan the right side311312if(--right_height <= 0) { // End of this section?313do {314if(right_vtx == max_vtx) return;315RightSection();316} while(right_height <= 0);317}318else319right_x += right_dxdy;320321// Scan the left side322323if(--left_height <= 0) { // End of this section?324do {325if(left_vtx == max_vtx) return;326LeftSection();327} while(left_height <= 0);328}329else {330left_x += left_dxdy;331left_z += left_dzdy;332}333}334}335336337