Path: blob/master/libmupen64plus/mupen64plus-video-glide64/src/DepthBufferRender.cpp
2 views
/*1* Glide64 - Glide video plugin for Nintendo 64 emulators.2* Copyright (c) 2002 Dave20013* Copyright (c) 2008 Günther <[email protected]>4*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 Public16* Licence along with this program; if not, write to the Free17* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,18* Boston, MA 02110-1301, USA19*/2021//****************************************************************22//23// Glide64 - Glide Plugin for Nintendo 64 emulators (tested mostly with Project64)24// Project started on December 29th, 200125//26// To modify Glide64:27// * 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.28// * 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.29//30// Official Glide64 development channel: #Glide64 on EFnet31//32//****************************************************************33//34// Software rendering into N64 depth buffer35// Idea and N64 depth value format by Orkin36// Polygon rasterization algorithm is taken from FATMAP2 engine by Mats Byggmastar, [email protected]37//38// Created by Gonetz, Dec 200439//40//****************************************************************4142#include "Gfx1.3.h"43#include "rdp.h"44#include "DepthBufferRender.h"4546WORD * zLUT = 0;4748void ZLUT_init()49{50if (zLUT)51return;52zLUT = new WORD[0x40000];53for(int i=0; i<0x40000; i++)54{55DWORD exponent = 0;56DWORD testbit = 1 << 17;57while((i & testbit) && (exponent < 7))58{59exponent++;60testbit = 1 << (17 - exponent);61}6263DWORD mantissa = (i >> (6 - (6 < exponent ? 6 : exponent))) & 0x7ff;64zLUT[i] = (WORD)(((exponent << 11) | mantissa) << 2);65}66/*67for(i=0; i<0x40000; i++)68{69int j = i + 1;70WORD z = zLUT[i];71while (zLUT[i] == zLUT[j])72j++;73int w = (j - i) >> 2;74if (w > 0)75{76int k;77for (k = 1; k < 4; k++)78for (int t = 0; t < w; t++)79zLUT[i+k*w+t] = z + k;80i = j - 1;81}82}83*/84}8586void ZLUT_release()87{88delete[] zLUT;89zLUT = 0;90}9192static vertexi * max_vtx; // Max y vertex (ending vertex)93static vertexi * start_vtx, * end_vtx; // First and last vertex in array94static vertexi * right_vtx, * left_vtx; // Current right and left vertex9596static int right_height, left_height;97static int right_x, right_dxdy, left_x, left_dxdy;98static int left_z, left_dzdy;99100__inline int iceil(int x)101{102x += 0xffff;103return (x >> 16);104}105106__inline int imul16(int x, int y) // (x * y) >> 16107{108return (((long long)x) * ((long long)y)) >> 16;109}110111__inline int imul14(int x, int y) // (x * y) >> 14112{113return (((long long)x) * ((long long)y)) >> 14;114}115116/*117int idiv16(int x, int y); // (x << 16) / y118#pragma aux idiv16 = \119" mov edx,eax "\120" sar edx,16 "\121" shl eax,16 "\122" idiv ebx "\123parm [eax] [ebx] modify exact [eax edx] value [eax]124*/125__inline int idiv16(int x, int y) // (x << 16) / y126{127//x = (((long long)x) << 16) / ((long long)y);128#if !defined(__GNUC__) && !defined(NO_ASM)129__asm {130mov eax, x131mov ebx, y132mov edx,eax133sar edx,16134shl eax,16135idiv ebx136mov x, eax137}138#elif !defined(NO_ASM)139int reminder;140asm ("idivl %[divisor]"141: "=a" (x), "=d" (reminder)142: [divisor] "g" (y), "d" (x >> 16), "a" (x << 16));143#endif144return x;145}146147148static void RightSection(void)149{150// Walk backwards trough the vertex array151152vertexi * v2, * v1 = right_vtx;153if(right_vtx > start_vtx) v2 = right_vtx-1;154else v2 = end_vtx; // Wrap to end of array155right_vtx = v2;156157// v1 = top vertex158// v2 = bottom vertex159160// Calculate number of scanlines in this section161162right_height = iceil(v2->y) - iceil(v1->y);163if(right_height <= 0) return;164165// Guard against possible div overflows166167if(right_height > 1) {168// OK, no worries, we have a section that is at least169// one pixel high. Calculate slope as usual.170171int height = v2->y - v1->y;172right_dxdy = idiv16(v2->x - v1->x, height);173}174else {175// Height is less or equal to one pixel.176// Calculate slope = width * 1/height177// using 18:14 bit precision to avoid overflows.178179int inv_height = (0x10000 << 14) / (v2->y - v1->y);180right_dxdy = imul14(v2->x - v1->x, inv_height);181}182183// Prestep initial values184185int prestep = (iceil(v1->y) << 16) - v1->y;186right_x = v1->x + imul16(prestep, right_dxdy);187}188189static void LeftSection(void)190{191// Walk forward trough the vertex array192193vertexi * v2, * v1 = left_vtx;194if(left_vtx < end_vtx) v2 = left_vtx+1;195else v2 = start_vtx; // Wrap to start of array196left_vtx = v2;197198// v1 = top vertex199// v2 = bottom vertex200201// Calculate number of scanlines in this section202203left_height = iceil(v2->y) - iceil(v1->y);204if(left_height <= 0) return;205206// Guard against possible div overflows207208if(left_height > 1) {209// OK, no worries, we have a section that is at least210// one pixel high. Calculate slope as usual.211212int height = v2->y - v1->y;213left_dxdy = idiv16(v2->x - v1->x, height);214left_dzdy = idiv16(v2->z - v1->z, height);215}216else {217// Height is less or equal to one pixel.218// Calculate slope = width * 1/height219// using 18:14 bit precision to avoid overflows.220221int inv_height = (0x10000 << 14) / (v2->y - v1->y);222left_dxdy = imul14(v2->x - v1->x, inv_height);223left_dzdy = imul14(v2->z - v1->z, inv_height);224}225226// Prestep initial values227228int prestep = (iceil(v1->y) << 16) - v1->y;229left_x = v1->x + imul16(prestep, left_dxdy);230left_z = v1->z + imul16(prestep, left_dzdy);231}232233234void Rasterize(vertexi * vtx, int vertices, int dzdx)235{236start_vtx = vtx; // First vertex in array237238// Search trough the vtx array to find min y, max y239// and the location of these structures.240241vertexi * min_vtx = vtx;242max_vtx = vtx;243244int min_y = vtx->y;245int max_y = vtx->y;246247vtx++;248249for(int n=1; n<vertices; n++) {250if(vtx->y < min_y) {251min_y = vtx->y;252min_vtx = vtx;253}254else255if(vtx->y > max_y) {256max_y = vtx->y;257max_vtx = vtx;258}259vtx++;260}261262// OK, now we know where in the array we should start and263// where to end while scanning the edges of the polygon264265left_vtx = min_vtx; // Left side starting vertex266right_vtx = min_vtx; // Right side starting vertex267end_vtx = vtx-1; // Last vertex in array268269// Search for the first usable right section270271do {272if(right_vtx == max_vtx) return;273RightSection();274} while(right_height <= 0);275276// Search for the first usable left section277278do {279if(left_vtx == max_vtx) return;280LeftSection();281} while(left_height <= 0);282283WORD * destptr = (WORD*)(gfx.RDRAM+rdp.zimg);284int y1 = iceil(min_y);285int shift;286//destptr += iceil(min_y) * rdp.zi_width;287288for(;;)289{290int x1 = iceil(left_x);291int width = iceil(right_x) - x1;292293if(width > 0) {294295// Prestep initial color intensity i296297if (y1 >= rdp.zi_lry) return;298//if (x1+width > rdp.zi_lrx) width = rdp.zi_lrx-x1;299int prestep = (x1 << 16) - left_x;300int z = left_z + imul16(prestep, dzdx);301302// if (y1 > max_y) return;303// FRDP("Depth render. x1: %d, y1: %d, width: %d\n", x1, y1, width);304shift = x1 + y1*rdp.zi_width;305// if (shift + width > rdp.zi_nb_pixels)306// return;307//draw to depth buffer308int trueZ;309int idx;310WORD encodedZ;311for (int x = 0; x < width; x++)312{313trueZ = z/8192;314if (trueZ < 0) trueZ = 0;315else if (trueZ > 0x3FFFF) trueZ = 0x3FFFF;316encodedZ = zLUT[trueZ];317idx = (shift+x)^1;318if(encodedZ < destptr[idx])319destptr[idx] = encodedZ;320z += dzdx;321}322}323324//destptr += rdp.zi_width;325y1++;326327// Scan the right side328329if(--right_height <= 0) { // End of this section?330do {331if(right_vtx == max_vtx) return;332RightSection();333} while(right_height <= 0);334}335else336right_x += right_dxdy;337338// Scan the left side339340if(--left_height <= 0) { // End of this section?341do {342if(left_vtx == max_vtx) return;343LeftSection();344} while(left_height <= 0);345}346else {347left_x += left_dxdy;348left_z += left_dzdy;349}350}351}352353354355