void UpdateZTiMatrices(CLink *Skelet) { /* **************************************************************************************************************************** */ int i; MDFloat tempT[4][4]; MDFloat tempZTi[4][4]; MDFloat *ptrZTi = (MDFloat*)tempZTi; MDFloat *ptrtempT = (MDFloat*)tempT; /* **************************************************************************************************************************** */ LoadIdentity(ptrZTi); for (i=0; i<_NO_OF_LINKS_; i++) { MultMatrix4x4((MDFloat(*)[4])Skelet[i].Get_im1Ti(), tempZTi, tempT); CopyMatrix4x4(ptrtempT, ptrZTi); Skelet[i].Set_ZTi(tempZTi); } /* **************************************************************************************************************************** */ }
# Dessin du squelette ############################################################################################################################ */ void DrawSkelet(void) { /* **************************************************************************************************************************** */ int i; MDFloat tempT[4][4]; MDFloat ZTi[4][4]; MDFloat *ptrZTi = (MDFloat*)ZTi; MDFloat *ptrtempT = (MDFloat*)tempT; /* **************************************************************************************************************************** */ MoveToOrigin(); /* **************************************************************************************************************************** */ glLoadName(_DESIRED_EE_ID_); glDisable(GL_LIGHTING); glMatrixMode(GL_MODELVIEW); glBegin(GL_POINTS); glColor3f(1.0f, 1.0f, 0.2f); glVertex3dv(PNew); glEnd(); glEnable(GL_LIGHTING); /* **************************************************************************************************************************** */ glMatrixMode(GL_MODELVIEW); /* **************************************************************************************************************************** */ glPushMatrix(); /* **************************************************************************************************************************** */ LoadIdentity(ptrZTi); for (i=0; i<_NO_OF_LINKS_; i++) { Skelet[i].Draw(); glPopMatrix(); glPushMatrix(); MultMatrix4x4((MDFloat(*)[4])Skelet[i].Get_im1Ti(), ZTi, tempT); CopyMatrix4x4(ptrtempT, ptrZTi); glMultTransposeMatrixd(ptrZTi); } /* **************************************************************************************************************************** */ DrawEE(); /* **************************************************************************************************************************** */
void SkeletInit() { /* **************************************************************************************************************************** */ int i; MDFloat (*ZTN)[4]; /* **************************************************************************************************************************** */ // Initialisation des paramètres du squelette Skelet[0].SetLength(0); Skelet[0].SetAlpha(0); Skelet[0].SetBeta(0); Skelet[0].SetGamma(_THETA_); for (i=0; i< _NO_OF_LINKS_; i++) { Skelet[i].SetIdx(i); if (i>0) { Skelet[i].SetLength(_L_); Skelet[i].SetAlpha(0); Skelet[i].SetBeta(0); Skelet[i].SetGamma(_THETA_); } } /* **************************************************************************************************************************** */ MDFloat tempT[4][4]; MDFloat tempZTi[4][4]; MDFloat *ptrZTi = (MDFloat*)tempZTi; MDFloat *ptrtempT = (MDFloat*)tempT; /* **************************************************************************************************************************** */ // Initialisation des matrices de transformation du noeud racine au noeud actuel : ZTi LoadIdentity(ptrZTi); for (i=0; i<_NO_OF_LINKS_; i++) { MultMatrix4x4((MDFloat(*)[4])Skelet[i].Get_im1Ti(), tempZTi, tempT); CopyMatrix4x4(ptrtempT, ptrZTi); Skelet[i].Set_ZTi(tempZTi); } ZTN = (MDFloat(*)[4])Skelet[_NO_OF_LINKS_-1].Get_ZTi(); PnIter[0] = ZTN[0][3]; PnIter[1] = ZTN[1][3]; PnIter[2] = ZTN[2][3]; PnIter[3] = 1.0; /* **************************************************************************************************************************** */ }
void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipViewport) { if (dirtyUniforms & DIRTY_TEXENV) { Uint8x3ToFloat4(ub->texEnvColor, gstate.texenvcolor); } if (dirtyUniforms & DIRTY_ALPHACOLORREF) { Uint8x3ToInt4_Alpha(ub->alphaColorRef, gstate.getColorTestRef(), gstate.getAlphaTestRef() & gstate.getAlphaTestMask()); } if (dirtyUniforms & DIRTY_ALPHACOLORMASK) { Uint8x3ToInt4_Alpha(ub->colorTestMask, gstate.getColorTestMask(), gstate.getAlphaTestMask()); } if (dirtyUniforms & DIRTY_FOGCOLOR) { Uint8x3ToFloat4(ub->fogColor, gstate.fogcolor); } if (dirtyUniforms & DIRTY_SHADERBLEND) { Uint8x3ToFloat4(ub->blendFixA, gstate.getFixA()); Uint8x3ToFloat4(ub->blendFixB, gstate.getFixB()); } if (dirtyUniforms & DIRTY_TEXCLAMP) { const float invW = 1.0f / (float)gstate_c.curTextureWidth; const float invH = 1.0f / (float)gstate_c.curTextureHeight; const int w = gstate.getTextureWidth(0); const int h = gstate.getTextureHeight(0); const float widthFactor = (float)w * invW; const float heightFactor = (float)h * invH; // First wrap xy, then half texel xy (for clamp.) ub->texClamp[0] = widthFactor; ub->texClamp[1] = heightFactor; ub->texClamp[2] = invW * 0.5f; ub->texClamp[3] = invH * 0.5f; ub->texClampOffset[0] = gstate_c.curTextureXOffset * invW; ub->texClampOffset[1] = gstate_c.curTextureYOffset * invH; } if (dirtyUniforms & DIRTY_PROJMATRIX) { Matrix4x4 flippedMatrix; memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float)); const bool invertedY = gstate_c.vpHeight < 0; if (invertedY) { flippedMatrix[1] = -flippedMatrix[1]; flippedMatrix[5] = -flippedMatrix[5]; flippedMatrix[9] = -flippedMatrix[9]; flippedMatrix[13] = -flippedMatrix[13]; } const bool invertedX = gstate_c.vpWidth < 0; if (invertedX) { flippedMatrix[0] = -flippedMatrix[0]; flippedMatrix[4] = -flippedMatrix[4]; flippedMatrix[8] = -flippedMatrix[8]; flippedMatrix[12] = -flippedMatrix[12]; } if (flipViewport) { ConvertProjMatrixToD3D11(flippedMatrix); } else { ConvertProjMatrixToVulkan(flippedMatrix); } if (g_Config.iRenderingMode == 0 && g_display_rotation != DisplayRotation::ROTATE_0) { flippedMatrix = flippedMatrix * g_display_rot_matrix; } CopyMatrix4x4(ub->proj, flippedMatrix.getReadPtr()); } if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) { Matrix4x4 proj_through; if (flipViewport) { proj_through.setOrthoD3D(0.0f, gstate_c.curRTWidth, gstate_c.curRTHeight, 0, 0, 1); } else { proj_through.setOrthoVulkan(0.0f, gstate_c.curRTWidth, 0, gstate_c.curRTHeight, 0, 1); } if (g_Config.iRenderingMode == 0 && g_display_rotation != DisplayRotation::ROTATE_0) { proj_through = proj_through * g_display_rot_matrix; } CopyMatrix4x4(ub->proj_through, proj_through.getReadPtr()); } // Transform if (dirtyUniforms & DIRTY_WORLDMATRIX) { ConvertMatrix4x3To3x4Transposed(ub->world, gstate.worldMatrix); } if (dirtyUniforms & DIRTY_VIEWMATRIX) { ConvertMatrix4x3To3x4Transposed(ub->view, gstate.viewMatrix); } if (dirtyUniforms & DIRTY_TEXMATRIX) { ConvertMatrix4x3To3x4Transposed(ub->tex, gstate.tgenMatrix); } // Combined two small uniforms if (dirtyUniforms & (DIRTY_FOGCOEF | DIRTY_STENCILREPLACEVALUE)) { float fogcoef_stencil[3] = { getFloat24(gstate.fog1), getFloat24(gstate.fog2), (float)gstate.getStencilTestRef()/255.0f }; if (my_isinf(fogcoef_stencil[1])) { // not really sure what a sensible value might be. fogcoef_stencil[1] = fogcoef_stencil[1] < 0.0f ? -10000.0f : 10000.0f; } else if (my_isnan(fogcoef_stencil[1])) { // Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988 // Just put the fog far away at a large finite distance. // Infinities and NaNs are rather unpredictable in shaders on many GPUs // so it's best to just make it a sane calculation. fogcoef_stencil[0] = 100000.0f; fogcoef_stencil[1] = 1.0f; } #ifndef MOBILE_DEVICE else if (my_isnanorinf(fogcoef_stencil[1]) || my_isnanorinf(fogcoef_stencil[0])) { ERROR_LOG_REPORT_ONCE(fognan, G3D, "Unhandled fog NaN/INF combo: %f %f", fogcoef_stencil[0], fogcoef_stencil[1]); } #endif CopyFloat3(ub->fogCoef_stencil, fogcoef_stencil); } // Note - this one is not in lighting but in transformCommon as it has uses beyond lighting if (dirtyUniforms & DIRTY_MATAMBIENTALPHA) { Uint8x3ToFloat4_AlphaUint8(ub->matAmbient, gstate.materialambient, gstate.getMaterialAmbientA()); } // Texturing if (dirtyUniforms & DIRTY_UVSCALEOFFSET) { const float invW = 1.0f / (float)gstate_c.curTextureWidth; const float invH = 1.0f / (float)gstate_c.curTextureHeight; const int w = gstate.getTextureWidth(0); const int h = gstate.getTextureHeight(0); const float widthFactor = (float)w * invW; const float heightFactor = (float)h * invH; if (gstate_c.bezier || gstate_c.spline) { // When we are generating UV coordinates through the bezier/spline, we need to apply the scaling. // However, this is missing a check that we're not getting our UV:s supplied for us in the vertices. ub->uvScaleOffset[0] = gstate_c.uv.uScale * widthFactor; ub->uvScaleOffset[1] = gstate_c.uv.vScale * heightFactor; ub->uvScaleOffset[2] = gstate_c.uv.uOff * widthFactor; ub->uvScaleOffset[3] = gstate_c.uv.vOff * heightFactor; } else { ub->uvScaleOffset[0] = widthFactor; ub->uvScaleOffset[1] = heightFactor; ub->uvScaleOffset[2] = 0.0f; ub->uvScaleOffset[3] = 0.0f; } } if (dirtyUniforms & DIRTY_DEPTHRANGE) { float viewZScale = gstate.getViewportZScale(); float viewZCenter = gstate.getViewportZCenter(); // We had to scale and translate Z to account for our clamped Z range. // Therefore, we also need to reverse this to round properly. // // Example: scale = 65535.0, center = 0.0 // Resulting range = -65535 to 65535, clamped to [0, 65535] // gstate_c.vpDepthScale = 2.0f // gstate_c.vpZOffset = -1.0f // // The projection already accounts for those, so we need to reverse them. // // Additionally, D3D9 uses a range from [0, 1]. We double and move the center. viewZScale *= (1.0f / gstate_c.vpDepthScale) * 2.0f; viewZCenter -= 65535.0f * gstate_c.vpZOffset + 32768.5f; float viewZInvScale; if (viewZScale != 0.0) { viewZInvScale = 1.0f / viewZScale; } else { viewZInvScale = 0.0; } ub->depthRange[0] = viewZScale; ub->depthRange[1] = viewZCenter; ub->depthRange[2] = viewZCenter; ub->depthRange[3] = viewZInvScale; } if (dirtyUniforms & DIRTY_BEZIERSPLINE) { ub->spline_count_u = gstate_c.spline_count_u; ub->spline_count_v = gstate_c.spline_count_v; ub->spline_type_u = gstate_c.spline_type_u; ub->spline_type_v = gstate_c.spline_type_v; } }
void ShaderManagerVulkan::BaseUpdateUniforms(int dirtyUniforms) { if (dirtyUniforms & DIRTY_TEXENV) { Uint8x3ToFloat4(ub_base.texEnvColor, gstate.texenvcolor); } if (dirtyUniforms & DIRTY_ALPHACOLORREF) { Uint8x3ToInt4_Alpha(ub_base.alphaColorRef, gstate.getColorTestRef(), gstate.getAlphaTestRef() & gstate.getAlphaTestMask()); } if (dirtyUniforms & DIRTY_ALPHACOLORMASK) { Uint8x3ToInt4_Alpha(ub_base.colorTestMask, gstate.getColorTestMask(), gstate.getAlphaTestMask()); } if (dirtyUniforms & DIRTY_FOGCOLOR) { Uint8x3ToFloat4(ub_base.fogColor, gstate.fogcolor); } if (dirtyUniforms & DIRTY_SHADERBLEND) { Uint8x3ToFloat4(ub_base.blendFixA, gstate.getFixA()); Uint8x3ToFloat4(ub_base.blendFixB, gstate.getFixB()); } if (dirtyUniforms & DIRTY_TEXCLAMP) { const float invW = 1.0f / (float)gstate_c.curTextureWidth; const float invH = 1.0f / (float)gstate_c.curTextureHeight; const int w = gstate.getTextureWidth(0); const int h = gstate.getTextureHeight(0); const float widthFactor = (float)w * invW; const float heightFactor = (float)h * invH; // First wrap xy, then half texel xy (for clamp.) ub_base.texClamp[0] = widthFactor; ub_base.texClamp[1] = heightFactor; ub_base.texClamp[2] = invW * 0.5f; ub_base.texClamp[3] = invH * 0.5f; ub_base.texClampOffset[0] = gstate_c.curTextureXOffset * invW; ub_base.texClampOffset[1] = gstate_c.curTextureYOffset * invH; } if (dirtyUniforms & DIRTY_PROJMATRIX) { Matrix4x4 flippedMatrix; memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float)); const bool invertedY = gstate_c.vpHeight < 0; if (invertedY) { flippedMatrix[1] = -flippedMatrix[1]; flippedMatrix[5] = -flippedMatrix[5]; flippedMatrix[9] = -flippedMatrix[9]; flippedMatrix[13] = -flippedMatrix[13]; } const bool invertedX = gstate_c.vpWidth < 0; if (invertedX) { flippedMatrix[0] = -flippedMatrix[0]; flippedMatrix[4] = -flippedMatrix[4]; flippedMatrix[8] = -flippedMatrix[8]; flippedMatrix[12] = -flippedMatrix[12]; } ConvertProjMatrixToVulkan(flippedMatrix, invertedX, invertedY); CopyMatrix4x4(ub_base.proj, flippedMatrix.getReadPtr()); } if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) { Matrix4x4 proj_through; proj_through.setOrthoVulkan(0.0f, gstate_c.curRTWidth, 0, gstate_c.curRTHeight, 0, 1); CopyMatrix4x4(ub_base.proj_through, proj_through.getReadPtr()); } // Transform if (dirtyUniforms & DIRTY_WORLDMATRIX) { ConvertMatrix4x3To4x4(ub_base.world, gstate.worldMatrix); } if (dirtyUniforms & DIRTY_VIEWMATRIX) { ConvertMatrix4x3To4x4(ub_base.view, gstate.viewMatrix); } if (dirtyUniforms & DIRTY_TEXMATRIX) { ConvertMatrix4x3To4x4(ub_base.tex, gstate.tgenMatrix); } // Combined two small uniforms if (dirtyUniforms & (DIRTY_FOGCOEF | DIRTY_STENCILREPLACEVALUE)) { float fogcoef_stencil[3] = { getFloat24(gstate.fog1), getFloat24(gstate.fog2), (float)gstate.getStencilTestRef() }; if (my_isinf(fogcoef_stencil[1])) { // not really sure what a sensible value might be. fogcoef_stencil[1] = fogcoef_stencil[1] < 0.0f ? -10000.0f : 10000.0f; } else if (my_isnan(fogcoef_stencil[1])) { // Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988 // Just put the fog far away at a large finite distance. // Infinities and NaNs are rather unpredictable in shaders on many GPUs // so it's best to just make it a sane calculation. fogcoef_stencil[0] = 100000.0f; fogcoef_stencil[1] = 1.0f; } #ifndef MOBILE_DEVICE else if (my_isnanorinf(fogcoef_stencil[1]) || my_isnanorinf(fogcoef_stencil[0])) { ERROR_LOG_REPORT_ONCE(fognan, G3D, "Unhandled fog NaN/INF combo: %f %f", fogcoef_stencil[0], fogcoef_stencil[1]); } #endif CopyFloat3(ub_base.fogCoef_stencil, fogcoef_stencil); } // Texturing if (dirtyUniforms & DIRTY_UVSCALEOFFSET) { const float invW = 1.0f / (float)gstate_c.curTextureWidth; const float invH = 1.0f / (float)gstate_c.curTextureHeight; const int w = gstate.getTextureWidth(0); const int h = gstate.getTextureHeight(0); const float widthFactor = (float)w * invW; const float heightFactor = (float)h * invH; ub_base.uvScaleOffset[0] = widthFactor; ub_base.uvScaleOffset[1] = heightFactor; ub_base.uvScaleOffset[2] = 0.0f; ub_base.uvScaleOffset[3] = 0.0f; } if (dirtyUniforms & DIRTY_DEPTHRANGE) { float viewZScale = gstate.getViewportZScale(); float viewZCenter = gstate.getViewportZCenter(); float viewZInvScale; // We had to scale and translate Z to account for our clamped Z range. // Therefore, we also need to reverse this to round properly. // // Example: scale = 65535.0, center = 0.0 // Resulting range = -65535 to 65535, clamped to [0, 65535] // gstate_c.vpDepthScale = 2.0f // gstate_c.vpZOffset = -1.0f // // The projection already accounts for those, so we need to reverse them. // // Additionally, D3D9 uses a range from [0, 1]. We double and move the center. viewZScale *= (1.0f / gstate_c.vpDepthScale) * 2.0f; viewZCenter -= 65535.0f * gstate_c.vpZOffset + 32768.5f; if (viewZScale != 0.0) { viewZInvScale = 1.0f / viewZScale; } else { viewZInvScale = 0.0; } ub_base.depthRange[0] = viewZScale; ub_base.depthRange[1] = viewZCenter; ub_base.depthRange[2] = viewZCenter; ub_base.depthRange[3] = viewZInvScale; } }
void MakeJacobian(CLink *Skelet, TJacobian J) { /* **************************************************************************************************************************** */ int i; MDFloat ai[4], bi[4], v[4], Pn[4], Pj[4]; MDFloat tempT[4][4]; MDFloat tempZTi[4][4]; MDFloat *ptrZTi = (MDFloat*)tempZTi; MDFloat *ptrtempT = (MDFloat*)tempT; /* **************************************************************************************************************************** */ // Calcul de la matrice de transformation globale de l'effecteur terminal (ZTi) LoadIdentity(ptrZTi); for (i=0; i<_NO_OF_LINKS_; i++) { // .. MultMatrix4x4((MDFloat(*)[4])Skelet[i].Get_im1Ti(),tempZTi,tempT); CopyMatrix4x4(ptrtempT,ptrZTi); Skelet[i].Set_ZTi(tempZTi); } /* **************************************************************************************************************************** */ MDFloat (*ZTi)[4]; MDFloat (*ZTN)[4]; // Extraction de la position de l'effecteur terminal // .. ZTN = (MDFloat(*)[4])Skelet[_NO_OF_LINKS_-1].Get_ZTi(); Pn[0] = ZTN[0][3]; Pn[1] = ZTN[1][3]; Pn[2] = ZTN[2][3]; Pn[3] = 1.0; // Calcul de la Jacobienne (3 lignes) for (i=0; i<_NO_OF_LINKS_; i++) { // Caclul du vecteur reliant l'effecteur terminal aux différents repères (locaux) des segments du squelette : v = Pn - Pj // .. ZTi = (MDFloat(*)[4])Skelet[i].Get_ZTi(); Pj[0] = ZTi[0][3]; Pj[0] = ZTi[1][3]; Pj[0] = ZTi[2][3]; Pj[0] = 1.0; VectSub(Pn,Pj,v); // Extraction du vecteur de rotation suivant l'axe oX (1ere colonne) // .. ai[0] = ZTi[0][0]; ai[1] = ZTi[1][0]; ai[2] = ZTi[2][0]; ai[3] = 1.0; // Calcul du vacteur orthogonal au vecteur v et au vecteur de rotation suivant l'axe oX : bi = ai X v // .. VectProd(ai,v,bi); // Calcul de la 1ere colonne de la Jacobienne (DDL : oX) : J[0][x]t = [bi[0],bi[1],bi[2],ai[0],ai[1],ai[2]] // .. J[i*3][0] = bi[0]; J[i*3][1] = bi[1]; J[i*3][2] = bi[2]; J[i*3][3] = ai[0]; J[i*3][4] = ai[1]; J[i*3][5] = ai[2]; // Extraction du vecteur de rotation suivant l'axe oY (2eme colonne) // .. ai[0] = ZTi[0][1]; ai[1] = ZTi[1][1]; ai[2] = ZTi[2][1]; ai[3] = 1.0; // Calcul du vacteur orthogonal au vecteur v et au vecteur de rotation suivant l'axe oY : bi = ai X v // .. VectProd(ai,v,bi); // Calcul de la 2eme colonne de la Jacobienne (DDL : oY) : J[1][x]t = [bi[0],bi[1],bi[2],ai[0],ai[1],ai[2]] // .. J[i*3+1][0] = bi[0]; J[i*3+1][1] = bi[1]; J[i*3+1][2] = bi[2]; J[i*3+1][3] = ai[0]; J[i*3+1][4] = ai[1]; J[i*3+1][5] = ai[2]; // Extraction du vecteur de rotation suivant l'axe oZ (3eme colonne) // .. ai[0] = ZTi[0][2]; ai[1] = ZTi[1][2]; ai[2] = ZTi[2][2]; ai[3] = 1.0; // Calcul du vacteur orthogonal au vecteur v et au vecteur de rotation suivant l'axe oZ : bi = ai X v // .. VectProd(ai,v,bi); // Calcul de la 3eme colonne de la Jacobienne (DDL : oZ) : J[2][x]t = [bi[0],bi[1],bi[2],ai[0],ai[1],ai[2]] // .. J[i*3+2][0] = bi[0]; J[i*3+2][1] = bi[1]; J[i*3+2][2] = bi[2]; J[i*3+2][3] = ai[0]; J[i*3+2][4] = ai[1]; J[i*3+2][5] = ai[2]; } FILE *f ; f = fopen ( "test.jac", "w" ) ;PrintJacobian(f,J); /* **************************************************************************************************************************** */ }
void ShaderManagerVulkan::BaseUpdateUniforms(int dirtyUniforms) { if (dirtyUniforms & DIRTY_TEXENV) { Uint8x3ToFloat4(ub_base.texEnvColor, gstate.texenvcolor); } if (dirtyUniforms & DIRTY_ALPHACOLORREF) { Uint8x3ToInt4_Alpha(ub_base.alphaColorRef, gstate.getColorTestRef(), gstate.getAlphaTestRef() & gstate.getAlphaTestMask()); } if (dirtyUniforms & DIRTY_ALPHACOLORMASK) { Uint8x3ToInt4_Alpha(ub_base.colorTestMask, gstate.getColorTestMask(), gstate.getAlphaTestMask()); } if (dirtyUniforms & DIRTY_FOGCOLOR) { Uint8x3ToFloat4(ub_base.fogColor, gstate.fogcolor); } if (dirtyUniforms & DIRTY_SHADERBLEND) { Uint8x3ToFloat4(ub_base.blendFixA, gstate.getFixA()); Uint8x3ToFloat4(ub_base.blendFixB, gstate.getFixB()); } if (dirtyUniforms & DIRTY_TEXCLAMP) { const float invW = 1.0f / (float)gstate_c.curTextureWidth; const float invH = 1.0f / (float)gstate_c.curTextureHeight; const int w = gstate.getTextureWidth(0); const int h = gstate.getTextureHeight(0); const float widthFactor = (float)w * invW; const float heightFactor = (float)h * invH; // First wrap xy, then half texel xy (for clamp.) const float texclamp[4] = { widthFactor, heightFactor, invW * 0.5f, invH * 0.5f, }; const float texclampoff[2] = { gstate_c.curTextureXOffset * invW, gstate_c.curTextureYOffset * invH, }; CopyFloat4(ub_base.texClamp, texclamp); CopyFloat2(ub_base.texClampOffset, texclampoff); } if (dirtyUniforms & DIRTY_PROJMATRIX) { Matrix4x4 flippedMatrix; memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float)); const bool invertedY = gstate_c.vpHeight < 0; if (invertedY) { flippedMatrix[1] = -flippedMatrix[1]; flippedMatrix[5] = -flippedMatrix[5]; flippedMatrix[9] = -flippedMatrix[9]; flippedMatrix[13] = -flippedMatrix[13]; } const bool invertedX = gstate_c.vpWidth < 0; if (invertedX) { flippedMatrix[0] = -flippedMatrix[0]; flippedMatrix[4] = -flippedMatrix[4]; flippedMatrix[8] = -flippedMatrix[8]; flippedMatrix[12] = -flippedMatrix[12]; } ConvertProjMatrixToVulkan(flippedMatrix, invertedX, invertedY); CopyMatrix4x4(ub_base.proj, flippedMatrix.getReadPtr()); } if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) { Matrix4x4 proj_through; proj_through.setOrthoVulkan(0.0f, gstate_c.curRTWidth, 0, gstate_c.curRTHeight, 0, 1); CopyMatrix4x4(ub_base.proj_through, proj_through.getReadPtr()); } // Transform if (dirtyUniforms & DIRTY_WORLDMATRIX) { ConvertMatrix4x3To4x4(ub_base.world, gstate.worldMatrix); } if (dirtyUniforms & DIRTY_VIEWMATRIX) { ConvertMatrix4x3To4x4(ub_base.view, gstate.viewMatrix); } if (dirtyUniforms & DIRTY_TEXMATRIX) { ConvertMatrix4x3To4x4(ub_base.tex, gstate.tgenMatrix); } // Combined two small uniforms if (dirtyUniforms & (DIRTY_FOGCOEF | DIRTY_STENCILREPLACEVALUE)) { float fogcoef_stencil[3] = { getFloat24(gstate.fog1), getFloat24(gstate.fog2), (float)gstate.getStencilTestRef() }; if (my_isinf(fogcoef_stencil[1])) { // not really sure what a sensible value might be. fogcoef_stencil[1] = fogcoef_stencil[1] < 0.0f ? -10000.0f : 10000.0f; } else if (my_isnan(fogcoef_stencil[1])) { // Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988 // Just put the fog far away at a large finite distance. // Infinities and NaNs are rather unpredictable in shaders on many GPUs // so it's best to just make it a sane calculation. fogcoef_stencil[0] = 100000.0f; fogcoef_stencil[1] = 1.0f; } #ifndef MOBILE_DEVICE else if (my_isnanorinf(fogcoef_stencil[1]) || my_isnanorinf(fogcoef_stencil[0])) { ERROR_LOG_REPORT_ONCE(fognan, G3D, "Unhandled fog NaN/INF combo: %f %f", fogcoef_stencil[0], fogcoef_stencil[1]); } #endif CopyFloat3(ub_base.fogCoef_stencil, fogcoef_stencil); } // Texturing if (dirtyUniforms & DIRTY_UVSCALEOFFSET) { const float invW = 1.0f / (float)gstate_c.curTextureWidth; const float invH = 1.0f / (float)gstate_c.curTextureHeight; const int w = gstate.getTextureWidth(0); const int h = gstate.getTextureHeight(0); const float widthFactor = (float)w * invW; const float heightFactor = (float)h * invH; static const float rescale[4] = { 1.0f, 2 * 127.5f / 128.f, 2 * 32767.5f / 32768.f, 1.0f }; const float factor = rescale[(gstate.vertType & GE_VTYPE_TC_MASK) >> GE_VTYPE_TC_SHIFT]; float uvscaleoff[4]; switch (gstate.getUVGenMode()) { case GE_TEXMAP_TEXTURE_COORDS: // Not sure what GE_TEXMAP_UNKNOWN is, but seen in Riviera. Treating the same as GE_TEXMAP_TEXTURE_COORDS works. case GE_TEXMAP_UNKNOWN: if (g_Config.bPrescaleUV) { // We are here but are prescaling UV in the decoder? Let's do the same as in the other case // except consider *Scale and *Off to be 1 and 0. uvscaleoff[0] = widthFactor; uvscaleoff[1] = heightFactor; uvscaleoff[2] = 0.0f; uvscaleoff[3] = 0.0f; } else { uvscaleoff[0] = gstate_c.uv.uScale * factor * widthFactor; uvscaleoff[1] = gstate_c.uv.vScale * factor * heightFactor; uvscaleoff[2] = gstate_c.uv.uOff * widthFactor; uvscaleoff[3] = gstate_c.uv.vOff * heightFactor; } break; // These two work the same whether or not we prescale UV. case GE_TEXMAP_TEXTURE_MATRIX: // We cannot bake the UV coord scale factor in here, as we apply a matrix multiplication // before this is applied, and the matrix multiplication may contain translation. In this case // the translation will be scaled which breaks faces in Hexyz Force for example. // So I've gone back to applying the scale factor in the shader. uvscaleoff[0] = widthFactor; uvscaleoff[1] = heightFactor; uvscaleoff[2] = 0.0f; uvscaleoff[3] = 0.0f; break; case GE_TEXMAP_ENVIRONMENT_MAP: // In this mode we only use uvscaleoff to scale to the texture size. uvscaleoff[0] = widthFactor; uvscaleoff[1] = heightFactor; uvscaleoff[2] = 0.0f; uvscaleoff[3] = 0.0f; break; default: ERROR_LOG_REPORT(G3D, "Unexpected UV gen mode: %d", gstate.getUVGenMode()); } CopyFloat4(ub_base.uvScaleOffset, uvscaleoff); } if (dirtyUniforms & DIRTY_DEPTHRANGE) { float viewZScale = gstate.getViewportZScale(); float viewZCenter = gstate.getViewportZCenter(); float viewZInvScale; // We had to scale and translate Z to account for our clamped Z range. // Therefore, we also need to reverse this to round properly. // // Example: scale = 65535.0, center = 0.0 // Resulting range = -65535 to 65535, clamped to [0, 65535] // gstate_c.vpDepthScale = 2.0f // gstate_c.vpZOffset = -1.0f // // The projection already accounts for those, so we need to reverse them. // // Additionally, D3D9 uses a range from [0, 1]. We double and move the center. viewZScale *= (1.0f / gstate_c.vpDepthScale) * 2.0f; viewZCenter -= 65535.0f * gstate_c.vpZOffset + 32768.5f; if (viewZScale != 0.0) { viewZInvScale = 1.0f / viewZScale; } else { viewZInvScale = 0.0; } float data[4] = { viewZScale, viewZCenter, viewZCenter, viewZInvScale }; CopyFloat4(ub_base.depthRange, data); } }