| 
									
										
										
										
											2015-05-24 06:55:12 +02:00
										 |  |  | // Copyright 2009 Dolphin Emulator Project
 | 
					
						
							| 
									
										
										
										
											2015-05-18 01:08:10 +02:00
										 |  |  | // Licensed under GPLv2+
 | 
					
						
							| 
									
										
										
										
											2013-04-17 23:29:41 -04:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 05:16:52 -04:00
										 |  |  | #include "VideoBackends/Software/TransformUnit.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-02 22:47:04 -04:00
										 |  |  | #include <algorithm>
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include <cmath>
 | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 05:16:52 -04:00
										 |  |  | #include "Common/Assert.h"
 | 
					
						
							|  |  |  | #include "Common/CommonFuncs.h"
 | 
					
						
							| 
									
										
										
										
											2014-09-07 20:06:58 -05:00
										 |  |  | #include "Common/CommonTypes.h"
 | 
					
						
							| 
									
										
										
										
											2016-09-24 05:16:52 -04:00
										 |  |  | #include "Common/Logging/Log.h"
 | 
					
						
							| 
									
										
										
										
											2014-05-11 12:53:02 -07:00
										 |  |  | #include "Common/MathUtil.h"
 | 
					
						
							| 
									
										
										
										
											2016-09-24 05:16:52 -04:00
										 |  |  | #include "Common/MsgHandler.h"
 | 
					
						
							| 
									
										
										
										
											2014-05-11 12:53:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "VideoBackends/Software/NativeVertexFormat.h"
 | 
					
						
							|  |  |  | #include "VideoBackends/Software/Vec3.h"
 | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | #include "VideoCommon/BPMemory.h"
 | 
					
						
							|  |  |  | #include "VideoCommon/XFMemory.h"
 | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace TransformUnit | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static void MultiplyVec2Mat24(const Vec3& vec, const float* mat, Vec3& result) | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] + mat[3]; | 
					
						
							|  |  |  |   result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] + mat[7]; | 
					
						
							|  |  |  |   result.z = 1.0f; | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static void MultiplyVec2Mat34(const Vec3& vec, const float* mat, Vec3& result) | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] + mat[3]; | 
					
						
							|  |  |  |   result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] + mat[7]; | 
					
						
							|  |  |  |   result.z = mat[8] * vec.x + mat[9] * vec.y + mat[10] + mat[11]; | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static void MultiplyVec3Mat33(const Vec3& vec, const float* mat, Vec3& result) | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] * vec.z; | 
					
						
							|  |  |  |   result.y = mat[3] * vec.x + mat[4] * vec.y + mat[5] * vec.z; | 
					
						
							|  |  |  |   result.z = mat[6] * vec.x + mat[7] * vec.y + mat[8] * vec.z; | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static void MultiplyVec3Mat24(const Vec3& vec, const float* mat, Vec3& result) | 
					
						
							| 
									
										
										
										
											2010-12-01 04:26:21 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] * vec.z + mat[3]; | 
					
						
							|  |  |  |   result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] * vec.z + mat[7]; | 
					
						
							|  |  |  |   result.z = 1.0f; | 
					
						
							| 
									
										
										
										
											2010-12-01 04:26:21 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static void MultiplyVec3Mat34(const Vec3& vec, const float* mat, Vec3& result) | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] * vec.z + mat[3]; | 
					
						
							|  |  |  |   result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] * vec.z + mat[7]; | 
					
						
							|  |  |  |   result.z = mat[8] * vec.x + mat[9] * vec.y + mat[10] * vec.z + mat[11]; | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static void MultipleVec3Perspective(const Vec3& vec, const float* proj, Vec4& result) | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   result.x = proj[0] * vec.x + proj[1] * vec.z; | 
					
						
							|  |  |  |   result.y = proj[2] * vec.y + proj[3] * vec.z; | 
					
						
							|  |  |  |   // result.z = (proj[4] * vec.z + proj[5]);
 | 
					
						
							|  |  |  |   result.z = (proj[4] * vec.z + proj[5]) * (1.0f - (float)1e-7); | 
					
						
							|  |  |  |   result.w = -vec.z; | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static void MultipleVec3Ortho(const Vec3& vec, const float* proj, Vec4& result) | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   result.x = proj[0] * vec.x + proj[1]; | 
					
						
							|  |  |  |   result.y = proj[2] * vec.y + proj[3]; | 
					
						
							|  |  |  |   result.z = proj[4] * vec.z + proj[5]; | 
					
						
							|  |  |  |   result.w = 1; | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void TransformPosition(const InputVertexData* src, OutputVertexData* dst) | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   const float* mat = &xfmem.posMatrices[src->posMtx * 4]; | 
					
						
							|  |  |  |   MultiplyVec3Mat34(src->position, mat, dst->mvPosition); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (xfmem.projection.type == GX_PERSPECTIVE) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     MultipleVec3Perspective(dst->mvPosition, xfmem.projection.rawProjection, | 
					
						
							|  |  |  |                             dst->projectedPosition); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     MultipleVec3Ortho(dst->mvPosition, xfmem.projection.rawProjection, dst->projectedPosition); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void TransformNormal(const InputVertexData* src, bool nbt, OutputVertexData* dst) | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   const float* mat = &xfmem.normalMatrices[(src->posMtx & 31) * 3]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (nbt) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     MultiplyVec3Mat33(src->normal[0], mat, dst->normal[0]); | 
					
						
							|  |  |  |     MultiplyVec3Mat33(src->normal[1], mat, dst->normal[1]); | 
					
						
							|  |  |  |     MultiplyVec3Mat33(src->normal[2], mat, dst->normal[2]); | 
					
						
							|  |  |  |     dst->normal[0].Normalize(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     MultiplyVec3Mat33(src->normal[0], mat, dst->normal[0]); | 
					
						
							|  |  |  |     dst->normal[0].Normalize(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static void TransformTexCoordRegular(const TexMtxInfo& texinfo, int coordNum, bool specialCase, | 
					
						
							|  |  |  |                                      const InputVertexData* srcVertex, OutputVertexData* dstVertex) | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-03-29 05:49:15 -04:00
										 |  |  |   Vec3 src; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   switch (texinfo.sourcerow) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case XF_SRCGEOM_INROW: | 
					
						
							| 
									
										
										
										
											2016-03-29 05:49:15 -04:00
										 |  |  |     src = srcVertex->position; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     break; | 
					
						
							|  |  |  |   case XF_SRCNORMAL_INROW: | 
					
						
							| 
									
										
										
										
											2016-03-29 05:49:15 -04:00
										 |  |  |     src = srcVertex->normal[0]; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     break; | 
					
						
							|  |  |  |   case XF_SRCBINORMAL_T_INROW: | 
					
						
							| 
									
										
										
										
											2016-03-29 05:49:15 -04:00
										 |  |  |     src = srcVertex->normal[1]; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     break; | 
					
						
							|  |  |  |   case XF_SRCBINORMAL_B_INROW: | 
					
						
							| 
									
										
										
										
											2016-03-29 05:49:15 -04:00
										 |  |  |     src = srcVertex->normal[2]; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     break; | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     _assert_(texinfo.sourcerow >= XF_SRCTEX0_INROW && texinfo.sourcerow <= XF_SRCTEX7_INROW); | 
					
						
							| 
									
										
										
										
											2016-03-29 05:49:15 -04:00
										 |  |  |     src.x = srcVertex->texCoords[texinfo.sourcerow - XF_SRCTEX0_INROW][0]; | 
					
						
							|  |  |  |     src.y = srcVertex->texCoords[texinfo.sourcerow - XF_SRCTEX0_INROW][1]; | 
					
						
							|  |  |  |     src.z = 1.0f; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const float* mat = &xfmem.posMatrices[srcVertex->texMtx[coordNum] * 4]; | 
					
						
							|  |  |  |   Vec3* dst = &dstVertex->texCoords[coordNum]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (texinfo.projection == XF_TEXPROJ_ST) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     if (texinfo.inputform == XF_TEXINPUT_AB11 || specialCase) | 
					
						
							| 
									
										
										
										
											2016-03-29 05:49:15 -04:00
										 |  |  |       MultiplyVec2Mat24(src, mat, *dst); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2016-03-29 05:49:15 -04:00
										 |  |  |       MultiplyVec3Mat24(src, mat, *dst); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   else  // texinfo.projection == XF_TEXPROJ_STQ
 | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     _assert_(!specialCase); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (texinfo.inputform == XF_TEXINPUT_AB11) | 
					
						
							| 
									
										
										
										
											2016-03-29 05:49:15 -04:00
										 |  |  |       MultiplyVec2Mat34(src, mat, *dst); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2016-03-29 05:49:15 -04:00
										 |  |  |       MultiplyVec3Mat34(src, mat, *dst); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (xfmem.dualTexTrans.enabled) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     Vec3 tempCoord; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-31 02:14:51 -05:00
										 |  |  |     // normalize
 | 
					
						
							|  |  |  |     const PostMtxInfo& postInfo = xfmem.postMtxInfo[coordNum]; | 
					
						
							|  |  |  |     const float* postMat = &xfmem.postMatrices[postInfo.index * 4]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     if (specialCase) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       // no normalization
 | 
					
						
							|  |  |  |       // q of input is 1
 | 
					
						
							|  |  |  |       // q of output is unknown
 | 
					
						
							|  |  |  |       tempCoord.x = dst->x; | 
					
						
							|  |  |  |       tempCoord.y = dst->y; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       dst->x = postMat[0] * tempCoord.x + postMat[1] * tempCoord.y + postMat[2] + postMat[3]; | 
					
						
							|  |  |  |       dst->y = postMat[4] * tempCoord.x + postMat[5] * tempCoord.y + postMat[6] + postMat[7]; | 
					
						
							|  |  |  |       dst->z = 1.0f; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (postInfo.normalize) | 
					
						
							|  |  |  |         tempCoord = dst->Normalized(); | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         tempCoord = *dst; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       MultiplyVec3Mat34(tempCoord, postMat, *dst); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-03-13 03:38:44 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-31 02:44:36 -05:00
										 |  |  |   // When q is 0, the GameCube appears to have a special case
 | 
					
						
							|  |  |  |   // This can be seen in devkitPro's neheGX Lesson08 example for Wii
 | 
					
						
							|  |  |  |   // Makes differences in Rogue Squadron 3 (Hoth sky) and The Last Story (shadow culling)
 | 
					
						
							| 
									
										
										
										
											2016-07-23 06:15:03 -05:00
										 |  |  |   if (dst->z == 0.0f) | 
					
						
							| 
									
										
										
										
											2016-03-13 03:38:44 -04:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-07-23 21:30:39 -05:00
										 |  |  |     dst->x = MathUtil::Clamp(dst->x / 2.0f, -1.0f, 1.0f); | 
					
						
							|  |  |  |     dst->y = MathUtil::Clamp(dst->y / 2.0f, -1.0f, 1.0f); | 
					
						
							| 
									
										
										
										
											2016-03-13 03:38:44 -04:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct LightPointer | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   u32 reserved[3]; | 
					
						
							|  |  |  |   u8 color[4]; | 
					
						
							|  |  |  |   Vec3 cosatt; | 
					
						
							|  |  |  |   Vec3 distatt; | 
					
						
							|  |  |  |   Vec3 pos; | 
					
						
							|  |  |  |   Vec3 dir; | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static inline void AddScaledIntegerColor(const u8* src, float scale, Vec3& dst) | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   dst.x += src[1] * scale; | 
					
						
							|  |  |  |   dst.y += src[2] * scale; | 
					
						
							|  |  |  |   dst.z += src[3] * scale; | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-10 21:51:05 -04:00
										 |  |  | static inline float SafeDivide(float n, float d) | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return (d == 0) ? (n > 0 ? 1 : 0) : n / d; | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static float CalculateLightAttn(const LightPointer* light, Vec3* _ldir, const Vec3& normal, | 
					
						
							|  |  |  |                                 const LitChannel& chan) | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   float attn = 1.0f; | 
					
						
							|  |  |  |   Vec3& ldir = *_ldir; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switch (chan.attnfunc) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case LIGHTATTN_NONE: | 
					
						
							|  |  |  |   case LIGHTATTN_DIR: | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ldir = ldir.Normalized(); | 
					
						
							|  |  |  |     if (ldir == Vec3(0.0f, 0.0f, 0.0f)) | 
					
						
							|  |  |  |       ldir = normal; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   case LIGHTATTN_SPEC: | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ldir = ldir.Normalized(); | 
					
						
							|  |  |  |     attn = (ldir * normal) >= 0.0 ? std::max(0.0f, light->dir * normal) : 0; | 
					
						
							|  |  |  |     Vec3 attLen = Vec3(1.0, attn, attn * attn); | 
					
						
							|  |  |  |     Vec3 cosAttn = light->cosatt; | 
					
						
							|  |  |  |     Vec3 distAttn = light->distatt; | 
					
						
							|  |  |  |     if (chan.diffusefunc != LIGHTDIF_NONE) | 
					
						
							|  |  |  |       distAttn = distAttn.Normalized(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     attn = SafeDivide(std::max(0.0f, attLen * cosAttn), attLen * distAttn); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   case LIGHTATTN_SPOT: | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     float dist2 = ldir.Length2(); | 
					
						
							|  |  |  |     float dist = sqrtf(dist2); | 
					
						
							|  |  |  |     ldir = ldir / dist; | 
					
						
							|  |  |  |     attn = std::max(0.0f, ldir * light->dir); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     float cosAtt = light->cosatt.x + (light->cosatt.y * attn) + (light->cosatt.z * attn * attn); | 
					
						
							|  |  |  |     float distAtt = light->distatt.x + (light->distatt.y * dist) + (light->distatt.z * dist2); | 
					
						
							|  |  |  |     attn = SafeDivide(std::max(0.0f, cosAtt), distAtt); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     PanicAlert("LightColor"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return attn; | 
					
						
							| 
									
										
										
										
											2015-02-07 17:16:04 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static void LightColor(const Vec3& pos, const Vec3& normal, u8 lightNum, LitChannel& chan, | 
					
						
							|  |  |  |                        Vec3& lightCol) | 
					
						
							| 
									
										
										
										
											2015-02-07 17:16:04 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   const LightPointer* light = (const LightPointer*)&xfmem.lights[lightNum]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Vec3 ldir = light->pos - pos; | 
					
						
							|  |  |  |   float attn = CalculateLightAttn(light, &ldir, normal, chan); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   float difAttn = ldir * normal; | 
					
						
							|  |  |  |   switch (chan.diffusefunc) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case LIGHTDIF_NONE: | 
					
						
							|  |  |  |     AddScaledIntegerColor(light->color, attn, lightCol); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case LIGHTDIF_SIGN: | 
					
						
							|  |  |  |     AddScaledIntegerColor(light->color, attn * difAttn, lightCol); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case LIGHTDIF_CLAMP: | 
					
						
							|  |  |  |     difAttn = std::max(0.0f, difAttn); | 
					
						
							|  |  |  |     AddScaledIntegerColor(light->color, attn * difAttn, lightCol); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     _assert_(0); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static void LightAlpha(const Vec3& pos, const Vec3& normal, u8 lightNum, const LitChannel& chan, | 
					
						
							|  |  |  |                        float& lightCol) | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   const LightPointer* light = (const LightPointer*)&xfmem.lights[lightNum]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Vec3 ldir = light->pos - pos; | 
					
						
							|  |  |  |   float attn = CalculateLightAttn(light, &ldir, normal, chan); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   float difAttn = ldir * normal; | 
					
						
							|  |  |  |   switch (chan.diffusefunc) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case LIGHTDIF_NONE: | 
					
						
							|  |  |  |     lightCol += light->color[0] * attn; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case LIGHTDIF_SIGN: | 
					
						
							|  |  |  |     lightCol += light->color[0] * attn * difAttn; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case LIGHTDIF_CLAMP: | 
					
						
							|  |  |  |     difAttn = std::max(0.0f, difAttn); | 
					
						
							|  |  |  |     lightCol += light->color[0] * attn * difAttn; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     _assert_(0); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void TransformColor(const InputVertexData* src, OutputVertexData* dst) | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   for (u32 chan = 0; chan < xfmem.numChan.numColorChans; chan++) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // abgr
 | 
					
						
							|  |  |  |     u8 matcolor[4]; | 
					
						
							|  |  |  |     u8 chancolor[4]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // color
 | 
					
						
							|  |  |  |     LitChannel& colorchan = xfmem.color[chan]; | 
					
						
							|  |  |  |     if (colorchan.matsource) | 
					
						
							|  |  |  |       *(u32*)matcolor = *(u32*)src->color[chan];  // vertex
 | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       *(u32*)matcolor = xfmem.matColor[chan]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (colorchan.enablelighting) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       Vec3 lightCol; | 
					
						
							|  |  |  |       if (colorchan.ambsource) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         // vertex
 | 
					
						
							|  |  |  |         lightCol.x = src->color[chan][1]; | 
					
						
							|  |  |  |         lightCol.y = src->color[chan][2]; | 
					
						
							|  |  |  |         lightCol.z = src->color[chan][3]; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         u8* ambColor = (u8*)&xfmem.ambColor[chan]; | 
					
						
							|  |  |  |         lightCol.x = ambColor[1]; | 
					
						
							|  |  |  |         lightCol.y = ambColor[2]; | 
					
						
							|  |  |  |         lightCol.z = ambColor[3]; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       u8 mask = colorchan.GetFullLightMask(); | 
					
						
							|  |  |  |       for (int i = 0; i < 8; ++i) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         if (mask & (1 << i)) | 
					
						
							|  |  |  |           LightColor(dst->mvPosition, dst->normal[0], i, colorchan, lightCol); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       int light_x = MathUtil::Clamp(static_cast<int>(lightCol.x), 0, 255); | 
					
						
							|  |  |  |       int light_y = MathUtil::Clamp(static_cast<int>(lightCol.y), 0, 255); | 
					
						
							|  |  |  |       int light_z = MathUtil::Clamp(static_cast<int>(lightCol.z), 0, 255); | 
					
						
							|  |  |  |       chancolor[1] = (matcolor[1] * (light_x + (light_x >> 7))) >> 8; | 
					
						
							|  |  |  |       chancolor[2] = (matcolor[2] * (light_y + (light_y >> 7))) >> 8; | 
					
						
							|  |  |  |       chancolor[3] = (matcolor[3] * (light_z + (light_z >> 7))) >> 8; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       *(u32*)chancolor = *(u32*)matcolor; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // alpha
 | 
					
						
							|  |  |  |     LitChannel& alphachan = xfmem.alpha[chan]; | 
					
						
							|  |  |  |     if (alphachan.matsource) | 
					
						
							|  |  |  |       matcolor[0] = src->color[chan][0];  // vertex
 | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       matcolor[0] = xfmem.matColor[chan] & 0xff; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (xfmem.alpha[chan].enablelighting) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       float lightCol; | 
					
						
							|  |  |  |       if (alphachan.ambsource) | 
					
						
							|  |  |  |         lightCol = src->color[chan][0];  // vertex
 | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         lightCol = (float)(xfmem.ambColor[chan] & 0xff); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       u8 mask = alphachan.GetFullLightMask(); | 
					
						
							|  |  |  |       for (int i = 0; i < 8; ++i) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         if (mask & (1 << i)) | 
					
						
							|  |  |  |           LightAlpha(dst->mvPosition, dst->normal[0], i, alphachan, lightCol); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       int light_a = MathUtil::Clamp(static_cast<int>(lightCol), 0, 255); | 
					
						
							|  |  |  |       chancolor[0] = (matcolor[0] * (light_a + (light_a >> 7))) >> 8; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       chancolor[0] = matcolor[0]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // abgr -> rgba
 | 
					
						
							|  |  |  |     *(u32*)dst->color[chan] = Common::swap32(*(u32*)chancolor); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void TransformTexCoord(const InputVertexData* src, OutputVertexData* dst, bool specialCase) | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   for (u32 coordNum = 0; coordNum < xfmem.numTexGen.numTexGens; coordNum++) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     const TexMtxInfo& texinfo = xfmem.texMtxInfo[coordNum]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (texinfo.texgentype) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case XF_TEXGEN_REGULAR: | 
					
						
							|  |  |  |       TransformTexCoordRegular(texinfo, coordNum, specialCase, src, dst); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case XF_TEXGEN_EMBOSS_MAP: | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       const LightPointer* light = (const LightPointer*)&xfmem.lights[texinfo.embosslightshift]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       Vec3 ldir = (light->pos - dst->mvPosition).Normalized(); | 
					
						
							|  |  |  |       float d1 = ldir * dst->normal[1]; | 
					
						
							|  |  |  |       float d2 = ldir * dst->normal[2]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       dst->texCoords[coordNum].x = dst->texCoords[texinfo.embosssourceshift].x + d1; | 
					
						
							|  |  |  |       dst->texCoords[coordNum].y = dst->texCoords[texinfo.embosssourceshift].y + d2; | 
					
						
							|  |  |  |       dst->texCoords[coordNum].z = dst->texCoords[texinfo.embosssourceshift].z; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |     case XF_TEXGEN_COLOR_STRGBC0: | 
					
						
							|  |  |  |       _assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW); | 
					
						
							|  |  |  |       _assert_(texinfo.inputform == XF_TEXINPUT_AB11); | 
					
						
							|  |  |  |       dst->texCoords[coordNum].x = (float)dst->color[0][0] / 255.0f; | 
					
						
							|  |  |  |       dst->texCoords[coordNum].y = (float)dst->color[0][1] / 255.0f; | 
					
						
							|  |  |  |       dst->texCoords[coordNum].z = 1.0f; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case XF_TEXGEN_COLOR_STRGBC1: | 
					
						
							|  |  |  |       _assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW); | 
					
						
							|  |  |  |       _assert_(texinfo.inputform == XF_TEXINPUT_AB11); | 
					
						
							|  |  |  |       dst->texCoords[coordNum].x = (float)dst->color[1][0] / 255.0f; | 
					
						
							|  |  |  |       dst->texCoords[coordNum].y = (float)dst->color[1][1] / 255.0f; | 
					
						
							|  |  |  |       dst->texCoords[coordNum].z = 1.0f; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       ERROR_LOG(VIDEO, "Bad tex gen type %i", texinfo.texgentype); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (u32 coordNum = 0; coordNum < xfmem.numTexGen.numTexGens; coordNum++) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     dst->texCoords[coordNum][0] *= (bpmem.texcoords[coordNum].s.scale_minus_1 + 1); | 
					
						
							|  |  |  |     dst->texCoords[coordNum][1] *= (bpmem.texcoords[coordNum].t.scale_minus_1 + 1); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | } |