| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | // Copyright (C) 2003-2009 Dolphin Project.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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, version 2.0.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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 2.0 for more details.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // A copy of the GPL 2.0 should have been included with the program.
 | 
					
						
							|  |  |  | // If not, see http://www.gnu.org/licenses/
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Official SVN repository and contact information can be found at
 | 
					
						
							|  |  |  | // http://code.google.com/p/dolphin-emu/
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | Portions of this file are based off work by Markus Trenkwalder. | 
					
						
							|  |  |  | Copyright (c) 2007, 2008 Markus Trenkwalder | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | All rights reserved. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Redistribution and use in source and binary forms, with or without  | 
					
						
							|  |  |  | modification, are permitted provided that the following conditions are met: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | * Redistributions of source code must retain the above copyright notice,  | 
					
						
							|  |  |  |   this list of conditions and the following disclaimer. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | * Redistributions in binary form must reproduce the above copyright notice, | 
					
						
							|  |  |  |   this list of conditions and the following disclaimer in the documentation  | 
					
						
							|  |  |  |   and/or other materials provided with the distribution. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | * Neither the name of the library's copyright owner nor the names of its  | 
					
						
							|  |  |  |   contributors may be used to endorse or promote products derived from this  | 
					
						
							|  |  |  |   software without specific prior written permission. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
					
						
							|  |  |  | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
					
						
							|  |  |  | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
					
						
							|  |  |  | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | 
					
						
							|  |  |  | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 
					
						
							|  |  |  | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
					
						
							|  |  |  | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
					
						
							|  |  |  | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | 
					
						
							|  |  |  | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | 
					
						
							|  |  |  | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 
					
						
							|  |  |  | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "Clipper.h"
 | 
					
						
							|  |  |  | #include "Rasterizer.h"
 | 
					
						
							|  |  |  | #include "NativeVertexFormat.h"
 | 
					
						
							|  |  |  | #include "XFMemLoader.h"
 | 
					
						
							|  |  |  | #include "BPMemLoader.h"
 | 
					
						
							|  |  |  | #include "Statistics.h"
 | 
					
						
							|  |  |  | #include "VideoConfig.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Clipper | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-12-02 05:38:48 +00:00
										 |  |  | 	enum { NUM_CLIPPED_VERTICES = 33, NUM_INDICES = NUM_CLIPPED_VERTICES + 3 }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	float m_ViewOffset[3]; | 
					
						
							|  |  |  |     OutputVertexData ClippedVertices[NUM_CLIPPED_VERTICES]; | 
					
						
							|  |  |  |     OutputVertexData *Vertices[NUM_INDICES]; | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     void Init() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2010-12-02 05:38:48 +00:00
										 |  |  |         for (int i = 0; i < NUM_CLIPPED_VERTICES; ++i) | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  |             Vertices[i+3] = &ClippedVertices[i]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void SetViewOffset() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         m_ViewOffset[0] = xfregs.viewport.xOrig - 342; | 
					
						
							|  |  |  |         m_ViewOffset[1] = xfregs.viewport.yOrig - 342; | 
					
						
							|  |  |  |         m_ViewOffset[2] = xfregs.viewport.farZ - xfregs.viewport.farZ; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     enum { | 
					
						
							|  |  |  | 	    SKIP_FLAG = -1, | 
					
						
							|  |  |  |         CLIP_POS_X_BIT = 0x01, | 
					
						
							|  |  |  | 	    CLIP_NEG_X_BIT = 0x02, | 
					
						
							|  |  |  | 	    CLIP_POS_Y_BIT = 0x04, | 
					
						
							|  |  |  | 	    CLIP_NEG_Y_BIT = 0x08, | 
					
						
							|  |  |  | 	    CLIP_POS_Z_BIT = 0x10, | 
					
						
							|  |  |  | 	    CLIP_NEG_Z_BIT = 0x20 | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static inline int CalcClipMask(OutputVertexData *v) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	    int cmask = 0; | 
					
						
							|  |  |  |         Vec4 pos = v->projectedPosition; | 
					
						
							|  |  |  | 	    if (pos.w - pos.x < 0) cmask |= CLIP_POS_X_BIT; | 
					
						
							|  |  |  | 	    if (pos.x + pos.w < 0) cmask |= CLIP_NEG_X_BIT; | 
					
						
							|  |  |  | 	    if (pos.w - pos.y < 0) cmask |= CLIP_POS_Y_BIT; | 
					
						
							|  |  |  | 	    if (pos.y + pos.w < 0) cmask |= CLIP_NEG_Y_BIT; | 
					
						
							|  |  |  | 	    if (pos.w * pos.z > 0) cmask |= CLIP_POS_Z_BIT; | 
					
						
							|  |  |  | 	    if (pos.z + pos.w < 0) cmask |= CLIP_NEG_Z_BIT; | 
					
						
							|  |  |  | 	    return cmask; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static inline void AddInterpolatedVertex(float t, int out, int in, int& numVertices) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Vertices[numVertices]->Lerp(t, Vertices[out], Vertices[in]); | 
					
						
							|  |  |  |         numVertices++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #define DIFFERENT_SIGNS(x,y) ((x <= 0 && y > 0) || (x > 0 && y <= 0))
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #define CLIP_DOTPROD(I, A, B, C, D) \
 | 
					
						
							|  |  |  | 	    (Vertices[I]->projectedPosition.x * A + Vertices[I]->projectedPosition.y * B + Vertices[I]->projectedPosition.z * C + Vertices[I]->projectedPosition.w * D) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #define POLY_CLIP( PLANE_BIT, A, B, C, D )                          \
 | 
					
						
							|  |  |  |     {                                                                   \ | 
					
						
							|  |  |  | 	    if (mask & PLANE_BIT) {                                         \ | 
					
						
							|  |  |  | 		    int idxPrev = inlist[0];                                    \ | 
					
						
							|  |  |  | 		    float dpPrev = CLIP_DOTPROD(idxPrev, A, B, C, D );            \ | 
					
						
							|  |  |  | 		    int outcount = 0;                                           \ | 
					
						
							|  |  |  |                                                                         \ | 
					
						
							|  |  |  | 		    inlist[n] = inlist[0];                                      \ | 
					
						
							|  |  |  | 		    for (int j = 1; j <= n; j++) { 		                            \ | 
					
						
							|  |  |  | 			    int idx = inlist[j];                                    \ | 
					
						
							|  |  |  | 			    float dp = CLIP_DOTPROD(idx, A, B, C, D );                \ | 
					
						
							|  |  |  | 			    if (dpPrev >= 0) {                                      \ | 
					
						
							|  |  |  | 				    outlist[outcount++] = idxPrev;                      \ | 
					
						
							|  |  |  | 			    }                                                       \ | 
					
						
							|  |  |  |                                                                         \ | 
					
						
							|  |  |  | 			    if (DIFFERENT_SIGNS(dp, dpPrev)) {				        \ | 
					
						
							|  |  |  | 				    if (dp < 0) {					                    \ | 
					
						
							|  |  |  | 					    float t = dp / (dp - dpPrev);                   \ | 
					
						
							|  |  |  | 					    AddInterpolatedVertex(t, idx, idxPrev, numVertices);         \ | 
					
						
							|  |  |  | 				    } else {							                \ | 
					
						
							|  |  |  | 					    float t = dpPrev / (dpPrev - dp);               \ | 
					
						
							|  |  |  | 					    AddInterpolatedVertex(t, idxPrev, idx, numVertices);         \ | 
					
						
							|  |  |  | 				    }								                    \ | 
					
						
							|  |  |  | 				    outlist[outcount++] = numVertices - 1;              \ | 
					
						
							|  |  |  | 			    }								                        \ | 
					
						
							|  |  |  |                                                                         \ | 
					
						
							|  |  |  | 			    idxPrev = idx;							                \ | 
					
						
							|  |  |  | 			    dpPrev = dp;							                \ | 
					
						
							|  |  |  | 		    }									                        \ | 
					
						
							|  |  |  |                                                                         \ | 
					
						
							|  |  |  | 		    if (outcount < 3)							                \ | 
					
						
							|  |  |  | 			    continue;							                    \ | 
					
						
							|  |  |  |                                                                         \ | 
					
						
							|  |  |  | 	 	    {									                        \ | 
					
						
							|  |  |  | 			    int *tmp = inlist;				  	                    \ | 
					
						
							|  |  |  | 			    inlist = outlist;				  	                    \ | 
					
						
							|  |  |  | 			    outlist = tmp;					  	                    \ | 
					
						
							|  |  |  | 			    n = outcount;					  	                    \ | 
					
						
							|  |  |  | 		    }									                        \ | 
					
						
							|  |  |  | 	    }									                            \ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#define LINE_CLIP(PLANE_BIT, A, B, C, D )					\
 | 
					
						
							|  |  |  | 	{															\ | 
					
						
							|  |  |  | 		if (mask & PLANE_BIT) {									\ | 
					
						
							|  |  |  | 			const float dp0 = CLIP_DOTPROD( 0, A, B, C, D );	\ | 
					
						
							|  |  |  | 			const float dp1 = CLIP_DOTPROD( 1, A, B, C, D );	\ | 
					
						
							|  |  |  | 			const bool neg_dp0 = dp0 < 0;						\ | 
					
						
							|  |  |  | 			const bool neg_dp1 = dp1 < 0;						\ | 
					
						
							|  |  |  | 																\ | 
					
						
							|  |  |  | 			if (neg_dp0 && neg_dp1)								\ | 
					
						
							|  |  |  | 				return;											\ | 
					
						
							|  |  |  | 																\ | 
					
						
							|  |  |  | 			if (neg_dp1) {										\ | 
					
						
							|  |  |  | 				float t = dp1 / (dp1 - dp0);					\ | 
					
						
							|  |  |  | 				if (t > t1) t1 = t;								\ | 
					
						
							|  |  |  | 			} else if (neg_dp0) {								\ | 
					
						
							|  |  |  | 				float t = dp0 / (dp0 - dp1);					\ | 
					
						
							|  |  |  | 				if (t > t0) t0 = t;								\ | 
					
						
							|  |  |  | 			}													\ | 
					
						
							|  |  |  | 		}														\ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void ClipTriangle(int *indices, int &numIndices) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	    int mask = 0; | 
					
						
							|  |  |  |     	 | 
					
						
							|  |  |  | 	    mask |= CalcClipMask(Vertices[0]); | 
					
						
							|  |  |  |         mask |= CalcClipMask(Vertices[1]); | 
					
						
							|  |  |  |         mask |= CalcClipMask(Vertices[2]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (mask != 0) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  | 		    for(int i = 0; i < 3; i += 3) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 int vlist[2][2*6+1]; | 
					
						
							|  |  |  | 		        int *inlist = vlist[0], *outlist = vlist[1]; | 
					
						
							|  |  |  |                 int n = 3; | 
					
						
							|  |  |  |                 int numVertices = 3; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		        inlist[0] = 0; | 
					
						
							|  |  |  | 		        inlist[1] = 1; | 
					
						
							|  |  |  | 		        inlist[2] = 2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		        // mark this triangle as unused in case it should be completely 
 | 
					
						
							|  |  |  | 		        // clipped
 | 
					
						
							|  |  |  | 		        indices[0] = SKIP_FLAG; | 
					
						
							|  |  |  | 		        indices[1] = SKIP_FLAG; | 
					
						
							|  |  |  | 		        indices[2] = SKIP_FLAG; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		        POLY_CLIP(CLIP_POS_X_BIT, -1,  0,  0, 1); | 
					
						
							|  |  |  | 		        POLY_CLIP(CLIP_NEG_X_BIT,  1,  0,  0, 1); | 
					
						
							|  |  |  | 		        POLY_CLIP(CLIP_POS_Y_BIT,  0, -1,  0, 1); | 
					
						
							|  |  |  | 		        POLY_CLIP(CLIP_NEG_Y_BIT,  0,  1,  0, 1); | 
					
						
							|  |  |  | 		        POLY_CLIP(CLIP_POS_Z_BIT,  0,  0,  0, 1); | 
					
						
							|  |  |  | 		        POLY_CLIP(CLIP_NEG_Z_BIT,  0,  0,  1, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 INCSTAT(stats.thisFrame.numTrianglesClipped); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		        // transform the poly in inlist into triangles
 | 
					
						
							|  |  |  | 		        indices[0] = inlist[0]; | 
					
						
							|  |  |  | 		        indices[1] = inlist[1]; | 
					
						
							|  |  |  | 		        indices[2] = inlist[2]; | 
					
						
							|  |  |  | 		        for (int j = 3; j < n; ++j) { | 
					
						
							|  |  |  | 			        indices[numIndices++] = inlist[0]; | 
					
						
							|  |  |  | 			        indices[numIndices++] = inlist[j - 1]; | 
					
						
							|  |  |  | 			        indices[numIndices++] = inlist[j]; | 
					
						
							|  |  |  | 		        } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void ClipLine(int *indices) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		int mask = 0; | 
					
						
							|  |  |  | 		int clip_mask[2] = { 0, 0 }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (int i = 0; i < 2; ++i) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			clip_mask[i] = CalcClipMask(Vertices[i]); | 
					
						
							|  |  |  | 			mask |= clip_mask[i]; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (mask == 0)  | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		float t0 = 0; | 
					
						
							|  |  |  | 		float t1 = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Mark unused in case of early termination 
 | 
					
						
							|  |  |  | 		// of the macros below. (When fully clipped)
 | 
					
						
							|  |  |  | 		indices[0] = SKIP_FLAG; | 
					
						
							|  |  |  | 		indices[1] = SKIP_FLAG; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		LINE_CLIP(CLIP_POS_X_BIT, -1,  0,  0, 1); | 
					
						
							|  |  |  | 		LINE_CLIP(CLIP_NEG_X_BIT,  1,  0,  0, 1); | 
					
						
							|  |  |  | 		LINE_CLIP(CLIP_POS_Y_BIT,  0, -1,  0, 1); | 
					
						
							|  |  |  | 		LINE_CLIP(CLIP_NEG_Y_BIT,  0,  1,  0, 1); | 
					
						
							|  |  |  | 		LINE_CLIP(CLIP_POS_Z_BIT,  0,  0, -1, 1); | 
					
						
							|  |  |  | 		LINE_CLIP(CLIP_NEG_Z_BIT,  0,  0,  1, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Restore the old values as this line 
 | 
					
						
							|  |  |  | 		// was not fully clipped.
 | 
					
						
							|  |  |  | 		indices[0] = 0; | 
					
						
							|  |  |  | 		indices[1] = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		int numVertices = 2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (clip_mask[0]) { | 
					
						
							|  |  |  | 			indices[0] = numVertices; | 
					
						
							|  |  |  | 			AddInterpolatedVertex(t0, 0, 1, numVertices); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (clip_mask[1]) { | 
					
						
							|  |  |  | 			indices[1] = numVertices; | 
					
						
							|  |  |  | 			AddInterpolatedVertex(t1, 1, 0, numVertices); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void ProcessTriangle(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2011-01-29 04:52:19 +00:00
										 |  |  |         if (stats.thisFrame.numDrawnObjects < g_SWVideoConfig.drawStart || stats.thisFrame.numDrawnObjects >= g_SWVideoConfig.drawEnd ) | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  |             return;   | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         INCSTAT(stats.thisFrame.numTrianglesIn) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bool backface; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if(!CullTest(v0, v1, v2, backface)) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |          | 
					
						
							| 
									
										
										
										
											2010-12-02 05:38:48 +00:00
										 |  |  |         int indices[NUM_INDICES] = { 0, 1, 2, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  |                                      SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, | 
					
						
							|  |  |  |                                      SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG }; | 
					
						
							|  |  |  |         int numIndices = 3; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (backface) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             Vertices[0] = v0; | 
					
						
							|  |  |  |             Vertices[1] = v2; | 
					
						
							|  |  |  |             Vertices[2] = v1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             Vertices[0] = v0; | 
					
						
							|  |  |  |             Vertices[1] = v1; | 
					
						
							|  |  |  |             Vertices[2] = v2; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ClipTriangle(indices, numIndices); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for(int i = 0; i+3 <= numIndices; i+=3) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2010-12-02 05:38:48 +00:00
										 |  |  | 			_assert_(i < NUM_INDICES); | 
					
						
							|  |  |  | 			if(indices[i] != SKIP_FLAG) | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  |             { | 
					
						
							|  |  |  |                 PerspectiveDivide(Vertices[indices[i]]); | 
					
						
							|  |  |  |                 PerspectiveDivide(Vertices[indices[i+1]]); | 
					
						
							|  |  |  |                 PerspectiveDivide(Vertices[indices[i+2]]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 Rasterizer::DrawTriangleFrontFace(Vertices[indices[i]], Vertices[indices[i+1]], Vertices[indices[i+2]]);                 | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void CopyVertex(OutputVertexData *dst, OutputVertexData *src, float dx, float dy, unsigned int sOffset) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		dst->screenPosition.x = src->screenPosition.x + dx; | 
					
						
							|  |  |  | 		dst->screenPosition.y = src->screenPosition.y + dy; | 
					
						
							|  |  |  | 		dst->screenPosition.z = src->screenPosition.z; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (int i = 0; i < 3; ++i) | 
					
						
							|  |  |  | 			dst->normal[i] = src->normal[i]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (int i = 0; i < 4; ++i) | 
					
						
							|  |  |  | 			dst->color[0][i] = src->color[0][i]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// todo - s offset
 | 
					
						
							|  |  |  | 		for (int i = 0; i < 8; ++i) | 
					
						
							|  |  |  | 			dst->texCoords[i] = src->texCoords[i]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void ProcessLine(OutputVertexData *lineV0, OutputVertexData *lineV1) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		int indices[4] = { 0, 1, SKIP_FLAG, SKIP_FLAG }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		Vertices[0] = lineV0; | 
					
						
							|  |  |  |         Vertices[1] = lineV1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// point to a valid vertex to store to when clipping
 | 
					
						
							|  |  |  | 		Vertices[2] = &ClippedVertices[17]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ClipLine(indices); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(indices[0] != SKIP_FLAG) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			OutputVertexData *v0 = Vertices[indices[0]]; | 
					
						
							|  |  |  | 			OutputVertexData *v1 = Vertices[indices[1]]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			PerspectiveDivide(v0); | 
					
						
							|  |  |  |             PerspectiveDivide(v1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			float dx = v1->screenPosition.x - v0->screenPosition.x; | 
					
						
							|  |  |  | 			float dy = v1->screenPosition.y - v0->screenPosition.y; | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			float screenDx = 0; | 
					
						
							|  |  |  | 			float screenDy = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-23 23:48:04 +00:00
										 |  |  | 			if(fabsf(dx) > fabsf(dy)) | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 			{ | 
					
						
							|  |  |  | 				if(dx > 0) | 
					
						
							|  |  |  | 					screenDy = bpmem.lineptwidth.linesize / -12.0f; | 
					
						
							|  |  |  | 				else | 
					
						
							|  |  |  | 					screenDy = bpmem.lineptwidth.linesize / 12.0f; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				if(dy > 0) | 
					
						
							|  |  |  | 					screenDx = bpmem.lineptwidth.linesize / 12.0f; | 
					
						
							|  |  |  | 				else | 
					
						
							|  |  |  | 					screenDx = bpmem.lineptwidth.linesize / -12.0f; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			OutputVertexData triangle[3]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			CopyVertex(&triangle[0], v0, screenDx, screenDy, 0); | 
					
						
							|  |  |  | 			CopyVertex(&triangle[1], v1, screenDx, screenDy, 0); | 
					
						
							|  |  |  | 			CopyVertex(&triangle[2], v1, -screenDx, -screenDy, bpmem.lineptwidth.lineoff); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// ccw winding
 | 
					
						
							|  |  |  | 			Rasterizer::DrawTriangleFrontFace(&triangle[2], &triangle[1], &triangle[0]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			CopyVertex(&triangle[1], v0, -screenDx, -screenDy, bpmem.lineptwidth.lineoff); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Rasterizer::DrawTriangleFrontFace(&triangle[0], &triangle[1], &triangle[2]); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     bool CullTest(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2, bool &backface) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         int mask = CalcClipMask(v0); | 
					
						
							|  |  |  |         mask &= CalcClipMask(v1); | 
					
						
							|  |  |  |         mask &= CalcClipMask(v2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if(mask) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             INCSTAT(stats.thisFrame.numTrianglesRejected) | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         float x0 = v0->projectedPosition.x; | 
					
						
							|  |  |  |         float x1 = v1->projectedPosition.x; | 
					
						
							|  |  |  |         float x2 = v2->projectedPosition.x; | 
					
						
							|  |  |  |         float y1 = v1->projectedPosition.y; | 
					
						
							|  |  |  |         float y0 = v0->projectedPosition.y; | 
					
						
							|  |  |  |         float y2 = v2->projectedPosition.y; | 
					
						
							|  |  |  |         float w0 = v0->projectedPosition.w; | 
					
						
							|  |  |  |         float w1 = v1->projectedPosition.w; | 
					
						
							|  |  |  |         float w2 = v2->projectedPosition.w; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         float normalZDir = (x0*w2 - x2*w0)*y1 + (x2*y0 - x0*y2)*w1 + (y2*w0 - y0*w2)*x1;  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         backface = normalZDir <= 0.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ((bpmem.genMode.cullmode & 1) && !backface) // cull frontfacing
 | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             INCSTAT(stats.thisFrame.numTrianglesCulled) | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ((bpmem.genMode.cullmode & 2) && backface) // cull backfacing
 | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             INCSTAT(stats.thisFrame.numTrianglesCulled) | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void PerspectiveDivide(OutputVertexData *vertex) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Vec4 &projected = vertex->projectedPosition; | 
					
						
							|  |  |  |         Vec3 &screen = vertex->screenPosition; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         float wInverse = 1.0f/projected.w; | 
					
						
							|  |  |  |         screen.x = projected.x * wInverse * xfregs.viewport.wd + m_ViewOffset[0]; | 
					
						
							|  |  |  |         screen.y = projected.y * wInverse * xfregs.viewport.ht + m_ViewOffset[1]; | 
					
						
							|  |  |  |         screen.z = projected.z * wInverse + m_ViewOffset[2]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  | } |