From: eihrul <eihrul@d7cf8633-e32d-0410-b094-e92efae38249>
Date: Mon, 4 Apr 2011 14:31:32 +0000 (+0000)
Subject: initial support for user clipping plane in dpsoftrast
X-Git-Tag: xonotic-v0.5.0~310
X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=5dbd53a2333dd071b6bf0e134e36b8075ac66889;p=xonotic%2Fdarkplaces.git

initial support for user clipping plane in dpsoftrast

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11016 d7cf8633-e32d-0410-b094-e92efae38249
::stable-branch::merge=c27fadf7530f9e06f6fba5afe584f82b2ebb2629
---

diff --git a/dpsoftrast.c b/dpsoftrast.c
index 70f3f3e4..a784374e 100644
--- a/dpsoftrast.c
+++ b/dpsoftrast.c
@@ -235,6 +235,7 @@ typedef ATOMIC(struct DPSOFTRAST_State_Thread_s
 	int scissor[4];
 	float depthrange[2];
 	float polygonoffset[2];
+	ALIGN(float clipplane[4]);
 
 	int shader_mode;
 	int shader_permutation;
@@ -1435,6 +1436,25 @@ void DPSOFTRAST_Uniform1i(DPSOFTRAST_UNIFORM index, int i0)
 	dpsoftrast.uniform1i[command->index] = i0;
 }
 
+DEFCOMMAND(24, ClipPlane, float clipplane[4];)
+static void DPSOFTRAST_Interpret_ClipPlane(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_ClipPlane *command)
+{
+	memcpy(thread->clipplane, command->clipplane, 4*sizeof(float));
+}
+void DPSOFTRAST_ClipPlane(float x, float y, float z, float w)
+{
+	DPSOFTRAST_Command_ClipPlane *command = DPSOFTRAST_ALLOCATECOMMAND(ClipPlane);
+	x /= dpsoftrast.fb_viewportscale[1];
+	y /= dpsoftrast.fb_viewportscale[2];
+	z /= dpsoftrast.fb_viewportscale[3];
+	w /= dpsoftrast.fb_viewportscale[0];
+	w -= dpsoftrast.fb_viewportcenter[1]*x + dpsoftrast.fb_viewportcenter[2]*y + dpsoftrast.fb_viewportcenter[3]*z + dpsoftrast.fb_viewportcenter[0]*w; 
+	command->clipplane[0] = x;
+	command->clipplane[1] = y;
+	command->clipplane[2] = z;
+	command->clipplane[3] = w;
+}
+
 #ifdef SSE_POSSIBLE
 static void DPSOFTRAST_Load4fTo4f(float *dst, const unsigned char *src, int size, int stride)
 {
@@ -4527,7 +4547,7 @@ void DPSOFTRAST_PixelShader_Refraction(DPSOFTRAST_State_Thread *thread, const DP
 
 		// "	vec2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\n"
 		iw = 1.0f / (ModelViewProjectionPositiondata[3] + ModelViewProjectionPositionslope[3]*x); // / z
-        
+		
 		// "	vec2 SafeScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
 		SafeScreenTexCoord[0] = (ModelViewProjectionPositiondata[0] + ModelViewProjectionPositionslope[0]*x) * iw * ScreenScaleRefractReflect[0] + ScreenCenterRefractReflect[0]; // * z (disappears)
 		SafeScreenTexCoord[1] = (ModelViewProjectionPositiondata[1] + ModelViewProjectionPositionslope[1]*x) * iw * ScreenScaleRefractReflect[1] + ScreenCenterRefractReflect[1]; // * z (disappears)
@@ -4788,6 +4808,8 @@ static void DPSOFTRAST_Interpret_Draw(DPSOFTRAST_State_Thread *thread, DPSOFTRAS
 	int numpoints;
 	int clipcase;
 	float clipdist[4];
+	float clip0origin, clip0slope;
+	int clip0dir;
 	__m128 triangleedge1, triangleedge2, trianglenormal;
 	__m128 clipfrac[3];
 	__m128 screen[4];
@@ -5012,6 +5034,43 @@ static void DPSOFTRAST_Interpret_Draw(DPSOFTRAST_State_Thread *thread, DPSOFTRAS
 			_mm_store_ss(&triangle->w[0], attribxslope);
 			_mm_store_ss(&triangle->w[1], attribyslope);
 			_mm_store_ss(&triangle->w[2], attriborigin);
+			
+			clip0origin = 0;
+			clip0slope = 0;
+			clip0dir = 0;
+			if(thread->clipplane[0] || thread->clipplane[1] || thread->clipplane[2])
+			{
+				float cliporigin, clipxslope, clipyslope;
+				attriborigin = _mm_shuffle_ps(screen[1], screen[1], _MM_SHUFFLE(2, 2, 2, 2));
+				attribedge1 = _mm_sub_ss(_mm_shuffle_ps(screen[0], screen[0], _MM_SHUFFLE(2, 2, 2, 2)), attriborigin);
+				attribedge2 = _mm_sub_ss(_mm_shuffle_ps(screen[2], screen[2], _MM_SHUFFLE(2, 2, 2, 2)), attriborigin);
+				attribxslope = _mm_sub_ss(_mm_mul_ss(attribuxslope, attribedge1), _mm_mul_ss(attribvxslope, attribedge2));
+				attribyslope = _mm_sub_ss(_mm_mul_ss(attribvyslope, attribedge2), _mm_mul_ss(attribuyslope, attribedge1));
+				attriborigin = _mm_sub_ss(attriborigin, _mm_add_ss(_mm_mul_ss(attribxslope, x1), _mm_mul_ss(attribyslope, y1)));
+				cliporigin = _mm_cvtss_f32(attriborigin)*thread->clipplane[2] + thread->clipplane[3];
+				clipxslope = thread->clipplane[0] + _mm_cvtss_f32(attribxslope)*thread->clipplane[2];
+				clipyslope = thread->clipplane[1] + _mm_cvtss_f32(attribyslope)*thread->clipplane[2];
+				if(clipxslope != 0)
+				{
+					clip0origin = -cliporigin/clipxslope;
+					clip0slope = -clipyslope/clipxslope;
+					clip0dir = clipxslope > 0 ? 1 : -1;
+				}
+				else if(clipyslope > 0)
+				{
+					clip0origin = dpsoftrast.fb_width*floor(cliporigin/clipyslope);
+					clip0slope = dpsoftrast.fb_width;
+					clip0dir = -1;
+				}
+				else if(clipyslope < 0)
+				{
+					clip0origin = dpsoftrast.fb_width*ceil(cliporigin/clipyslope);
+					clip0slope = -dpsoftrast.fb_width;
+					clip0dir = -1;
+				}
+				else if(clip0origin < 0) continue;
+			}
+
 			mipedgescale = _mm_setzero_ps();
 			for (j = 0;j < DPSOFTRAST_ARRAY_TOTAL; j++)
 			{
@@ -5073,6 +5132,7 @@ static void DPSOFTRAST_Interpret_Draw(DPSOFTRAST_State_Thread *thread, DPSOFTRAS
 			int yccmask = _mm_movemask_epi8(ycc);
 			int edge0p, edge0n, edge1p, edge1n;
 			int nexty;
+			float clip0;
 			if (numpoints == 4)
 			{
 				switch(yccmask)
@@ -5126,9 +5186,10 @@ static void DPSOFTRAST_Interpret_Draw(DPSOFTRAST_State_Thread *thread, DPSOFTRAS
 				xcoords = _mm_shuffle_ps(xcoords, xcoords, _MM_SHUFFLE(1, 0, 3, 2));
 				xslope = _mm_shuffle_ps(xslope, xslope, _MM_SHUFFLE(1, 0, 3, 2));
 			}
-			for(; y <= nexty; y++, xcoords = _mm_add_ps(xcoords, xslope))
+			clip0 = clip0origin + (y+0.5f)*clip0slope;
+			for(; y <= nexty; y++, xcoords = _mm_add_ps(xcoords, xslope), clip0 += clip0slope)
 			{
-				int startx, endx, offset;
+				int startx, endx, clipx = minx, offset;
 				startx = _mm_cvtss_si32(xcoords);
 				endx = _mm_cvtss_si32(_mm_movehl_ps(xcoords, xcoords));
 				if (startx < minx) 
@@ -5138,13 +5199,32 @@ static void DPSOFTRAST_Interpret_Draw(DPSOFTRAST_State_Thread *thread, DPSOFTRAS
 				}
 				if (endx > maxx) endx = maxx;
 				if (startx >= endx) continue;
+
+				if (clip0dir)
+				{
+					if (clip0dir > 0)
+					{
+						if (startx < clip0) 
+						{
+							if(endx <= clip0) continue;
+							clipx = max((int)clip0, minx);
+							startx += (clipx-startx)&~(DPSOFTRAST_DRAW_MAXSPANLENGTH-1); 
+						}
+					}
+					else if (endx > clip0) 
+					{
+						if(startx >= clip0) continue;
+						endx = (int)clip0;
+					}
+				}
+						
 				for (offset = startx; offset < endx;offset += DPSOFTRAST_DRAW_MAXSPANLENGTH)
 				{
 					DPSOFTRAST_State_Span *span = &thread->spans[thread->numspans];
 					span->triangle = thread->numtriangles;
 					span->x = offset;
 					span->y = y;
-					span->startx = max(minx - offset, 0);
+					span->startx = max(clipx - offset, 0);
 					span->endx = min(endx - offset, DPSOFTRAST_DRAW_MAXSPANLENGTH);
 					if (span->startx >= span->endx)
 						continue; 
@@ -5334,6 +5414,7 @@ static void DPSOFTRAST_Draw_InterpretCommands(DPSOFTRAST_State_Thread *thread, i
 		INTERPCOMMAND(UniformMatrix4f)
 		INTERPCOMMAND(Uniform1i)
 		INTERPCOMMAND(SetRenderTargets)
+		INTERPCOMMAND(ClipPlane)
 
 		case DPSOFTRAST_OPCODE_Draw:
 			DPSOFTRAST_Interpret_Draw(thread, (DPSOFTRAST_Command_Draw *)command);
@@ -5496,6 +5577,10 @@ int DPSOFTRAST_Init(int width, int height, int numthreads, int interlace, unsign
 		thread->depthrange[1] = 1;
 		thread->polygonoffset[0] = 0;
 		thread->polygonoffset[1] = 0;
+		thread->clipplane[0] = 0;
+		thread->clipplane[1] = 0;
+		thread->clipplane[2] = 0;
+		thread->clipplane[3] = 1;
 	
 		DPSOFTRAST_RecalcThread(thread);
 	
diff --git a/dpsoftrast.h b/dpsoftrast.h
index 8ebb98d6..6b7a7067 100644
--- a/dpsoftrast.h
+++ b/dpsoftrast.h
@@ -56,6 +56,7 @@ void DPSOFTRAST_ColorMask(int r, int g, int b, int a);
 void DPSOFTRAST_DepthTest(int enable);
 void DPSOFTRAST_ScissorTest(int enable);
 void DPSOFTRAST_Scissor(float x, float y, float width, float height);
+void DPSOFTRAST_ClipPlane(float x, float y, float z, float w);
 
 void DPSOFTRAST_BlendFunc(int smodulate, int dmodulate);
 void DPSOFTRAST_BlendSubtract(int enable);
diff --git a/gl_backend.c b/gl_backend.c
index 7bc929e9..bb1d6b16 100644
--- a/gl_backend.c
+++ b/gl_backend.c
@@ -730,7 +730,7 @@ static void R_Viewport_ApplyNearClipPlaneFloatGL(const r_viewport_t *v, float *m
 
 	VectorSet(normal, normalx, normaly, normalz);
 	Matrix4x4_Transform3x3(&v->viewmatrix, normal, clipPlane);
-	VectorScale(normal, dist, v3);
+	VectorScale(normal, -dist, v3);
 	Matrix4x4_Transform(&v->viewmatrix, v3, v4);
 	// FIXME: LordHavoc: I think this can be done more efficiently somehow but I can't remember the technique
 	clipPlane[3] = -DotProduct(v4, clipPlane);
diff --git a/gl_rmain.c b/gl_rmain.c
index 4be0e918..7f998d21 100644
--- a/gl_rmain.c
+++ b/gl_rmain.c
@@ -5158,8 +5158,8 @@ void R_SetupView(qboolean allowwaterclippingplane)
 		plane[0] = r_refdef.view.clipplane.normal[0];
 		plane[1] = r_refdef.view.clipplane.normal[1];
 		plane[2] = r_refdef.view.clipplane.normal[2];
-		plane[3] = dist;
-		customclipplane = plane;
+		plane[3] = -dist;
+		if(vid.renderpath != RENDERPATH_SOFT) customclipplane = plane;
 	}
 
 	R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &scaledwidth, &scaledheight);
@@ -5171,6 +5171,16 @@ void R_SetupView(qboolean allowwaterclippingplane)
 		R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, vid.height - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
 	R_Mesh_SetMainRenderTargets();
 	R_SetViewport(&r_refdef.view.viewport);
+	if (r_refdef.view.useclipplane && allowwaterclippingplane && vid.renderpath == RENDERPATH_SOFT)
+	{
+		matrix4x4_t mvpmatrix, invmvpmatrix, invtransmvpmatrix;
+		float screenplane[4];
+		Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
+		Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
+		Matrix4x4_Transpose(&invtransmvpmatrix, &invmvpmatrix);
+		Matrix4x4_Transform4(&invtransmvpmatrix, plane, screenplane);
+		DPSOFTRAST_ClipPlane(screenplane[0], screenplane[1], screenplane[2], screenplane[3]);
+	}
 }
 
 void R_EntityMatrix(const matrix4x4_t *matrix)
@@ -5665,6 +5675,7 @@ static void R_Water_ProcessPlanes(void)
 		}
 
 	}
+	DPSOFTRAST_ClipPlane(0, 0, 0, 1);
 	r_waterstate.renderingscene = false;
 	r_refdef.view = originalview;
 	R_ResetViewRendering3D();