int CTransparencyRenderer::SplitPoly (tTranspPoly *item, int nDepth) { tTranspPoly split [2]; CFloatVector vSplit; tRgbaColorf color; int i, l, i0, i1, i2, i3, nMinLen = 0x7fff, nMaxLen = 0; float z, zMin, zMax, *c, *c0, *c1; split [0] = split [1] = *item; for (i = i0 = 0; i < split [0].nVertices; i++) { l = split [0].sideLength [i]; if (nMaxLen < l) { nMaxLen = l; i0 = i; } if (nMinLen > l) nMinLen = l; } if ((nDepth > 1) || !nMaxLen || (nMaxLen < 10) || ((nMaxLen <= 30) && ((split [0].nVertices == 3) || (nMaxLen <= nMinLen / 2 * 3)))) { for (i = 0, zMax = 0, zMin = 1e30f; i < split [0].nVertices; i++) { z = split [0].vertices [i][Z]; if (zMax < z) zMax = z; if (zMin > z) zMin = z; } #if TI_POLY_CENTER return Add (item->bmP ? riTexPoly : riFlatPoly, item, sizeof (*item), F2X (zMax), F2X ((zMax + zMin) / 2)); #else return Add (item->bmP ? riTexPoly : riFlatPoly, item, sizeof (*item), F2X (zMax), F2X (zMin)); #endif } if (split [0].nVertices == 3) { i1 = (i0 + 1) % 3; vSplit = CFloatVector::Avg(split [0].vertices [i0], split [0].vertices [i1]); split [0].vertices [i0] = split [1].vertices [i1] = vSplit; split [0].sideLength [i0] = split [1].sideLength [i0] = nMaxLen / 2; if (split [0].bmP) { split [0].texCoord [i0].v.u = split [1].texCoord [i1].v.u = (split [0].texCoord [i1].v.u + split [0].texCoord [i0].v.u) / 2; split [0].texCoord [i0].v.v = split [1].texCoord [i1].v.v = (split [0].texCoord [i1].v.v + split [0].texCoord [i0].v.v) / 2; } if (split [0].nColors == 3) { for (i = 4, c = reinterpret_cast<float*> (&color, c0 = reinterpret_cast<float*> (split [0].color + i0), c1 = reinterpret_cast<float*> (split [0].color + i1); i; i--) *c++ = (*c0++ + *c1++) / 2; split [0].color [i0] = split [1].color [i1] = color; } }
//------------------------------------------------------------------------------------------------- void SmokeGrid::set_density_src(int dens_src_power) { FVal POSIT = F2X(transVal(-20, 40, dens_src_power)); for (int I = 5; I <= N-4; I++) for (int J = 1; J <= 3; J++) { dens_src[I][J] = POSIT; } }
void SmokeGrid::set_velocity_src(int v_up, int) { FVal UP = F2X(transVal(0, 8, v_up)); for (int I = 3; I <= N-2; I++) for (int J = 20; J <= N-10; J++) { v[I][J] = UP; } }
fix CParticle::Drag (void) { if ((m_nType == BUBBLE_PARTICLES) || (m_nType == FIRE_PARTICLES)) return I2X (1); // constant speed else if (m_nType == WATERFALL_PARTICLES) { float h = 4.0f - 3.0f * m_decay; h *= h; return F2X (h); } else return I2X (1); //F2X (m_decay); // decelerate }
void DoReactorSmoke (CObject *objP) { int h = -1, nObject, nSmoke, nShields = 0, nParts; CFixVector vDir, vPos; nObject = objP->Index (); if (!(SHOW_SMOKE && gameOpts->render.particles.bRobots)) { if (particleManager.GetObjectSystem (nObject) >= 0) KillObjectSmoke (nObject); return; } if ((objP->info.xShields < 0) || (objP->info.nFlags & (OF_SHOULD_BE_DEAD | OF_DESTROYED))) nParts = 0; else { nShields = X2IR (gameData.bots.info [gameStates.app.bD1Mission][objP->info.nId].strength); h = nShields ? X2IR (objP->info.xShields) * 100 / nShields : 0; } if (h < 0) h = 0; nParts = 10 - h / 10; if (nParts > 0) { nParts = REACTOR_MAX_PARTS; if (0 > (nSmoke = particleManager.GetObjectSystem (nObject))) { //PrintLog ("creating robot %d smoke\n", nObject); nSmoke = particleManager.Create (&objP->info.position.vPos, NULL, NULL, objP->info.nSegment, 1, nParts, F2X (-4.0), -1, 1, BOT_PART_LIFE * 2, BOT_PART_SPEED, SMOKE_PARTICLES, nObject, smokeColors, 1, -1); if (nSmoke < 0) return; particleManager.SetObjectSystem (nObject, nSmoke); } else { particleManager.SetScale (nSmoke, F2X (-4.0)); particleManager.SetDensity (nSmoke, nParts, -1); vDir[X] = d_rand () - I2X (1) / 4; vDir[Y] = d_rand () - I2X (1) / 4; vDir[Z] = d_rand () - I2X (1) / 4; CFixVector::Normalize (vDir); vPos = objP->info.position.vPos + vDir * (-objP->info.xSize / 2); particleManager.SetPos (nSmoke, &vPos, NULL, objP->info.nSegment); } } else KillObjectSmoke (nObject); }
void DoReactorSmoke (tObject *objP) { int h = -1, i, nShields = 0, nParts; vmsVector vDir, vPos; i = OBJ_IDX (objP); if (!(SHOW_SMOKE && gameOpts->render.smoke.bRobots)) { if (gameData.smoke.objects [i] >= 0) KillObjectSmoke (i); return; } if ((objP->info.xShields < 0) || (objP->info.nFlags & (OF_SHOULD_BE_DEAD | OF_DESTROYED))) nParts = 0; else { nShields = X2IR (gameData.bots.info [gameStates.app.bD1Mission][objP->info.nId].strength); h = nShields ? X2IR (objP->info.xShields) * 100 / nShields : 0; } if (h < 0) h = 0; nParts = 10 - h / 10; if (nParts > 0) { nParts = REACTOR_MAX_PARTS; if (gameData.smoke.objects [i] < 0) { //PrintLog ("creating robot %d smoke\n", i); SetSmokeObject (i, CreateSmoke (&objP->info.position.vPos, NULL, NULL, objP->info.nSegment, 1, nParts, F2X (-4.0), -1, 1, BOT_PART_LIFE * 2, BOT_PART_SPEED, SMOKE_PARTICLES, i, smokeColors, 1, -1)); } else { SetSmokePartScale (gameData.smoke.objects [i], F2X (-4.0)); SetSmokeDensity (gameData.smoke.objects [i], nParts, -1); vDir[X] = d_rand () - F1_0 / 4; vDir[Y] = d_rand () - F1_0 / 4; vDir[Z] = d_rand () - F1_0 / 4; vmsVector::Normalize(vDir); vPos = objP->info.position.vPos + vDir * (-objP->info.xSize / 2); SetSmokePos (gameData.smoke.objects [i], &vPos, NULL, objP->info.nSegment); } } else KillObjectSmoke (i); }
int RenderWeaponCorona (CObject *objP, tRgbaColorf *colorP, float alpha, fix xOffset, float fScale, int bSimple, int bViewerOffset, int bDepthSort) { if (!SHOW_OBJ_FX) return 0; if (SHOW_SHADOWS && (gameStates.render.nShadowPass != 1)) return 0; if ((objP->info.nType == OBJ_WEAPON) && (objP->info.renderType == RT_POLYOBJ)) RenderLaserCorona (objP, colorP, alpha, fScale); else if (gameOpts->render.coronas.bShots && LoadCorona ()) { fix xSize; tRgbaColorf color; static tTexCoord2f tcCorona [4] = {{{0,0}},{{1,0}},{{1,1}},{{0,1}}}; CFixVector vPos = objP->info.position.vPos; xSize = (fix) (WeaponBlobSize (objP->info.nId) * F2X (fScale)); if (xOffset) { if (bViewerOffset) { CFixVector o = gameData.render.mine.viewerEye - vPos; CFixVector::Normalize (o); vPos += o * xOffset; } else vPos += objP->info.position.mOrient.FVec () * xOffset; } if (xSize < I2X (1)) xSize = I2X (1); color.alpha = alpha; alpha = coronaIntensities [gameOpts->render.coronas.nObjIntensity] / 2; color.red = colorP->red * alpha; color.green = colorP->green * alpha; color.blue = colorP->blue * alpha; return transparencyRenderer.AddSprite (bmpCorona, vPos, &color, FixMulDiv (xSize, bmpCorona->Width (), bmpCorona->Height ()), xSize, 0, LIGHTTRAIL_BLENDMODE, 3); } return 0; }
int CParticle::Update (int nCurTime) { int j, nRad; short nSegment; fix t, dot; CFixVector vPos, drift; fix drag = (m_nType == BUBBLE_PARTICLES) ? I2X (1) : F2X ((float) m_nLife / (float) m_nTTL); if ((m_nLife <= 0) /*|| (m_color [0].alpha < 0.01f)*/) return 0; t = nCurTime - m_nMoved; if (m_nDelay > 0) m_nDelay -= t; else { vPos = m_vPos; drift = m_vDrift; if ((m_nType == SMOKE_PARTICLES) /*|| (m_nType == BUBBLE_PARTICLES)*/) { drift [X] = ChangeDir (drift [X]); drift [Y] = ChangeDir (drift [Y]); drift [Z] = ChangeDir (drift [Z]); } for (j = 0; j < 2; j++) { if (t < 0) t = -t; m_vPos = vPos + drift * t; //(I2X (t) / 1000); if (m_bHaveDir) { CFixVector vi = drift, vj = m_vDir; CFixVector::Normalize (vi); CFixVector::Normalize (vj); // if (CFixVector::Dot (drift, m_vDir) < 0) if (CFixVector::Dot (vi, vj) < 0) drag = -drag; // VmVecScaleInc (&drift, &m_vDir, drag); m_vPos += m_vDir * drag; } if ((m_nType == BUBBLE_PARTICLES) || (m_nTTL - m_nLife > I2X (1) / 16)) { nSegment = FindSegByPos (m_vPos, m_nSegment, 0, 0, 1); if (nSegment < 0) { #if DBG if (m_nSegment == nDbgSeg) nSegment = FindSegByPos (m_vPos, m_nSegment, 1, 0, 1); #endif nSegment = FindSegByPos (m_vPos, m_nSegment, 0, 1, 1); if (nSegment < 0) return 0; } if ((m_nType == BUBBLE_PARTICLES) && (SEGMENTS [nSegment].m_nType != SEGMENT_IS_WATER)) return 0; m_nSegment = nSegment; } if (gameOpts->render.particles.bCollisions && CollideWithWall ()) { //Reflect the particle if (m_nType == BUBBLE_PARTICLES) return 0; if (j) return 0; else if (!(dot = CFixVector::Dot (drift, *wallNorm))) return 0; else { drift = m_vDrift + *wallNorm * (-2 * dot); //VmVecScaleAdd (&m_vPos, &vPos, &drift, 2 * t); m_nBounce = 3; continue; } } else if (m_nBounce) m_nBounce--; else { break; } } m_vDrift = drift; if (m_nTTL >= 0) { #if SMOKE_SLOWMO m_nLife -= (int) (t / gameStates.gameplay.slowmo [0].fSpeed); #else m_nLife -= t; #endif if ((m_nType == SMOKE_PARTICLES) && (nRad = m_nRad)) { if (m_bBlowUp) { if (m_nWidth >= nRad) m_nRad = 0; else { m_nWidth += nRad / 10 / m_bBlowUp; m_nHeight += nRad / 10 / m_bBlowUp; if (m_nWidth > nRad) m_nWidth = nRad; if (m_nHeight > nRad) m_nHeight = nRad; m_color [0].alpha *= (1.0f + 0.0725f / m_bBlowUp); if (m_color [0].alpha > 1) m_color [0].alpha = 1; } } else { if (m_nWidth <= nRad) m_nRad = 0; else { m_nRad += nRad / 5; m_color [0].alpha *= 1.0725f; if (m_color [0].alpha > 1) m_color [0].alpha = 1; } } } } } m_nMoved = nCurTime; return 1; }
void RenderLaserCorona (CObject *objP, tRgbaColorf *colorP, float alpha, float fScale) { if (!SHOW_OBJ_FX) return; if (SHOW_SHADOWS && (gameStates.render.nShadowPass != 1)) return; if (gameOpts->render.coronas.bShots && LoadGlare ()) { tHitbox* phb = &gameData.models.hitboxes [objP->rType.polyObjInfo.nModel].hitboxes [0]; float fLength = X2F (phb->vMax [Z] - phb->vMin [Z]) / 2; tRgbaColorf color; static CFloatVector vEye = CFloatVector::ZERO; colorP->alpha = alpha; float fScale = coronaIntensities [gameOpts->render.coronas.nObjIntensity] / 2; color = *colorP; colorP = &color; color.red *= fScale; color.green *= fScale; color.blue *= fScale; bmpGlare->SetColor (colorP); ogl.RenderSprite (bmpGlare, objP->info.position.vPos + objP->info.position.mOrient.FVec () * (F2X (fLength - 0.5f)), I2X (1), I2X (1), alpha, LIGHTTRAIL_BLENDMODE, 1); bmpGlare->SetColor (NULL); } }
void DoCountdownFrame (void) { fix oldTime; int fc, h, xScale; static fix cdtFrameTime; if (!gameData.reactor.bDestroyed) { cdtFrameTime = 0; return; } cdtFrameTime += gameData.time.xRealFrame; if (gameStates.limitFPS.bCountDown && !gameStates.app.tick40fps.bTick) return; if (!IS_D2_OEM && !IS_MAC_SHARE && !IS_SHAREWARE) { // get countdown in OEM and SHAREWARE only // On last level, we don't want a countdown. if ((gameData.missions.nCurrentMission == gameData.missions.nBuiltinMission) && (gameData.missions.nCurrentLevel == gameData.missions.nLastLevel)) { if (!IsMultiGame) return; if (gameData.app.nGameMode & GM_MULTI_ROBOTS) return; } } // Control center destroyed, rock the CPlayerData's ship. fc = gameData.reactor.countdown.nSecsLeft; if (fc > 16) fc = 16; // At Trainee, decrease rocking of ship by 4x. xScale = 1; if (gameStates.app.nDifficultyLevel == 0) xScale = 4; h = I2X (3) / 16 + (I2X (16 - fc)) / 32; gameData.objs.consoleP->mType.physInfo.rotVel [X] += (FixMul (d_rand () - 16384, h)) / xScale; gameData.objs.consoleP->mType.physInfo.rotVel [Z] += (FixMul (d_rand () - 16384, h)) / xScale; // Hook in the rumble sound effect here. oldTime = gameData.reactor.countdown.nTimer; if (!TimeStopped ()) gameData.reactor.countdown.nTimer -= cdtFrameTime; if (IsMultiGame && NetworkIAmMaster ()) MultiSendCountdown (); cdtFrameTime = 0; gameData.reactor.countdown.nSecsLeft = X2I (gameData.reactor.countdown.nTimer + I2X (7) / 8); if ((oldTime > COUNTDOWN_VOICE_TIME) && (gameData.reactor.countdown.nTimer <= COUNTDOWN_VOICE_TIME)) audio.PlaySound (SOUND_COUNTDOWN_13_SECS, SOUNDCLASS_GENERIC, I2X (3)); if (X2I (oldTime + I2X (7) / 8) != gameData.reactor.countdown.nSecsLeft) { if ((gameData.reactor.countdown.nSecsLeft >= 0) && (gameData.reactor.countdown.nSecsLeft < 10)) audio.PlaySound ((short) (SOUND_COUNTDOWN_0_SECS + gameData.reactor.countdown.nSecsLeft), SOUNDCLASS_GENERIC, I2X (3)); if (gameData.reactor.countdown.nSecsLeft == gameData.reactor.countdown.nTotalTime - 1) audio.PlaySound (SOUND_COUNTDOWN_29_SECS, SOUNDCLASS_GENERIC, I2X (3)); } if (gameData.reactor.countdown.nTimer > 0) { fix size = (I2X (gameData.reactor.countdown.nTotalTime) - gameData.reactor.countdown.nTimer) / F2X (0.65); fix oldSize = (I2X (gameData.reactor.countdown.nTotalTime) - oldTime) / F2X (0.65); if ((size != oldSize) && (gameData.reactor.countdown.nSecsLeft < gameData.reactor.countdown.nTotalTime - 5)) // Every 2 seconds! audio.PlaySound (SOUND_CONTROL_CENTER_WARNING_SIREN, SOUNDCLASS_GENERIC, I2X (3)); } else { int flashValue = X2I (-gameData.reactor.countdown.nTimer * (64 / 4)); // 4 seconds to total whiteness if (oldTime > 0) audio.PlaySound (SOUND_MINE_BLEW_UP); paletteManager.SetEffect (flashValue, flashValue, flashValue); if (paletteManager.BlueEffect () >= 64) { CCanvas::SetCurrent (NULL); CCanvas::Current ()->Clear (RGBA_PAL2 (31,31,31)); //make screen all white to match palette effect paletteManager.ResetEffect (); //restore palette for death message DoPlayerDead (); //kill_player (); } } }
void RenderSide (CSegment *segP, short nSide) { CSide *sideP = segP->m_sides + nSide; tFaceProps props; #if LIGHTMAPS #define LMAP_SIZE (1.0 / 16.0) static tUVL uvl_lMaps [4] = { {F2X (LMAP_SIZE), F2X (LMAP_SIZE), 0}, {F2X (1.0 - LMAP_SIZE), F2X (LMAP_SIZE), 0}, {F2X (1.0 - LMAP_SIZE), F2X (1.0 - LMAP_SIZE), 0}, {F2X (LMAP_SIZE), F2X (1.0 - LMAP_SIZE), 0} }; #endif props.segNum = segP->Index (); props.sideNum = nSide; #if DBG if ((props.segNum == nDbgSeg) && ((nDbgSide < 0) || (props.sideNum == nDbgSide))) segP = segP; #endif props.widFlags = segP->IsDoorWay (props.sideNum, NULL); if (!(gameOpts->render.debug.bWalls || IsMultiGame) && IS_WALL (segP->WallNum (props.sideNum))) return; switch (gameStates.render.nType) { case -1: if (!(props.widFlags & WID_RENDER_FLAG) && (SEGMENTS [props.segNum].m_nType < SEGMENT_IS_WATER)) //if (WALL_IS_DOORWAY(segP, props.sideNum) == WID_NO_WALL) return; break; case 0: if (segP->m_children [props.sideNum] >= 0) //&& IS_WALL (WallNumP (segP, props.sideNum))) return; break; case 1: if (!IS_WALL (segP->WallNum (props.sideNum))) return; break; case 2: if ((SEGMENTS [props.segNum].m_nType < SEGMENT_IS_WATER) && (SEGMENTS [props.segNum].m_owner < 1)) return; break; case 3: if ((IsLight (sideP->m_nBaseTex) || (sideP->m_nOvlTex && IsLight (sideP->m_nOvlTex)))) RenderCorona (props.segNum, props.sideNum, 1, 20); return; } #if LIGHTMAPS if (gameStates.render.bDoLightmaps) { float Xs = 8; float h = 0.5f / (float) Xs; props.uvl_lMaps [0].u = props.uvl_lMaps [0].v = props.uvl_lMaps [1].v = props.uvl_lMaps [3].u = F2X (h); props.uvl_lMaps [1].u = props.uvl_lMaps [2].u = props.uvl_lMaps [2].v = props.uvl_lMaps [3].v = F2X (1-h); } #endif props.nBaseTex = sideP->m_nBaseTex; props.nOvlTex = sideP->m_nOvlTex; props.nOvlOrient = sideP->m_nOvlOrient; // ========== Mark: Here is the change...beginning here: ========== #if LIGHTMAPS if (gameStates.render.bDoLightmaps) { memcpy (props.uvl_lMaps, uvl_lMaps, sizeof (tUVL) * 4); #if LMAP_LIGHTADJUST props.uvls [0].l = props.uvls [1].l = props.uvls [2].l = props.uvls [3].l = I2X (1) / 2; # endif } #endif #if DBG //convenient place for a debug breakpoint if (props.segNum == nDbgSeg && props.sideNum == nDbgSide) props.segNum = props.segNum; if (props.nBaseTex == nDbgBaseTex) props.segNum = props.segNum; if (props.nOvlTex == nDbgOvlTex) props.segNum = props.segNum; # if 0 else return; # endif #endif if (!FaceIsVisible (props.segNum, props.sideNum)) return; if (sideP->m_nType == SIDE_IS_QUAD) { props.vNormal = sideP->m_normals [0]; props.nVertices = 4; memcpy (props.uvls, sideP->m_uvls, sizeof (tUVL) * 4); memcpy (props.vp, SEGMENTS [props.segNum].Corners (props.sideNum), 4 * sizeof (ushort)); RenderFace (&props); } else { // new code // non-planar faces are still passed as quads to the renderer as it will render triangles (GL_TRIANGLE_FAN) anyway // just need to make sure the vertices come in the proper order depending of the the orientation of the two non-planar triangles props.vNormal = sideP->m_normals [0] + sideP->m_normals [1]; props.vNormal *= (I2X (1) / 2); props.nVertices = 4; if (sideP->m_nType == SIDE_IS_TRI_02) { memcpy (props.uvls, sideP->m_uvls, sizeof (tUVL) * 4); memcpy (props.vp, SEGMENTS [props.segNum].Corners (props.sideNum), 4 * sizeof (ushort)); RenderFace (&props); } else if (sideP->m_nType == SIDE_IS_TRI_13) { //just rendering the fan with vertex 1 instead of 0 memcpy (props.uvls + 1, sideP->m_uvls, sizeof (tUVL) * 3); props.uvls [0] = sideP->m_uvls [3]; memcpy (props.vp + 1, SEGMENTS [props.segNum].Corners (props.sideNum), 4 * sizeof (ushort)); props.vp [0] = props.vp [4]; RenderFace (&props); } else { Error("Illegal CSide nType in RenderSide, nType = %i, CSegment # = %i, CSide # = %i\n", sideP->m_nType, segP->Index (), props.sideNum); return; } } }
void CLightmapManager::BuildAll (int nFace) { CSide* sideP; int nLastFace; int i; float h; int nBlackLightmaps = 0, nWhiteLightmaps = 0; gameStates.render.nState = 0; h = 1.0f / float (LM_W - 1); for (i = 0; i < LM_W; i++) m_data.nOffset [i] = F2X (i * h); InitVertColorData (m_data.vcd); m_data.vcd.vertPosP = &m_data.vcd.vertPos; m_data.vcd.fMatShininess = 4; #if 0 if (gameStates.app.bMultiThreaded) nLastFace = nFace ? gameData.segs.nFaces : gameData.segs.nFaces / 2; else #endif INIT_PROGRESS_LOOP (nFace, nLastFace, gameData.segs.nFaces); if (nFace <= 0) { CreateSpecial (m_data.texColor, 0, 0); CreateSpecial (m_data.texColor, 1, 255); m_list.nLightmaps = 2; } //Next Go through each surface and create a lightmap for it. for (m_data.faceP = FACES.faces + nFace; nFace < nLastFace; nFace++, m_data.faceP++) { #if DBG if ((m_data.faceP->nSegment == nDbgSeg) && ((nDbgSide < 0) || (m_data.faceP->nSide == nDbgSide))) nDbgSeg = nDbgSeg; #endif if (SEGMENTS [m_data.faceP->nSegment].m_nType == SEGMENT_IS_SKYBOX) continue; sideP = SEGMENTS [m_data.faceP->nSegment].m_sides + m_data.faceP->nSide; memcpy (m_data.sideVerts, m_data.faceP->index, sizeof (m_data.sideVerts)); m_data.nType = (sideP->m_nType == SIDE_IS_QUAD) || (sideP->m_nType == SIDE_IS_TRI_02); m_data.vNormal = CFixVector::Avg (sideP->m_normals [0], sideP->m_normals [1]); CFixVector::Normalize (m_data.vNormal); m_data.vcd.vertNorm.Assign (m_data.vNormal); CFloatVector3::Normalize (m_data.vcd.vertNorm); m_data.nColor = 0; memset (m_data.texColor, 0, LM_W * LM_H * sizeof (tRgbColorb)); if (!RunRenderThreads (rtLightmap)) Build (-1); #if DBG if ((m_data.faceP->nSegment == nDbgSeg) && ((nDbgSide < 0) || (m_data.faceP->nSide == nDbgSide))) nDbgSeg = nDbgSeg; #endif if (m_data.nColor == 1) { m_data.faceP->nLightmap = 0; nBlackLightmaps++; } else if (m_data.nColor == 2) { m_data.faceP->nLightmap = 1; nWhiteLightmaps++; } else { Copy (m_data.texColor, m_list.nLightmaps); m_data.faceP->nLightmap = m_list.nLightmaps++; } } }
void CCamera::GetUVL (CSegFace *faceP, tUVL *uvlP, tTexCoord2f *texCoordP, CFloatVector3 *vertexP) { int i2, i3, nType = 0, nScale = 2 - gameOpts->render.cameras.bHires; if (gameStates.render.bTriangleMesh) { if ((nType = faceP->nType == SIDE_IS_TRI_13)) { i2 = 4; } else { i2 = 2; } i3 = 5; } else { i2 = 2; i3 = 3; } #if !DBG if (m_info.bHaveUVL) { if (uvlP) memcpy (uvlP, m_info.uvlList, sizeof (m_info.uvlList)); } else #endif { fix i; float duImage, dvImage, duFace, dvFace, du, dv,aFace, aImage; int xFlip, yFlip, rotLeft, rotRight; #if RENDER2TEXTURE int bHaveBuffer = HaveBuffer (1) == 1; int bFitToWall = m_info.bTeleport || gameOpts->render.cameras.bFitToWall; #endif if (uvlP) { rotLeft = (uvlP [1].u > uvlP [0].u); rotRight = (uvlP [1].u < uvlP [0].u); if (rotLeft) { yFlip = (uvlP [1].u < uvlP [2].u); xFlip = (uvlP [3].v > uvlP [1].v); } else if (rotRight) { yFlip = (uvlP [3].u < uvlP [0].u); xFlip = (uvlP [1].v > uvlP [3].v); } else { xFlip = (uvlP [2].u < uvlP [0].u); yFlip = (uvlP [1].v > uvlP [0].v); } dvFace = X2F (uvlP [1].v - uvlP [0].v); duFace = X2F (uvlP [2].u - uvlP [0].u); } else { rotLeft = (texCoordP [1].v.u < texCoordP [0].v.u); rotRight = (texCoordP [1].v.u > texCoordP [0].v.u); if (rotLeft) { yFlip = (texCoordP [1].v.u > texCoordP [i2].v.u); xFlip = (texCoordP [i3].v.v < texCoordP [1].v.v); } else if (rotRight) { yFlip = (texCoordP [i3].v.u > texCoordP [0].v.u); xFlip = (texCoordP [1].v.v < texCoordP [i3].v.v); } else { xFlip = (texCoordP [i2].v.u < texCoordP [0].v.u); yFlip = (texCoordP [1].v.v > texCoordP [0].v.v); } dvFace = (float) fabs (texCoordP [1].v.v - texCoordP [0].v.v); duFace = (float) fabs (texCoordP [i2].v.u - texCoordP [0].v.u); } du = dv = 0; if (bHaveBuffer) { duImage = (float) CCanvas::Current ()->Width () / (float) m_info.buffer.Width () / nScale; dvImage = (float) CCanvas::Current ()->Height () / (float) m_info.buffer.Height () / nScale; if (!bFitToWall) { aImage = (float) CCanvas::Current ()->Height () / (float) CCanvas::Current ()->Width (); if (vertexP) aFace = CFloatVector::Dist(*reinterpret_cast<CFloatVector*> (vertexP), *reinterpret_cast<CFloatVector*> (vertexP + 1)) / CFloatVector::Dist(*reinterpret_cast<CFloatVector*> (vertexP + 1), *reinterpret_cast<CFloatVector*> (vertexP + i2)); else aFace = dvFace / duFace; dv = (aImage - aFace) / (float) nScale; duImage -= du / nScale; dvImage -= dv; } } else { duImage = duFace; dvImage = dvFace; } if (m_info.bMirror) xFlip = !xFlip; if (uvlP) { uvlP [0].v = uvlP [3].v = F2X (yFlip ? dvImage : dv / nScale); uvlP [1].v = uvlP [2].v = F2X (yFlip ? dv / nScale : dvImage); uvlP [0].u = uvlP [1].u = F2X (xFlip ? duImage : du / nScale); uvlP [2].u = uvlP [3].u = F2X (xFlip ? du / nScale : duImage); for (i = 0; i < 4; i++) uvlP [i].l = I2X (1); if (rotRight) { for (i = 1; i < 5; i++) { m_info.uvlList [i - 1] = uvlP [i % 4]; } } else if (rotRight) { for (i = 0; i < 4; i++) { m_info.uvlList [i] = uvlP [(i + 1) % 4]; } } else memcpy (m_info.uvlList, uvlP, sizeof (m_info.uvlList)); } else { tTexCoord2f texCoord [6]; texCoord [0].v.v = texCoord [3].v.v = yFlip ? dvImage : dv; texCoord [1].v.v = texCoord [2].v.v = yFlip ? dv : dvImage; texCoord [0].v.u = texCoord [1].v.u = xFlip ? duImage : du / nScale; texCoord [2].v.u = texCoord [3].v.u = xFlip ? du / nScale : duImage; if (rotLeft) { tTexCoord2f h = texCoord [0]; texCoord [0] = texCoord [1]; texCoord [1] = texCoord [2]; texCoord [2] = texCoord [3]; texCoord [3] = h; } else if (rotRight) { tTexCoord2f h = texCoord [3]; texCoord [3] = texCoord [2]; texCoord [2] = texCoord [1]; texCoord [1] = texCoord [0]; texCoord [0] = h; } if (gameStates.render.bTriangleMesh) { if (nType) { texCoord [5] = texCoord [3]; texCoord [4] = texCoord [2]; texCoord [3] = texCoord [1]; texCoord [2] = texCoord [5]; } else { texCoord [5] = texCoord [3]; texCoord [4] = texCoord [2]; texCoord [3] = texCoord [0]; } } memcpy (m_info.texCoord, texCoord, sizeof (m_info.texCoord)); } m_info.bHaveUVL = 1; } }