mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-03-22 19:18:14 +05:00
* Fix split-screen UI wrong positioning on window resize In vertical split at window heights below 1080, ComputeTileScale's min-scale clamp (>= 1.0) prevented the SWF from scaling down to fit, cropping the bottom and causing repositionHud to shift HUD elements downward. Chat and Tooltips additionally applied an offset from ComputeSplitContentOffset that only produced correct values at the 1920x1080 design resolution. Override the scale for vertical split so the SWF fits the full window height when it is shorter than the movie. Remove the broken content offset from Chat and Tooltips -- the tile crop already positions the content correctly. * Fix gamma post-process in split-screen The gamma shader sampled the full backbuffer texture (UV 0..1) into each player's viewport, stretching the entire screen into every split region. Extended the shader constant buffer with per-viewport UV offset and scale so each pass samples only its own portion of the backbuffer. ComputeViewportForPlayer was hardcoded to top/bottom for 2 players, ignoring the vertical split setting. Rewrote it to read each player's m_iScreenSection directly, which already accounts for the split orientation preference. Secondary players have no Graphics menu and cannot change gamma. CachePlayerGammas now reads the primary player's setting and applies it uniformly to all viewports.
2253 lines
67 KiB
C++
2253 lines
67 KiB
C++
#include "stdafx.h"
|
|
#include "GameRenderer.h"
|
|
#include "ItemInHandRenderer.h"
|
|
#include "LevelRenderer.h"
|
|
#include "Frustum.h"
|
|
#include "FrustumCuller.h"
|
|
#include "Textures.h"
|
|
#include "Tesselator.h"
|
|
#include "ParticleEngine.h"
|
|
#include "SmokeParticle.h"
|
|
#include "WaterDropParticle.h"
|
|
#include "GameMode.h"
|
|
#include "CreativeMode.h"
|
|
#include "Lighting.h"
|
|
#include "Options.h"
|
|
#include "MultiplayerLocalPlayer.h"
|
|
#include "GuiParticles.h"
|
|
#include "MultiPlayerLevel.h"
|
|
#include "Chunk.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.entity.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.entity.player.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.item.enchantment.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.level.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.level.material.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.level.tile.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.level.chunk.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.level.biome.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.level.dimension.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.phys.h"
|
|
#include "..\Minecraft.World\System.h"
|
|
#include "..\Minecraft.World\FloatBuffer.h"
|
|
#include "..\Minecraft.World\ThreadName.h"
|
|
#include "..\Minecraft.World\SparseLightStorage.h"
|
|
#include "..\Minecraft.World\CompressedTileStorage.h"
|
|
#include "..\Minecraft.World\SparseDataStorage.h"
|
|
#include "..\Minecraft.World\JavaMath.h"
|
|
#include "..\Minecraft.World\Facing.h"
|
|
#include "..\Minecraft.World\MobEffect.h"
|
|
#include "..\Minecraft.World\IntCache.h"
|
|
#include "..\Minecraft.World\SmoothFloat.h"
|
|
#include "..\Minecraft.World\MobEffectInstance.h"
|
|
#include "..\Minecraft.World\Item.h"
|
|
#include "Camera.h"
|
|
#include "..\Minecraft.World\SoundTypes.h"
|
|
#include "HumanoidModel.h"
|
|
#include "..\Minecraft.World\Item.h"
|
|
#include "..\Minecraft.World\compression.h"
|
|
#include "PS3\PS3Extras\ShutdownManager.h"
|
|
#include "BossMobGuiInfo.h"
|
|
|
|
#include "TexturePackRepository.h"
|
|
#include "TexturePack.h"
|
|
#include "TextureAtlas.h"
|
|
#include "Common/PostProcesser.h"
|
|
|
|
bool GameRenderer::anaglyph3d = false;
|
|
int GameRenderer::anaglyphPass = 0;
|
|
|
|
#ifdef MULTITHREAD_ENABLE
|
|
C4JThread* GameRenderer::m_updateThread;
|
|
C4JThread::EventArray* GameRenderer::m_updateEvents;
|
|
bool GameRenderer::nearThingsToDo = false;
|
|
bool GameRenderer::updateRunning = false;
|
|
vector<byte *> GameRenderer::m_deleteStackByte;
|
|
vector<SparseLightStorage *> GameRenderer::m_deleteStackSparseLightStorage;
|
|
vector<CompressedTileStorage *> GameRenderer::m_deleteStackCompressedTileStorage;
|
|
vector<SparseDataStorage *> GameRenderer::m_deleteStackSparseDataStorage;
|
|
#endif
|
|
CRITICAL_SECTION GameRenderer::m_csDeleteStack;
|
|
|
|
ResourceLocation GameRenderer::RAIN_LOCATION = ResourceLocation(TN_ENVIRONMENT_RAIN);
|
|
ResourceLocation GameRenderer::SNOW_LOCATION = ResourceLocation(TN_ENVIRONMENT_SNOW);
|
|
|
|
GameRenderer::GameRenderer(Minecraft *mc)
|
|
{
|
|
// 4J - added this block of initialisers
|
|
renderDistance = static_cast<float>(16 * 16 >> mc->options->viewDistance);
|
|
_tick = 0;
|
|
hovered = nullptr;
|
|
thirdDistance = 4;
|
|
thirdDistanceO = 4;
|
|
thirdRotation = 0;
|
|
thirdRotationO = 0;
|
|
thirdTilt = 0;
|
|
thirdTiltO = 0;
|
|
|
|
accumulatedSmoothXO = 0;
|
|
accumulatedSmoothYO = 0;
|
|
tickSmoothXO = 0;
|
|
tickSmoothYO = 0;
|
|
lastTickA = 0;
|
|
|
|
cameraPos = Vec3::newPermanent(0.0f,0.0f,0.0f);
|
|
|
|
fovOffset = 0;
|
|
fovOffsetO = 0;
|
|
cameraRoll = 0;
|
|
cameraRollO = 0;
|
|
for( int i = 0; i < 4; i++ )
|
|
{
|
|
fov[i] = 0.0f;
|
|
oFov[i] = 0.0f;
|
|
tFov[i] = 0.0f;
|
|
}
|
|
isInClouds = false;
|
|
zoom = 1;
|
|
zoom_x = 0;
|
|
zoom_y = 0;
|
|
rainXa = nullptr;
|
|
rainZa = nullptr;
|
|
lastActiveTime = Minecraft::currentTimeMillis();
|
|
lastNsTime = 0;
|
|
random = new Random();
|
|
rainSoundTime = 0;
|
|
xMod = 0;
|
|
yMod = 0;
|
|
lb = MemoryTracker::createFloatBuffer(16);
|
|
fr = 0.0f;
|
|
fg = 0.0f;
|
|
fb = 0.0f;
|
|
fogBrO = 0.0f;
|
|
fogBr = 0.0f;
|
|
cameraFlip = 0;
|
|
_updateLightTexture = false;
|
|
blr = 0.0f;
|
|
blrt = 0.0f;
|
|
blg = 0.0f;
|
|
blgt = 0.0f;
|
|
|
|
darkenWorldAmount = 0.0f;
|
|
darkenWorldAmountO = 0.0f;
|
|
|
|
m_fov=70.0f;
|
|
|
|
// 4J Stu - Init these so they are setup before the tick
|
|
for( int i = 0; i < 4; i++ )
|
|
{
|
|
fov[i] = oFov[i] = 1.0f;
|
|
}
|
|
|
|
this->mc = mc;
|
|
itemInHandRenderer = nullptr;
|
|
|
|
// 4J-PB - set up the local players iteminhand renderers here - needs to be done with lighting enabled so that the render geometry gets compiled correctly
|
|
glEnable(GL_LIGHTING);
|
|
mc->localitemInHandRenderers[0] = new ItemInHandRenderer(mc);//itemInHandRenderer;
|
|
mc->localitemInHandRenderers[1] = new ItemInHandRenderer(mc);
|
|
mc->localitemInHandRenderers[2] = new ItemInHandRenderer(mc);
|
|
mc->localitemInHandRenderers[3] = new ItemInHandRenderer(mc);
|
|
glDisable(GL_LIGHTING);
|
|
|
|
// 4J - changes brought forward from 1.8.2
|
|
BufferedImage *img = new BufferedImage(16, 16, BufferedImage::TYPE_INT_RGB);
|
|
for( int i = 0; i < NUM_LIGHT_TEXTURES; i++ )
|
|
{
|
|
lightTexture[i] = mc->textures->getTexture(img); // 4J - changed to one light texture per level to support split screen
|
|
}
|
|
delete img;
|
|
#ifdef __PS3__
|
|
// we're using the RSX now to upload textures to vram, so we need the main ram textures allocated from io space
|
|
for(int i=0;i<NUM_LIGHT_TEXTURES;i++)
|
|
lightPixels[i] = intArray((int*)RenderManager.allocIOMem(16*16*sizeof(int)), 16*16);
|
|
#else
|
|
for(int i=0;i<NUM_LIGHT_TEXTURES;i++)
|
|
lightPixels[i] = intArray(16*16);
|
|
#endif
|
|
|
|
#ifdef MULTITHREAD_ENABLE
|
|
m_updateEvents = new C4JThread::EventArray(eUpdateEventCount, C4JThread::EventArray::e_modeAutoClear);
|
|
m_updateEvents->Set(eUpdateEventIsFinished);
|
|
|
|
InitializeCriticalSection(&m_csDeleteStack);
|
|
m_updateThread = new C4JThread(runUpdate, nullptr, "Chunk update");
|
|
#ifdef __PS3__
|
|
m_updateThread->SetPriority(THREAD_PRIORITY_ABOVE_NORMAL);
|
|
#endif// __PS3__
|
|
m_updateThread->SetProcessor(CPU_CORE_CHUNK_UPDATE);
|
|
m_updateThread->Run();
|
|
#endif
|
|
}
|
|
|
|
// 4J Stu Added to go with 1.8.2 change
|
|
GameRenderer::~GameRenderer()
|
|
{
|
|
if(rainXa != nullptr) delete [] rainXa;
|
|
if(rainZa != nullptr) delete [] rainZa;
|
|
}
|
|
|
|
void GameRenderer::tick(bool first) // 4J - add bFirst
|
|
{
|
|
tickFov();
|
|
tickLightTexture(); // 4J - change brought forward from 1.8.2
|
|
fogBrO = fogBr;
|
|
thirdDistanceO = thirdDistance;
|
|
thirdRotationO = thirdRotation;
|
|
thirdTiltO = thirdTilt;
|
|
fovOffsetO = fovOffset;
|
|
cameraRollO = cameraRoll;
|
|
|
|
if (mc->options->smoothCamera)
|
|
{
|
|
// update player view in tick() instead of render() to maintain
|
|
// camera movement regardless of FPS
|
|
float ss = mc->options->sensitivity * 0.6f + 0.2f;
|
|
float sens = (ss * ss * ss) * 8;
|
|
tickSmoothXO = smoothTurnX.getNewDeltaValue(accumulatedSmoothXO, 0.05f * sens);
|
|
tickSmoothYO = smoothTurnY.getNewDeltaValue(accumulatedSmoothYO, 0.05f * sens);
|
|
lastTickA = 0;
|
|
|
|
accumulatedSmoothXO = 0;
|
|
accumulatedSmoothYO = 0;
|
|
}
|
|
|
|
if (mc->cameraTargetPlayer == nullptr)
|
|
{
|
|
mc->cameraTargetPlayer = dynamic_pointer_cast<Mob>(mc->player);
|
|
}
|
|
|
|
float brr = mc->level->getBrightness(Mth::floor(mc->cameraTargetPlayer->x), Mth::floor(mc->cameraTargetPlayer->y), Mth::floor(mc->cameraTargetPlayer->z));
|
|
float whiteness = (3 - mc->options->viewDistance) / 3.0f;
|
|
float fogBrT = brr * (1 - whiteness) + whiteness;
|
|
fogBr += (fogBrT - fogBr) * 0.1f;
|
|
|
|
itemInHandRenderer->tick();
|
|
|
|
PIXBeginNamedEvent(0,"Rain tick");
|
|
tickRain();
|
|
PIXEndNamedEvent();
|
|
|
|
darkenWorldAmountO = darkenWorldAmount;
|
|
if (BossMobGuiInfo::darkenWorld)
|
|
{
|
|
darkenWorldAmount += 1.0f / (static_cast<float>(SharedConstants::TICKS_PER_SECOND) * 1);
|
|
if (darkenWorldAmount > 1)
|
|
{
|
|
darkenWorldAmount = 1;
|
|
}
|
|
BossMobGuiInfo::darkenWorld = false;
|
|
}
|
|
else if (darkenWorldAmount > 0)
|
|
{
|
|
darkenWorldAmount -= 1.0f / (static_cast<float>(SharedConstants::TICKS_PER_SECOND) * 4);
|
|
}
|
|
|
|
if( mc->player != mc->localplayers[ProfileManager.GetPrimaryPad()] ) return; // 4J added for split screen - only do rest of processing for once per frame
|
|
|
|
_tick++;
|
|
}
|
|
|
|
void GameRenderer::pick(float a)
|
|
{
|
|
if (mc->cameraTargetPlayer == nullptr) return;
|
|
if (mc->level == nullptr) return;
|
|
|
|
mc->crosshairPickMob = nullptr;
|
|
|
|
double range = mc->gameMode->getPickRange();
|
|
delete mc->hitResult;
|
|
MemSect(31);
|
|
mc->hitResult = mc->cameraTargetPlayer->pick(range, a);
|
|
MemSect(0);
|
|
|
|
// 4J - added - stop blocks right at the edge of the world from being pickable so we shouldn't be able to directly destroy or create anything there
|
|
if( mc->hitResult )
|
|
{
|
|
int maxxz = ( ( mc->level->chunkSource->m_XZSize / 2 ) * 16 ) - 2;
|
|
int minxz = ( -( mc->level->chunkSource->m_XZSize / 2 ) * 16 ) + 1;
|
|
|
|
// Don't select the tops of the very edge blocks, or the sides of the next blocks in
|
|
// 4J Stu - Only block the sides that are facing an outside block
|
|
int hitx = mc->hitResult->x;
|
|
int hitz = mc->hitResult->z;
|
|
int face = mc->hitResult->f;
|
|
if( face == Facing::WEST && hitx < 0 ) hitx -= 1;
|
|
if( face == Facing::EAST && hitx > 0 ) hitx += 1;
|
|
if( face == Facing::NORTH && hitz < 0 ) hitz -= 1;
|
|
if( face == Facing::SOUTH && hitz > 0 ) hitz += 1;
|
|
|
|
if( ( hitx < minxz ) || ( hitx > maxxz) ||
|
|
( hitz < minxz ) || ( hitz > maxxz) )
|
|
{
|
|
delete mc->hitResult;
|
|
mc->hitResult = nullptr;
|
|
}
|
|
}
|
|
|
|
double dist = range;
|
|
Vec3 *from = mc->cameraTargetPlayer->getPos(a);
|
|
|
|
if (mc->gameMode->hasFarPickRange())
|
|
{
|
|
dist = range = 6;
|
|
}
|
|
else
|
|
{
|
|
if (dist > 3) dist = 3;
|
|
range = dist;
|
|
}
|
|
|
|
if (mc->hitResult != nullptr)
|
|
{
|
|
dist = mc->hitResult->pos->distanceTo(from);
|
|
}
|
|
|
|
Vec3 *b = mc->cameraTargetPlayer->getViewVector(a);
|
|
Vec3 *to = from->add(b->x * range, b->y * range, b->z * range);
|
|
hovered = nullptr;
|
|
float overlap = 1;
|
|
vector<shared_ptr<Entity> > *objects = mc->level->getEntities(mc->cameraTargetPlayer, mc->cameraTargetPlayer->bb->expand(b->x * (range), b->y * (range), b->z * (range))->grow(overlap, overlap, overlap));
|
|
double nearest = dist;
|
|
|
|
for (auto& e : *objects )
|
|
{
|
|
if ( e == nullptr || !e->isPickable() ) continue;
|
|
|
|
float rr = e->getPickRadius();
|
|
AABB *bb = e->bb->grow(rr, rr, rr);
|
|
HitResult *p = bb->clip(from, to);
|
|
if (bb->contains(from))
|
|
{
|
|
if (0 < nearest || nearest == 0)
|
|
{
|
|
hovered = e;
|
|
nearest = 0;
|
|
}
|
|
}
|
|
else if (p != nullptr)
|
|
{
|
|
double dd = from->distanceTo(p->pos);
|
|
auto const riding = mc->cameraTargetPlayer->riding;
|
|
if (riding != nullptr && e == riding)
|
|
{
|
|
if (nearest == 0)
|
|
{
|
|
hovered = e;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hovered = e;
|
|
nearest = dd;
|
|
}
|
|
}
|
|
delete p;
|
|
}
|
|
|
|
if (hovered != nullptr)
|
|
{
|
|
if (nearest < dist || (mc->hitResult == nullptr))
|
|
{
|
|
if( mc->hitResult != nullptr )
|
|
delete mc->hitResult;
|
|
mc->hitResult = new HitResult(hovered);
|
|
if (hovered->instanceof(eTYPE_LIVINGENTITY))
|
|
{
|
|
mc->crosshairPickMob = dynamic_pointer_cast<LivingEntity>(hovered);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameRenderer::SetFovVal(float fov)
|
|
{
|
|
m_fov=fov;
|
|
}
|
|
|
|
float GameRenderer::GetFovVal()
|
|
{
|
|
return m_fov;
|
|
}
|
|
|
|
void GameRenderer::tickFov()
|
|
{
|
|
shared_ptr<LocalPlayer>player = dynamic_pointer_cast<LocalPlayer>(mc->cameraTargetPlayer);
|
|
|
|
int playerIdx = player ? player->GetXboxPad() : 0;
|
|
tFov[playerIdx] = player->getFieldOfViewModifier();
|
|
|
|
oFov[playerIdx] = fov[playerIdx];
|
|
fov[playerIdx] += (tFov[playerIdx] - fov[playerIdx]) * 0.5f;
|
|
|
|
if (fov[playerIdx] > 1.5f) fov[playerIdx] = 1.5f;
|
|
if (fov[playerIdx] < 0.1f) fov[playerIdx] = 0.1f;
|
|
}
|
|
|
|
float GameRenderer::getFov(float a, bool applyEffects)
|
|
{
|
|
if (cameraFlip > 0 ) return 90;
|
|
|
|
shared_ptr<LocalPlayer> player = dynamic_pointer_cast<LocalPlayer>(mc->cameraTargetPlayer);
|
|
int playerIdx = player ? player->GetXboxPad() : 0;
|
|
float fov = m_fov;//70;
|
|
if (applyEffects)
|
|
{
|
|
fov += mc->options->fov * 40;
|
|
fov *= oFov[playerIdx] + (this->fov[playerIdx] - oFov[playerIdx]) * a;
|
|
}
|
|
if (player->getHealth() <= 0)
|
|
{
|
|
float duration = player->deathTime + a;
|
|
|
|
fov /= ((1 - 500 / (duration + 500)) * 2.0f + 1);
|
|
}
|
|
|
|
int t = Camera::getBlockAt(mc->level, player, a);
|
|
if (t != 0 && Tile::tiles[t]->material == Material::water) fov = fov * 60 / 70;
|
|
|
|
return fov + fovOffsetO + (fovOffset - fovOffsetO) * a;
|
|
|
|
}
|
|
|
|
void GameRenderer::bobHurt(float a)
|
|
{
|
|
shared_ptr<LivingEntity> player = mc->cameraTargetPlayer;
|
|
|
|
float hurt = player->hurtTime - a;
|
|
|
|
if (player->getHealth() <= 0)
|
|
{
|
|
float duration = player->deathTime + a;
|
|
|
|
glRotatef(40 - (40 * 200) / (duration + 200), 0, 0, 1);
|
|
}
|
|
|
|
if (hurt < 0) return;
|
|
hurt /= player->hurtDuration;
|
|
hurt = (float) Mth::sin(hurt * hurt * hurt * hurt * PI);
|
|
|
|
float rr = player->hurtDir;
|
|
|
|
|
|
glRotatef(-rr, 0, 1, 0);
|
|
glRotatef(-hurt * 14, 0, 0, 1);
|
|
glRotatef(+rr, 0, 1, 0);
|
|
|
|
}
|
|
|
|
void GameRenderer::bobView(float a)
|
|
{
|
|
if (!mc->cameraTargetPlayer->instanceof(eTYPE_LIVINGENTITY)) return;
|
|
|
|
shared_ptr<Player> player = dynamic_pointer_cast<Player>(mc->cameraTargetPlayer);
|
|
|
|
float wda = player->walkDist - player->walkDistO;
|
|
float b = -(player->walkDist + wda * a);
|
|
float bob = player->oBob + (player->bob - player->oBob) * a;
|
|
float tilt = player->oTilt + (player->tilt - player->oTilt) * a;
|
|
glTranslatef((float) Mth::sin(b * PI) * bob * 0.5f, -(float) abs(Mth::cos(b * PI) * bob), 0);
|
|
glRotatef((float) Mth::sin(b * PI) * bob * 3, 0, 0, 1);
|
|
glRotatef((float) abs(Mth::cos(b * PI - 0.2f) * bob) * 5, 1, 0, 0);
|
|
glRotatef((float) tilt, 1, 0, 0);
|
|
}
|
|
|
|
void GameRenderer::moveCameraToPlayer(float a)
|
|
{
|
|
shared_ptr<LivingEntity> player = mc->cameraTargetPlayer;
|
|
shared_ptr<LocalPlayer> localplayer = dynamic_pointer_cast<LocalPlayer>(mc->cameraTargetPlayer);
|
|
float heightOffset = player->heightOffset - 1.62f;
|
|
|
|
double x = player->xo + (player->x - player->xo) * a;
|
|
double y = player->yo + (player->y - player->yo) * a - heightOffset;
|
|
double z = player->zo + (player->z - player->zo) * a;
|
|
|
|
|
|
glRotatef(cameraRollO + (cameraRoll - cameraRollO) * a, 0, 0, 1);
|
|
|
|
if (player->isSleeping())
|
|
{
|
|
heightOffset += 1.0;
|
|
glTranslatef(0.0f, 0.3f, 0);
|
|
if (!mc->options->fixedCamera)
|
|
{
|
|
int t = mc->level->getTile(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z));
|
|
if (t == Tile::bed_Id)
|
|
{
|
|
int data = mc->level->getData(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z));
|
|
|
|
int direction = data & 3;
|
|
glRotatef(static_cast<float>(direction) * 90,0.0f, 1.0f, 0.0f);
|
|
}
|
|
glRotatef(player->yRotO + (player->yRot - player->yRotO) * a + 180, 0, -1, 0);
|
|
glRotatef(player->xRotO + (player->xRot - player->xRotO) * a, -1, 0, 0);
|
|
}
|
|
}
|
|
// 4J-PB - changing this to be per player
|
|
//else if (mc->options->thirdPersonView)
|
|
else if (localplayer->ThirdPersonView())
|
|
{
|
|
double cameraDist = thirdDistanceO + (thirdDistance - thirdDistanceO) * a;
|
|
|
|
if (mc->options->fixedCamera)
|
|
{
|
|
|
|
float rotationY = thirdRotationO + (thirdRotation - thirdRotationO) * a;
|
|
float xRot = thirdTiltO + (thirdTilt - thirdTiltO) * a;
|
|
|
|
glTranslatef(0, 0, static_cast<float>(-cameraDist));
|
|
glRotatef(xRot, 1, 0, 0);
|
|
glRotatef(rotationY, 0, 1, 0);
|
|
}
|
|
else
|
|
{
|
|
// 4J - corrected bug where this used to just take player->xRot & yRot directly and so wasn't taking into account interpolation, allowing camera to go through walls
|
|
float yRot = player->yRotO + (player->yRot - player->yRotO) * a;
|
|
float xRot = player->xRotO + (player->xRot - player->xRotO) * a;
|
|
|
|
// Thirdperson view values are now 0 for disabled, 1 for original mode, 2 for reversed.
|
|
if( localplayer->ThirdPersonView() == 2 )
|
|
{
|
|
// Reverse y rotation - note that this is only used in doing collision to calculate our view
|
|
// distance, the actual rotation itself is just below this else {} block
|
|
yRot += 180.0f;
|
|
}
|
|
|
|
double xd = -Mth::sin(yRot / 180 * PI) * Mth::cos(xRot / 180 * PI) * cameraDist;
|
|
double zd = Mth::cos(yRot / 180 * PI) * Mth::cos(xRot / 180 * PI) * cameraDist;
|
|
double yd = -Mth::sin(xRot / 180 * PI) * cameraDist;
|
|
|
|
if (localplayer->ThirdPersonView() == 2)
|
|
{
|
|
yd = Mth::sin(xRot / 180 * PI) * cameraDist;
|
|
}
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
float xo = static_cast<float>((i & 1) * 2 - 1);
|
|
float yo = static_cast<float>(((i >> 1) & 1) * 2 - 1);
|
|
float zo = static_cast<float>(((i >> 2) & 1) * 2 - 1);
|
|
|
|
xo *= 0.1f;
|
|
yo *= 0.1f;
|
|
zo *= 0.1f;
|
|
|
|
// 4J - corrected bug here where zo was also added to x component
|
|
HitResult *hr = mc->level->clip(Vec3::newTemp(x + xo, y + yo, z + zo), Vec3::newTemp(x - xd + xo, y - yd + yo, z - zd + zo));
|
|
if (hr != nullptr)
|
|
{
|
|
double dist = hr->pos->distanceTo(Vec3::newTemp(x, y, z));
|
|
if (dist < cameraDist) cameraDist = dist;
|
|
delete hr;
|
|
}
|
|
}
|
|
|
|
glTranslatef(0, 0, static_cast<float>(-cameraDist));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
glTranslatef(0, 0, -0.1f);
|
|
}
|
|
|
|
if (!mc->options->fixedCamera)
|
|
{
|
|
float pitch = player->xRotO + (player->xRot - player->xRotO) * a;
|
|
if (localplayer->ThirdPersonView() == 2)
|
|
{
|
|
pitch = -pitch;
|
|
}
|
|
|
|
glRotatef(pitch, 1, 0, 0);
|
|
if (localplayer->ThirdPersonView() == 2)
|
|
{
|
|
glRotatef(player->yRotO + (player->yRot - player->yRotO) * a, 0, 1, 0);
|
|
}
|
|
else
|
|
{
|
|
glRotatef(player->yRotO + (player->yRot - player->yRotO) * a + 180, 0, 1, 0);
|
|
}
|
|
}
|
|
|
|
glTranslatef(0, heightOffset, 0);
|
|
|
|
x = player->xo + (player->x - player->xo) * a;
|
|
y = player->yo + (player->y - player->yo) * a - heightOffset;
|
|
z = player->zo + (player->z - player->zo) * a;
|
|
|
|
isInClouds = mc->levelRenderer->isInCloud(x, y, z, a);
|
|
|
|
}
|
|
|
|
|
|
void GameRenderer::zoomRegion(double zoom, double xa, double ya)
|
|
{
|
|
zoom = zoom;
|
|
zoom_x = xa;
|
|
zoom_y = ya;
|
|
}
|
|
|
|
void GameRenderer::unZoomRegion()
|
|
{
|
|
zoom = 1;
|
|
}
|
|
|
|
// 4J added as we have more complex adjustments to make for fov & aspect on account of viewports
|
|
void GameRenderer::getFovAndAspect(float& fov, float& aspect, float a, bool applyEffects)
|
|
{
|
|
// Use the real window dimensions so the perspective updates on resize.
|
|
extern int g_rScreenWidth;
|
|
extern int g_rScreenHeight;
|
|
aspect = g_rScreenWidth / static_cast<float>(g_rScreenHeight);
|
|
fov = getFov(a, applyEffects);
|
|
|
|
if( ( mc->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_TOP ) ||
|
|
( mc->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM ) )
|
|
{
|
|
aspect *= 2.0f;
|
|
fov *= 0.7f; // Reduce FOV to make things less fish-eye, at the expense of reducing vertical FOV from single player mode
|
|
}
|
|
else if( ( mc->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_LEFT ) ||
|
|
( mc->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT) )
|
|
{
|
|
// Ideally I'd like to make the fov bigger here, but if I do then you an see that the arm isn't very long...
|
|
aspect *= 0.5f;
|
|
}
|
|
}
|
|
|
|
void GameRenderer::setupCamera(float a, int eye)
|
|
{
|
|
if (mc->options->viewDistance >= 0)
|
|
{
|
|
renderDistance = static_cast<float>(16 * 16 >> mc->options->viewDistance);
|
|
}
|
|
else
|
|
{
|
|
renderDistance = static_cast<float>((16 * 16) << (-mc->options->viewDistance));
|
|
}
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
|
|
float stereoScale = 0.07f;
|
|
if (mc->options->anaglyph3d) glTranslatef(-(eye * 2 - 1) * stereoScale, 0, 0);
|
|
|
|
// 4J - have split out fov & aspect calculation so we can take into account viewports
|
|
float aspect, fov;
|
|
getFovAndAspect(fov, aspect, a, true);
|
|
|
|
if (zoom != 1)
|
|
{
|
|
glTranslatef(static_cast<float>(zoom_x), static_cast<float>(-zoom_y), 0);
|
|
glScaled(zoom, zoom, 1);
|
|
}
|
|
gluPerspective(fov, aspect, 0.05f, renderDistance * 2);
|
|
|
|
if (mc->gameMode->isCutScene())
|
|
{
|
|
float s = 1 / 1.5f;
|
|
glScalef(1, s, 1);
|
|
}
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
if (mc->options->anaglyph3d) glTranslatef((eye * 2 - 1) * 0.10f, 0, 0);
|
|
|
|
bobHurt(a);
|
|
|
|
// 4J-PB - this is a per-player option
|
|
//if (mc->options->bobView) bobView(a);
|
|
|
|
bool bNoLegAnim =(mc->player->getAnimOverrideBitmask()&(1<<HumanoidModel::eAnim_NoLegAnim))!=0;
|
|
bool bNoBobbingAnim =(mc->player->getAnimOverrideBitmask()&(1<<HumanoidModel::eAnim_NoBobbing))!=0;
|
|
|
|
if(app.GetGameSettings(mc->player->GetXboxPad(),eGameSetting_ViewBob) && !mc->player->abilities.flying && !bNoLegAnim && !bNoBobbingAnim) bobView(a);
|
|
|
|
float pt = mc->player->oPortalTime + (mc->player->portalTime - mc->player->oPortalTime) * a;
|
|
if (pt > 0)
|
|
{
|
|
int multiplier = 20;
|
|
if (mc->player->hasEffect(MobEffect::confusion))
|
|
{
|
|
multiplier = 7;
|
|
}
|
|
|
|
float skew = 5 / (pt * pt + 5) - pt * 0.04f;
|
|
skew *= skew;
|
|
glRotatef((_tick + a) * multiplier, 0, 1, 1);
|
|
glScalef(1 / skew, 1, 1);
|
|
glRotatef(-(_tick + a) * multiplier, 0, 1, 1);
|
|
}
|
|
|
|
|
|
moveCameraToPlayer(a);
|
|
|
|
if (cameraFlip > 0)
|
|
{
|
|
int i = cameraFlip - 1;
|
|
if (i == 1) glRotatef(90, 0, 1, 0);
|
|
if (i == 2) glRotatef(180, 0, 1, 0);
|
|
if (i == 3) glRotatef(-90, 0, 1, 0);
|
|
if (i == 4) glRotatef(90, 1, 0, 0);
|
|
if (i == 5) glRotatef(-90, 1, 0, 0);
|
|
}
|
|
}
|
|
|
|
void GameRenderer::renderItemInHand(float a, int eye)
|
|
{
|
|
if (cameraFlip > 0) return;
|
|
|
|
// 4J-JEV: I'm fairly confident this method would crash if the cameratarget isnt a local player anyway, but oh well.
|
|
shared_ptr<LocalPlayer> localplayer = mc->cameraTargetPlayer->instanceof(eTYPE_LOCALPLAYER) ? dynamic_pointer_cast<LocalPlayer>(mc->cameraTargetPlayer) : nullptr;
|
|
|
|
bool renderHand = true;
|
|
|
|
// 4J-PB - to turn off the hand for screenshots, but not when the item held is a map
|
|
if ( localplayer!=nullptr)
|
|
{
|
|
shared_ptr<ItemInstance> item = localplayer->inventory->getSelected();
|
|
if(!(item && item->getItem()->id==Item::map_Id) && app.GetGameSettings(localplayer->GetXboxPad(),eGameSetting_DisplayHand)==0 ) renderHand = false;
|
|
}
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
|
|
float stereoScale = 0.07f;
|
|
if (mc->options->anaglyph3d) glTranslatef(-(eye * 2 - 1) * stereoScale, 0, 0);
|
|
|
|
// 4J - have split out fov & aspect calculation so we can take into account viewports
|
|
float fov, aspect;
|
|
getFovAndAspect(fov, aspect, a, false);
|
|
|
|
if (zoom != 1)
|
|
{
|
|
glTranslatef(static_cast<float>(zoom_x), static_cast<float>(-zoom_y), 0);
|
|
glScaled(zoom, zoom, 1);
|
|
}
|
|
gluPerspective(fov, aspect, 0.05f, renderDistance * 2);
|
|
|
|
if (mc->gameMode->isCutScene())
|
|
{
|
|
float s = 1 / 1.5f;
|
|
glScalef(1, s, 1);
|
|
}
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
if (mc->options->anaglyph3d) glTranslatef((eye * 2 - 1) * 0.10f, 0, 0);
|
|
|
|
glPushMatrix();
|
|
bobHurt(a);
|
|
|
|
// 4J-PB - changing this to be per player
|
|
//if (mc->options->bobView) bobView(a);
|
|
bool bNoLegAnim =(localplayer->getAnimOverrideBitmask()&( (1<<HumanoidModel::eAnim_NoLegAnim) | (1<<HumanoidModel::eAnim_NoBobbing) ))!=0;
|
|
if(app.GetGameSettings(localplayer->GetXboxPad(),eGameSetting_ViewBob) && !localplayer->abilities.flying && !bNoLegAnim) bobView(a);
|
|
|
|
// 4J: Skip hand rendering if render hand is off
|
|
if (renderHand)
|
|
{
|
|
// 4J-PB - changing this to be per player
|
|
//if (!mc->options->thirdPersonView && !mc->cameraTargetPlayer->isSleeping())
|
|
if (!localplayer->ThirdPersonView() && !mc->cameraTargetPlayer->isSleeping())
|
|
{
|
|
if (!mc->options->hideGui && !mc->gameMode->isCutScene())
|
|
{
|
|
turnOnLightLayer(a);
|
|
PIXBeginNamedEvent(0,"Item in hand render");
|
|
itemInHandRenderer->render(a);
|
|
PIXEndNamedEvent();
|
|
turnOffLightLayer(a);
|
|
}
|
|
}
|
|
}
|
|
glPopMatrix();
|
|
|
|
// 4J-PB - changing this to be per player
|
|
//if (!mc->options->thirdPersonView && !mc->cameraTargetPlayer->isSleeping())
|
|
if (!localplayer->ThirdPersonView() && !mc->cameraTargetPlayer->isSleeping())
|
|
{
|
|
itemInHandRenderer->renderScreenEffect(a);
|
|
bobHurt(a);
|
|
}
|
|
|
|
// 4J-PB - changing this to be per player
|
|
//if (mc->options->bobView) bobView(a);
|
|
if(app.GetGameSettings(localplayer->GetXboxPad(),eGameSetting_ViewBob) && !localplayer->abilities.flying && !bNoLegAnim) bobView(a);
|
|
}
|
|
|
|
// 4J - change brought forward from 1.8.2
|
|
void GameRenderer::turnOffLightLayer(double alpha)
|
|
{ // 4J - TODO
|
|
#if 0
|
|
if (SharedConstants::TEXTURE_LIGHTING)
|
|
{
|
|
glClientActiveTexture(GL_TEXTURE1);
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glClientActiveTexture(GL_TEXTURE0);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
}
|
|
#endif
|
|
RenderManager.TextureBindVertex(-1);
|
|
}
|
|
|
|
// 4J - change brought forward from 1.8.2
|
|
void GameRenderer::turnOnLightLayer(double alpha)
|
|
{ // 4J - TODO
|
|
#if 0
|
|
if (SharedConstants::TEXTURE_LIGHTING)
|
|
{
|
|
glClientActiveTexture(GL_TEXTURE1);
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glMatrixMode(GL_TEXTURE);
|
|
glLoadIdentity();
|
|
// float s = 1 / 16f / 15.0f*16/14.0f;
|
|
float s = 1 / 16.0f / 15.0f * 15 / 16;
|
|
glScalef(s, s, s);
|
|
glTranslatef(8f, 8f, 8f);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
mc->textures->bind(lightTexture);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
|
glColor4f(1, 1, 1, 1);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glClientActiveTexture(GL_TEXTURE0);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
}
|
|
#endif
|
|
RenderManager.TextureBindVertex(getLightTexture(mc->player->GetXboxPad(), mc->level));
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
|
}
|
|
|
|
// 4J - change brought forward from 1.8.2
|
|
void GameRenderer::tickLightTexture()
|
|
{
|
|
blrt += static_cast<float>((Math::random() - Math::random()) * Math::random() * Math::random());
|
|
blgt += static_cast<float>((Math::random() - Math::random()) * Math::random() * Math::random());
|
|
blrt *= 0.9;
|
|
blgt *= 0.9;
|
|
blr += (blrt - blr) * 1;
|
|
blg += (blgt - blg) * 1;
|
|
_updateLightTexture = true;
|
|
}
|
|
|
|
void GameRenderer::updateLightTexture(float a)
|
|
{
|
|
CachePlayerGammas();
|
|
|
|
for (int j = 0; j < XUSER_MAX_COUNT; j++)
|
|
{
|
|
shared_ptr<MultiplayerLocalPlayer> player = Minecraft::GetInstance()->localplayers[j];
|
|
if (player == nullptr)
|
|
continue;
|
|
|
|
Level *level = player->level;
|
|
|
|
const float skyDarken1 = level->getSkyDarken(1.0f);
|
|
for (int i = 0; i < 256; i++)
|
|
{
|
|
const float darken = skyDarken1 * 0.95f + 0.05f;
|
|
float sky = level->dimension->brightnessRamp[i / 16] * darken;
|
|
const float block = level->dimension->brightnessRamp[i % 16] * (blr * 0.1f + 1.5f);
|
|
|
|
if (level->skyFlashTime < 0)
|
|
{
|
|
sky = level->dimension->brightnessRamp[i / 16];
|
|
}
|
|
|
|
const float rs = sky * (skyDarken1 * 0.65f + 0.35f);
|
|
const float gs = sky * (skyDarken1 * 0.65f + 0.35f);
|
|
const float bs = sky;
|
|
|
|
const float rb = block;
|
|
const float gb = block * ((block * 0.6f + 0.4f) * 0.6f + 0.4f);
|
|
const float bb = block * ((block * block) * 0.6f + 0.4f);
|
|
|
|
float _r = (rs + rb);
|
|
float _g = (gs + gb);
|
|
float _b = (bs + bb);
|
|
|
|
_r = _r * 0.96f + 0.03f;
|
|
_g = _g * 0.96f + 0.03f;
|
|
_b = _b * 0.96f + 0.03f;
|
|
|
|
if (darkenWorldAmount > 0)
|
|
{
|
|
const float amount = darkenWorldAmountO + (darkenWorldAmount - darkenWorldAmountO) * a;
|
|
_r = _r * (1.0f - amount) + (_r * 0.7f) * amount;
|
|
_g = _g * (1.0f - amount) + (_g * 0.6f) * amount;
|
|
_b = _b * (1.0f - amount) + (_b * 0.6f) * amount;
|
|
}
|
|
|
|
if (level->dimension->id == 1)
|
|
{
|
|
_r = (0.22f + rb * 0.75f);
|
|
_g = (0.28f + gb * 0.75f);
|
|
_b = (0.25f + bb * 0.75f);
|
|
}
|
|
|
|
if (player->hasEffect(MobEffect::nightVision))
|
|
{
|
|
const float scale = getNightVisionScale(player, a);
|
|
float dist = 1.0f / _r;
|
|
if (dist > (1.0f / _g))
|
|
dist = (1.0f / _g);
|
|
if (dist > (1.0f / _b))
|
|
dist = (1.0f / _b);
|
|
_r = _r * (1.0f - scale) + (_r * dist) * scale;
|
|
_g = _g * (1.0f - scale) + (_g * dist) * scale;
|
|
_b = _b * (1.0f - scale) + (_b * dist) * scale;
|
|
}
|
|
|
|
if (_r > 1.0f)
|
|
_r = 1.0f;
|
|
if (_r < 0.0f)
|
|
_r = 0.0f;
|
|
if (_g > 1.0f)
|
|
_g = 1.0f;
|
|
if (_g < 0.0f)
|
|
_g = 0.0f;
|
|
if (_b > 1.0f)
|
|
_b = 1.0f;
|
|
if (_b < 0.0f)
|
|
_b = 0.0f;
|
|
|
|
constexpr int alpha = 255;
|
|
const int r = static_cast<int>(_r * 255);
|
|
const int g = static_cast<int>(_g * 255);
|
|
const int b = static_cast<int>(_b * 255);
|
|
|
|
#if ( defined _DURANGO || defined _WIN64 || __PSVITA__ )
|
|
lightPixels[j][i] = alpha << 24 | b << 16 | g << 8 | r;
|
|
#elif ( defined _XBOX || defined __ORBIS__ )
|
|
lightPixels[j][i] = alpha << 24 | r << 16 | g << 8 | b;
|
|
#else
|
|
lightPixels[j][i] = r << 24 | g << 16 | b << 8 | alpha;
|
|
#endif
|
|
}
|
|
|
|
mc->textures->replaceTextureDirect(lightPixels[j], 16, 16, getLightTexture(j, level));
|
|
}
|
|
}
|
|
|
|
float GameRenderer::ComputeGammaFromSlider(float slider0to100)
|
|
{
|
|
float slider = slider0to100;
|
|
slider = max(slider, 0.0f);
|
|
slider = min(slider, 100.0f);
|
|
|
|
if (slider > 50.0f)
|
|
return 1.0f + (slider - 50.0f) / 50.0f * 1.2f; // 1.0 -> 1.5
|
|
else
|
|
return 1.0f - (50.0f - slider) / 50.0f * 0.4f; // 1.0 -> 0.5
|
|
}
|
|
|
|
void GameRenderer::CachePlayerGammas()
|
|
{
|
|
const float slider = app.GetGameSettings(ProfileManager.GetPrimaryPad(), eGameSetting_Gamma);
|
|
const float gamma = ComputeGammaFromSlider(slider);
|
|
|
|
for (int j = 0; j < XUSER_MAX_COUNT && j < NUM_LIGHT_TEXTURES; ++j)
|
|
m_cachedGammaPerPlayer[j] = gamma;
|
|
}
|
|
|
|
bool GameRenderer::ComputeViewportForPlayer(int j, D3D11_VIEWPORT &outViewport) const
|
|
{
|
|
extern int g_rScreenWidth;
|
|
extern int g_rScreenHeight;
|
|
|
|
std::shared_ptr<MultiplayerLocalPlayer> player = Minecraft::GetInstance()->localplayers[j];
|
|
if (!player)
|
|
return false;
|
|
|
|
const float w = static_cast<float>(g_rScreenWidth);
|
|
const float h = static_cast<float>(g_rScreenHeight);
|
|
const float halfW = w * 0.5f;
|
|
const float halfH = h * 0.5f;
|
|
|
|
outViewport.MinDepth = 0.0f;
|
|
outViewport.MaxDepth = 1.0f;
|
|
|
|
switch (static_cast<C4JRender::eViewportType>(player->m_iScreenSection))
|
|
{
|
|
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
|
|
outViewport.TopLeftX = 0; outViewport.TopLeftY = 0;
|
|
outViewport.Width = w; outViewport.Height = halfH;
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
|
|
outViewport.TopLeftX = 0; outViewport.TopLeftY = halfH;
|
|
outViewport.Width = w; outViewport.Height = halfH;
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
|
|
outViewport.TopLeftX = 0; outViewport.TopLeftY = 0;
|
|
outViewport.Width = halfW; outViewport.Height = h;
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
|
|
outViewport.TopLeftX = halfW; outViewport.TopLeftY = 0;
|
|
outViewport.Width = halfW; outViewport.Height = h;
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
|
|
outViewport.TopLeftX = 0; outViewport.TopLeftY = 0;
|
|
outViewport.Width = halfW; outViewport.Height = halfH;
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
|
|
outViewport.TopLeftX = halfW; outViewport.TopLeftY = 0;
|
|
outViewport.Width = halfW; outViewport.Height = halfH;
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
|
|
outViewport.TopLeftX = 0; outViewport.TopLeftY = halfH;
|
|
outViewport.Width = halfW; outViewport.Height = halfH;
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
|
|
outViewport.TopLeftX = halfW; outViewport.TopLeftY = halfH;
|
|
outViewport.Width = halfW; outViewport.Height = halfH;
|
|
break;
|
|
default:
|
|
outViewport.TopLeftX = 0; outViewport.TopLeftY = 0;
|
|
outViewport.Width = w; outViewport.Height = h;
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
uint32_t GameRenderer::BuildPlayerViewports(D3D11_VIEWPORT *outViewports, float *outGammas, UINT maxCount) const
|
|
{
|
|
UINT count = 0;
|
|
for (int j = 0; j < XUSER_MAX_COUNT && j < NUM_LIGHT_TEXTURES && count < maxCount; ++j)
|
|
{
|
|
if (!Minecraft::GetInstance()->localplayers[j])
|
|
continue;
|
|
D3D11_VIEWPORT vp;
|
|
if (!ComputeViewportForPlayer(j, vp))
|
|
continue;
|
|
outViewports[count] = vp;
|
|
outGammas[count] = m_cachedGammaPerPlayer[j];
|
|
++count;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
void GameRenderer::ApplyGammaPostProcess() const
|
|
{
|
|
D3D11_VIEWPORT vps[NUM_LIGHT_TEXTURES];
|
|
float gammas[NUM_LIGHT_TEXTURES];
|
|
const UINT n = BuildPlayerViewports(vps, gammas, NUM_LIGHT_TEXTURES);
|
|
|
|
float gamma = 1.0f;
|
|
bool hasPlayers = n > 0;
|
|
|
|
if (hasPlayers)
|
|
{
|
|
bool anyEffect = false;
|
|
for (UINT i = 0; i < n; ++i)
|
|
{
|
|
if (gammas[i] < 0.99f || gammas[i] > 1.01f)
|
|
{
|
|
anyEffect = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!anyEffect)
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
const float slider = app.GetGameSettings(0, eGameSetting_Gamma);
|
|
gamma = ComputeGammaFromSlider(slider);
|
|
if (gamma < 0.99f || gamma > 1.01f)
|
|
{
|
|
PostProcesser::GetInstance().SetGamma(gamma);
|
|
PostProcesser::GetInstance().Apply();
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (n == 1)
|
|
{
|
|
PostProcesser::GetInstance().SetGamma(gammas[0]);
|
|
PostProcesser::GetInstance().Apply();
|
|
}
|
|
else
|
|
{
|
|
PostProcesser::GetInstance().CopyBackbuffer();
|
|
for (UINT i = 0; i < n; ++i)
|
|
{
|
|
PostProcesser::GetInstance().SetGamma(gammas[i]);
|
|
PostProcesser::GetInstance().SetViewport(vps[i]);
|
|
PostProcesser::GetInstance().ApplyFromCopied();
|
|
}
|
|
PostProcesser::GetInstance().ResetViewport();
|
|
}
|
|
}
|
|
|
|
float GameRenderer::getNightVisionScale(shared_ptr<Player> player, float a)
|
|
{
|
|
int duration = player->getEffect(MobEffect::nightVision)->getDuration();
|
|
if (duration > (SharedConstants::TICKS_PER_SECOND * 10))
|
|
{
|
|
return 1.0f;
|
|
}
|
|
else
|
|
{
|
|
float flash = max(0.0f, (float)duration - a);
|
|
return .7f + Mth::sin(flash * PI * .05f) * .3f; // was: .7 + sin(flash*pi*0.2) * .3
|
|
}
|
|
}
|
|
|
|
// 4J added, so we can have a light texture for each player to support split screen
|
|
int GameRenderer::getLightTexture(int iPad, Level *level)
|
|
{
|
|
// Turn the current dimenions id into an index from 0 to 2
|
|
// int idx = level->dimension->id;
|
|
// if( idx == -1 ) idx = 2;
|
|
|
|
return lightTexture[iPad]; // 4J-JEV: Changing to Per Player lighting textures.
|
|
}
|
|
|
|
void GameRenderer::render(float a, bool bFirst)
|
|
{
|
|
if (mc->player == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( _updateLightTexture && bFirst) updateLightTexture(a);
|
|
if (Display::isActive())
|
|
{
|
|
lastActiveTime = System::currentTimeMillis();
|
|
}
|
|
else
|
|
{
|
|
if (System::currentTimeMillis() - lastActiveTime > 500)
|
|
{
|
|
mc->pauseGame();
|
|
}
|
|
}
|
|
|
|
#if 0 // 4J - TODO
|
|
if (mc->mouseGrabbed && focused) {
|
|
mc->mouseHandler.poll();
|
|
|
|
float ss = mc->options->sensitivity * 0.6f + 0.2f;
|
|
float sens = (ss * ss * ss) * 8;
|
|
float xo = mc->mouseHandler.xd * sens;
|
|
float yo = mc->mouseHandler.yd * sens;
|
|
|
|
int yAxis = 1;
|
|
if (mc->options->invertYMouse) yAxis = -1;
|
|
|
|
if (mc->options->smoothCamera) {
|
|
|
|
xo = smoothTurnX.getNewDeltaValue(xo, .05f * sens);
|
|
yo = smoothTurnY.getNewDeltaValue(yo, .05f * sens);
|
|
|
|
}
|
|
|
|
mc->player.turn(xo, yo * yAxis);
|
|
}
|
|
#endif
|
|
|
|
if (mc->noRender)
|
|
return;
|
|
anaglyph3d = mc->options->anaglyph3d;
|
|
|
|
glViewport(0, 0, mc->width, mc->height); // 4J - added (no-op on Win64, viewport set by StateSetViewport)
|
|
ScreenSizeCalculator ssc(mc->options, mc->width, mc->height);
|
|
const int screenWidth = ssc.getWidth();
|
|
const int screenHeight = ssc.getHeight();
|
|
const int xMouse = Mouse::getX() * screenWidth / mc->width;
|
|
const int yMouse = screenHeight - Mouse::getY() * screenHeight / mc->height - 1;
|
|
|
|
const int maxFps = getFpsCap(mc->options->framerateLimit);
|
|
|
|
if (mc->level != nullptr)
|
|
{
|
|
if (mc->options->framerateLimit == 0)
|
|
{
|
|
renderLevel(a, 0);
|
|
}
|
|
else
|
|
{
|
|
renderLevel(a, lastNsTime + 1000000000 / maxFps);
|
|
}
|
|
|
|
lastNsTime = System::nanoTime();
|
|
|
|
if (!mc->options->hideGui || mc->screen != nullptr)
|
|
{
|
|
mc->gui->render(a, mc->screen != nullptr, xMouse, yMouse);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
glViewport(0, 0, mc->width, mc->height);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
setupGuiScreen();
|
|
|
|
lastNsTime = System::nanoTime();
|
|
}
|
|
|
|
if (mc->screen != nullptr)
|
|
{
|
|
glClear(GL_DEPTH_BUFFER_BIT);
|
|
mc->screen->render(xMouse, yMouse, a);
|
|
if (mc->screen != nullptr && mc->screen->particles != nullptr)
|
|
mc->screen->particles->render(a);
|
|
}
|
|
}
|
|
|
|
void GameRenderer::renderLevel(float a)
|
|
{
|
|
renderLevel(a, 0);
|
|
}
|
|
|
|
#ifdef MULTITHREAD_ENABLE
|
|
// Request that an item be deleted, when it is safe to do so
|
|
void GameRenderer::AddForDelete(byte *deleteThis)
|
|
{
|
|
EnterCriticalSection(&m_csDeleteStack);
|
|
m_deleteStackByte.push_back(deleteThis);
|
|
}
|
|
|
|
void GameRenderer::AddForDelete(SparseLightStorage *deleteThis)
|
|
{
|
|
EnterCriticalSection(&m_csDeleteStack);
|
|
m_deleteStackSparseLightStorage.push_back(deleteThis);
|
|
}
|
|
|
|
void GameRenderer::AddForDelete(CompressedTileStorage *deleteThis)
|
|
{
|
|
EnterCriticalSection(&m_csDeleteStack);
|
|
m_deleteStackCompressedTileStorage.push_back(deleteThis);
|
|
}
|
|
|
|
void GameRenderer::AddForDelete(SparseDataStorage *deleteThis)
|
|
{
|
|
EnterCriticalSection(&m_csDeleteStack);
|
|
m_deleteStackSparseDataStorage.push_back(deleteThis);
|
|
}
|
|
|
|
void GameRenderer::FinishedReassigning()
|
|
{
|
|
LeaveCriticalSection(&m_csDeleteStack);
|
|
}
|
|
|
|
int GameRenderer::runUpdate(LPVOID lpParam)
|
|
{
|
|
Minecraft *minecraft = Minecraft::GetInstance();
|
|
Vec3::CreateNewThreadStorage();
|
|
AABB::CreateNewThreadStorage();
|
|
IntCache::CreateNewThreadStorage();
|
|
Tesselator::CreateNewThreadStorage(1024*1024);
|
|
Compression::UseDefaultThreadStorage();
|
|
RenderManager.InitialiseContext();
|
|
#ifdef _LARGE_WORLDS
|
|
Chunk::CreateNewThreadStorage();
|
|
#endif
|
|
Tile::CreateNewThreadStorage();
|
|
|
|
ShutdownManager::HasStarted(ShutdownManager::eRenderChunkUpdateThread,m_updateEvents);
|
|
while(ShutdownManager::ShouldRun(ShutdownManager::eRenderChunkUpdateThread))
|
|
{
|
|
//m_updateEvents->Clear(eUpdateEventIsFinished);
|
|
//m_updateEvents->WaitForSingle(eUpdateCanRun,INFINITE);
|
|
// 4J Stu - We Need to have this happen atomically to avoid deadlocks
|
|
m_updateEvents->WaitForAll(INFINITE);
|
|
|
|
if( !ShutdownManager::ShouldRun(ShutdownManager::eRenderChunkUpdateThread) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
m_updateEvents->Set(eUpdateCanRun);
|
|
|
|
// PIXBeginNamedEvent(0,"Updating dirty chunks %d",(count++)&7);
|
|
|
|
// Update chunks atomically until there aren't any very near ones left - they will be deferred for rendering
|
|
// until the call to CBuffDeferredModeEnd if we have anything near to render here
|
|
// Now limiting maximum number of updates that can be deferred as have noticed that with redstone clock circuits, it is possible to create
|
|
// things that need constant updating, so if you stand near them, the render data Never gets updated and the game just keeps going until it runs out of render memory...
|
|
int count = 0;
|
|
static const int MAX_DEFERRED_UPDATES = 10;
|
|
bool shouldContinue = false;
|
|
do
|
|
{
|
|
shouldContinue = minecraft->levelRenderer->updateDirtyChunks();
|
|
count++;
|
|
} while ( shouldContinue && count < MAX_DEFERRED_UPDATES );
|
|
|
|
// while( minecraft->levelRenderer->updateDirtyChunks() )
|
|
// ;
|
|
RenderManager.CBuffDeferredModeEnd();
|
|
|
|
// If any renderable tile entities were flagged in this last block of chunk(s) that were udpated, then change their
|
|
// flags to say that this deferred chunk is over and they are actually safe to be removed now
|
|
minecraft->levelRenderer->fullyFlagRenderableTileEntitiesToBeRemoved();
|
|
|
|
// We've got stacks for things that can only safely be deleted whilst this thread isn't updating things - delete those things now
|
|
EnterCriticalSection(&m_csDeleteStack);
|
|
for(unsigned int i = 0; i < m_deleteStackByte.size(); i++ )
|
|
{
|
|
delete m_deleteStackByte[i];
|
|
}
|
|
m_deleteStackByte.clear();
|
|
for(unsigned int i = 0; i < m_deleteStackSparseLightStorage.size(); i++ )
|
|
{
|
|
delete m_deleteStackSparseLightStorage[i];
|
|
}
|
|
m_deleteStackSparseLightStorage.clear();
|
|
for(unsigned int i = 0; i < m_deleteStackCompressedTileStorage.size(); i++ )
|
|
{
|
|
delete m_deleteStackCompressedTileStorage[i];
|
|
}
|
|
m_deleteStackCompressedTileStorage.clear();
|
|
for(unsigned int i = 0; i < m_deleteStackSparseDataStorage.size(); i++ )
|
|
{
|
|
delete m_deleteStackSparseDataStorage[i];
|
|
}
|
|
m_deleteStackSparseDataStorage.clear();
|
|
LeaveCriticalSection(&m_csDeleteStack);
|
|
|
|
// PIXEndNamedEvent();
|
|
|
|
AABB::resetPool();
|
|
Vec3::resetPool();
|
|
IntCache::Reset();
|
|
m_updateEvents->Set(eUpdateEventIsFinished);
|
|
}
|
|
|
|
ShutdownManager::HasFinished(ShutdownManager::eRenderChunkUpdateThread);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
void GameRenderer::EnableUpdateThread()
|
|
{
|
|
// #ifdef __PS3__ // MGH - disable the update on PS3 for now
|
|
// return;
|
|
// #endif
|
|
#ifdef MULTITHREAD_ENABLE
|
|
if( updateRunning) return;
|
|
app.DebugPrintf("------------------EnableUpdateThread--------------------\n");
|
|
updateRunning = true;
|
|
m_updateEvents->Set(eUpdateCanRun);
|
|
m_updateEvents->Set(eUpdateEventIsFinished);
|
|
#endif
|
|
}
|
|
|
|
void GameRenderer::DisableUpdateThread()
|
|
{
|
|
// #ifdef __PS3__ // MGH - disable the update on PS3 for now
|
|
// return;
|
|
// #endif
|
|
#ifdef MULTITHREAD_ENABLE
|
|
if( !updateRunning) return;
|
|
app.DebugPrintf("------------------DisableUpdateThread--------------------\n");
|
|
updateRunning = false;
|
|
m_updateEvents->Clear(eUpdateCanRun);
|
|
m_updateEvents->WaitForSingle(eUpdateEventIsFinished,INFINITE);
|
|
#endif
|
|
}
|
|
|
|
void GameRenderer::renderLevel(float a, int64_t until)
|
|
{
|
|
// if (updateLightTexture) updateLightTexture(); // 4J - TODO - Java 1.0.1 has this line enabled, should check why - don't want to put it in now in case it breaks split-screen
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
// Is this the primary player? Only do the updating of chunks if it is. This controls the creation of render data for each chunk - all of this we are only
|
|
// going to do for the primary player, and the other players can just view whatever they have loaded in - we're sharing render data between players.
|
|
bool updateChunks = ( mc->player == mc->localplayers[ProfileManager.GetPrimaryPad()] );
|
|
|
|
// if (mc->cameraTargetPlayer == nullptr) // 4J - removed condition as we want to update this is mc->player changes for different local players
|
|
{
|
|
mc->cameraTargetPlayer = mc->player;
|
|
}
|
|
pick(a);
|
|
|
|
shared_ptr<LivingEntity> cameraEntity = mc->cameraTargetPlayer;
|
|
LevelRenderer *levelRenderer = mc->levelRenderer;
|
|
ParticleEngine *particleEngine = mc->particleEngine;
|
|
double xOff = cameraEntity->xOld + (cameraEntity->x - cameraEntity->xOld) * a;
|
|
double yOff = cameraEntity->yOld + (cameraEntity->y - cameraEntity->yOld) * a;
|
|
double zOff = cameraEntity->zOld + (cameraEntity->z - cameraEntity->zOld) * a;
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
if (mc->options->anaglyph3d)
|
|
{
|
|
GameRenderer::anaglyphPass = i;
|
|
if (GameRenderer::anaglyphPass == 0) glColorMask(false, true, true, false);
|
|
else glColorMask(true, false, false, false);
|
|
}
|
|
|
|
|
|
glViewport(0, 0, mc->width, mc->height);
|
|
setupClearColor(a);
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
setupCamera(a, i);
|
|
Camera::prepare(mc->player, mc->player->ThirdPersonView() == 2);
|
|
|
|
Frustum::getFrustum();
|
|
if (mc->options->viewDistance < 2)
|
|
{
|
|
setupFog(-1, a);
|
|
levelRenderer->renderSky(a);
|
|
if(mc->skins->getSelected()->getId() == 1026 ) levelRenderer->renderHaloRing(a);
|
|
}
|
|
glEnable(GL_FOG);
|
|
setupFog(1, a);
|
|
|
|
if (mc->options->ambientOcclusion)
|
|
{
|
|
GL11::glShadeModel(GL11::GL_SMOOTH);
|
|
}
|
|
|
|
PIXBeginNamedEvent(0,"Culling");
|
|
MemSect(31);
|
|
// Culler *frustum = new FrustumCuller();
|
|
FrustumCuller frustObj;
|
|
Culler *frustum = &frustObj;
|
|
MemSect(0);
|
|
frustum->prepare(xOff, yOff, zOff);
|
|
|
|
mc->levelRenderer->cull(frustum, a);
|
|
PIXEndNamedEvent();
|
|
|
|
#ifndef MULTITHREAD_ENABLE
|
|
if ( (i == 0) && updateChunks ) // 4J - added updateChunks condition
|
|
{
|
|
int PIXPass = 0;
|
|
PIXBeginNamedEvent(0,"Updating dirty chunks");
|
|
do
|
|
{
|
|
PIXBeginNamedEvent(0,"Updating dirty chunks pass %d",PIXPass++);
|
|
bool retval = mc->levelRenderer->updateDirtyChunks(cameraEntity, false);
|
|
PIXEndNamedEvent();
|
|
if( retval ) break;
|
|
|
|
|
|
if (until == 0) break;
|
|
|
|
int64_t diff = until - System::nanoTime();
|
|
if (diff < 0) break;
|
|
if (diff > 1000000000) break;
|
|
} while (true);
|
|
PIXEndNamedEvent();
|
|
}
|
|
#endif
|
|
|
|
|
|
if (cameraEntity->y < Level::genDepth)
|
|
{
|
|
prepareAndRenderClouds(levelRenderer, a);
|
|
}
|
|
Frustum::getFrustum(); // 4J added - re-calculate frustum as rendering the clouds does a scale & recalculates one that isn't any good for the rest of the level rendering
|
|
|
|
setupFog(0, a);
|
|
glEnable(GL_FOG);
|
|
MemSect(31);
|
|
mc->textures->bindTexture(&TextureAtlas::LOCATION_BLOCKS); // 4J was L"/terrain.png"
|
|
MemSect(0);
|
|
Lighting::turnOff();
|
|
PIXBeginNamedEvent(0,"Level render");
|
|
levelRenderer->render(cameraEntity, 0, a, updateChunks);
|
|
PIXEndNamedEvent();
|
|
|
|
GL11::glShadeModel(GL11::GL_FLAT);
|
|
|
|
if (cameraFlip == 0 )
|
|
{
|
|
Lighting::turnOn();
|
|
PIXBeginNamedEvent(0,"Entity render");
|
|
// 4J - for entities, don't include the "a" factor that interpolates from the old to new position, as the AABBs for the entities are already fully at the new position
|
|
// This fixes flickering minecarts, and pigs that you are riding on
|
|
frustum->prepare(cameraEntity->x,cameraEntity->y,cameraEntity->z);
|
|
// 4J Stu - When rendering entities, in the end if the dragon is hurt or we have a lot of entities we can end up wrapping
|
|
// our index into the temp Vec3 cache and overwrite the one that was storing the camera position
|
|
// Fix for #77745 - TU9: Content: Gameplay: Items and mobs not belonging to end world are disappearing when Enderdragon is damaged.
|
|
Vec3 *cameraPosTemp = cameraEntity->getPos(a);
|
|
cameraPos->x = cameraPosTemp->x;
|
|
cameraPos->y = cameraPosTemp->y;
|
|
cameraPos->z = cameraPosTemp->z;
|
|
levelRenderer->renderEntities(cameraPos, frustum, a);
|
|
#ifdef __PSVITA__
|
|
// AP - make sure we're using the Alpha cut out effect for particles
|
|
glEnable(GL_ALPHA_TEST);
|
|
#endif
|
|
PIXEndNamedEvent();
|
|
PIXBeginNamedEvent(0,"Particle render");
|
|
turnOnLightLayer(a); // 4J - brought forward from 1.8.2
|
|
particleEngine->renderLit(cameraEntity, a, ParticleEngine::OPAQUE_LIST);
|
|
Lighting::turnOff();
|
|
setupFog(0, a);
|
|
particleEngine->render(cameraEntity, a, ParticleEngine::OPAQUE_LIST);
|
|
PIXEndNamedEvent();
|
|
turnOffLightLayer(a); // 4J - brought forward from 1.8.2
|
|
|
|
if ( (mc->hitResult != nullptr) && cameraEntity->isUnderLiquid(Material::water) && cameraEntity->instanceof(eTYPE_PLAYER) ) //&& !mc->options.hideGui)
|
|
{
|
|
shared_ptr<Player> player = dynamic_pointer_cast<Player>(cameraEntity);
|
|
glDisable(GL_ALPHA_TEST);
|
|
levelRenderer->renderHit(player, mc->hitResult, 0, player->inventory->getSelected(), a);
|
|
glEnable(GL_ALPHA_TEST);
|
|
}
|
|
}
|
|
|
|
glDisable(GL_BLEND);
|
|
glEnable(GL_CULL_FACE);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glDepthMask(true);
|
|
setupFog(0, a);
|
|
glEnable(GL_BLEND);
|
|
glDisable(GL_CULL_FACE);
|
|
MemSect(31);
|
|
mc->textures->bindTexture(&TextureAtlas::LOCATION_BLOCKS); // 4J was L"/terrain.png"
|
|
MemSect(0);
|
|
// 4J - have changed this fancy rendering option to work with our command buffers. The original used to use frame buffer flags to disable
|
|
// writing to colour when doing the z-only pass, but that value gets obliterated by our command buffers. Using alpha blend function instead
|
|
// to achieve the same effect.
|
|
if (true) // (mc->options->fancyGraphics)
|
|
{
|
|
if (mc->options->ambientOcclusion)
|
|
{
|
|
GL11::glShadeModel(GL11::GL_SMOOTH);
|
|
}
|
|
|
|
glBlendFunc(GL_ZERO, GL_ONE);
|
|
PIXBeginNamedEvent(0,"Fancy second pass - writing z");
|
|
int visibleWaterChunks = levelRenderer->render(cameraEntity, 1, a, updateChunks);
|
|
PIXEndNamedEvent();
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
if (visibleWaterChunks > 0)
|
|
{
|
|
PIXBeginNamedEvent(0,"Fancy second pass - actual rendering");
|
|
levelRenderer->render(cameraEntity, 1, a, updateChunks); // 4J - chanaged, used to be renderSameAsLast but we don't support that anymore
|
|
PIXEndNamedEvent();
|
|
}
|
|
|
|
GL11::glShadeModel(GL11::GL_FLAT);
|
|
}
|
|
else
|
|
{
|
|
PIXBeginNamedEvent(0,"Second pass level render");
|
|
levelRenderer->render(cameraEntity, 1, a, updateChunks);
|
|
PIXEndNamedEvent();
|
|
}
|
|
|
|
// 4J - added - have split out translucent particle rendering so that it happens after the water is rendered, primarily for fireworks
|
|
PIXBeginNamedEvent(0,"Particle render (translucent)");
|
|
Lighting::turnOn();
|
|
turnOnLightLayer(a); // 4J - brought forward from 1.8.2
|
|
particleEngine->renderLit(cameraEntity, a, ParticleEngine::TRANSLUCENT_LIST);
|
|
Lighting::turnOff();
|
|
setupFog(0, a);
|
|
particleEngine->render(cameraEntity, a, ParticleEngine::TRANSLUCENT_LIST);
|
|
PIXEndNamedEvent();
|
|
turnOffLightLayer(a); // 4J - brought forward from 1.8.2
|
|
////////////////////////// End of 4J added section
|
|
|
|
glDepthMask(true);
|
|
glEnable(GL_CULL_FACE);
|
|
glDisable(GL_BLEND);
|
|
|
|
if ( (zoom == 1) && cameraEntity->instanceof(eTYPE_PLAYER) ) //&& !mc->options.hideGui)
|
|
{
|
|
if (mc->hitResult != nullptr && !cameraEntity->isUnderLiquid(Material::water))
|
|
{
|
|
shared_ptr<Player> player = dynamic_pointer_cast<Player>(cameraEntity);
|
|
glDisable(GL_ALPHA_TEST);
|
|
levelRenderer->renderHitOutline(player, mc->hitResult, 0, a);
|
|
glEnable(GL_ALPHA_TEST);
|
|
}
|
|
}
|
|
|
|
/* 4J - moved rain rendering to after clouds so that it alpha blends onto them properly
|
|
PIXBeginNamedEvent(0,"Rendering snow and rain");
|
|
renderSnowAndRain(a);
|
|
PIXEndNamedEvent();
|
|
glDisable(GL_FOG);
|
|
*/
|
|
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
|
levelRenderer->renderDestroyAnimation(Tesselator::getInstance(), dynamic_pointer_cast<Player>(cameraEntity), a);
|
|
glDisable(GL_BLEND);
|
|
|
|
if (cameraEntity->y >= Level::genDepth)
|
|
{
|
|
prepareAndRenderClouds(levelRenderer, a);
|
|
}
|
|
|
|
// 4J - rain rendering moved here so that it renders after clouds & can blend properly onto them
|
|
setupFog(0, a);
|
|
glEnable(GL_FOG);
|
|
PIXBeginNamedEvent(0,"Rendering snow and rain");
|
|
renderSnowAndRain(a);
|
|
PIXEndNamedEvent();
|
|
glDisable(GL_FOG);
|
|
|
|
|
|
if (zoom == 1)
|
|
{
|
|
glClear(GL_DEPTH_BUFFER_BIT);
|
|
renderItemInHand(a, i);
|
|
}
|
|
|
|
|
|
if (!mc->options->anaglyph3d)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
glColorMask(true, true, true, false);
|
|
}
|
|
|
|
void GameRenderer::prepareAndRenderClouds(LevelRenderer *levelRenderer, float a)
|
|
{
|
|
if (mc->options->isCloudsOn())
|
|
{
|
|
glPushMatrix();
|
|
setupFog(0, a);
|
|
glEnable(GL_FOG);
|
|
PIXBeginNamedEvent(0,"Rendering clouds");
|
|
levelRenderer->renderClouds(a);
|
|
PIXEndNamedEvent();
|
|
glDisable(GL_FOG);
|
|
setupFog(1, a);
|
|
glPopMatrix();
|
|
}
|
|
}
|
|
|
|
void GameRenderer::tickRain()
|
|
{
|
|
float rainLevel = mc->level->getRainLevel(1);
|
|
|
|
if (!mc->options->fancyGraphics) rainLevel /= 2;
|
|
if (rainLevel == 0) return;
|
|
|
|
rainLevel /= ( mc->levelRenderer->activePlayers() + 1 );
|
|
|
|
random->setSeed(_tick * 312987231l);
|
|
shared_ptr<LivingEntity> player = mc->cameraTargetPlayer;
|
|
Level *level = mc->level;
|
|
|
|
int x0 = Mth::floor(player->x);
|
|
int y0 = Mth::floor(player->y);
|
|
int z0 = Mth::floor(player->z);
|
|
|
|
int r = 10;
|
|
|
|
double rainPosX = 0;
|
|
double rainPosY = 0;
|
|
double rainPosZ = 0;
|
|
int rainPosSamples = 0;
|
|
|
|
int rainCount = static_cast<int>(100 * rainLevel * rainLevel);
|
|
if (mc->options->particles == 1)
|
|
{
|
|
rainCount >>= 1;
|
|
} else if (mc->options->particles == 2)
|
|
{
|
|
rainCount = 0;
|
|
}
|
|
for (int i = 0; i < rainCount; i++)
|
|
{
|
|
int x = x0 + random->nextInt(r) - random->nextInt(r);
|
|
int z = z0 + random->nextInt(r) - random->nextInt(r);
|
|
int y = level->getTopRainBlock(x, z);
|
|
int t = level->getTile(x, y - 1, z);
|
|
Biome *biome = level->getBiome(x,z);
|
|
if (y <= y0 + r && y >= y0 - r && biome->hasRain() && biome->getTemperature() >= 0.2f)
|
|
{
|
|
float xa = random->nextFloat();
|
|
float za = random->nextFloat();
|
|
if (t > 0)
|
|
{
|
|
if (Tile::tiles[t]->material == Material::lava)
|
|
{
|
|
mc->particleEngine->add(std::make_shared<SmokeParticle>(level, x + xa, y + 0.1f - Tile::tiles[t]->getShapeY0(), z + za, 0, 0, 0));
|
|
}
|
|
else
|
|
{
|
|
if (random->nextInt(++rainPosSamples) == 0)
|
|
{
|
|
rainPosX = x + xa;
|
|
rainPosY = y + 0.1f - Tile::tiles[t]->getShapeY0();
|
|
rainPosZ = z + za;
|
|
}
|
|
mc->particleEngine->add(std::make_shared<WaterDropParticle>(level, x + xa, y + 0.1f - Tile::tiles[t]->getShapeY0(), z + za));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (rainPosSamples > 0 && random->nextInt(3) < rainSoundTime++)
|
|
{
|
|
rainSoundTime = 0;
|
|
MemSect(24);
|
|
if (rainPosY > player->y + 1 && level->getTopRainBlock(Mth::floor(player->x), Mth::floor(player->z)) > Mth::floor(player->y))
|
|
{
|
|
mc->level->playLocalSound(rainPosX, rainPosY, rainPosZ, eSoundType_AMBIENT_WEATHER_RAIN, 0.1f, 0.5f);
|
|
}
|
|
else
|
|
{
|
|
mc->level->playLocalSound(rainPosX, rainPosY, rainPosZ, eSoundType_AMBIENT_WEATHER_RAIN, 0.2f, 1.0f);
|
|
}
|
|
MemSect(0);
|
|
}
|
|
|
|
}
|
|
|
|
// 4J - this whole function updated from 1.8.2
|
|
void GameRenderer::renderSnowAndRain(float a)
|
|
{
|
|
float rainLevel = mc->level->getRainLevel(a);
|
|
if (rainLevel <= 0) return;
|
|
|
|
// 4J - rain is relatively low poly, but high fill-rate - better to clip it
|
|
RenderManager.StateSetEnableViewportClipPlanes(true);
|
|
|
|
turnOnLightLayer(a);
|
|
|
|
if (rainXa == nullptr)
|
|
{
|
|
rainXa = new float[32 * 32];
|
|
rainZa = new float[32 * 32];
|
|
|
|
for (int z = 0; z < 32; z++)
|
|
{
|
|
for (int x = 0; x < 32; x++)
|
|
{
|
|
float xa = x - 16;
|
|
float za = z - 16;
|
|
float d = Mth::sqrt(xa * xa + za * za);
|
|
rainXa[z << 5 | x] = -za / d;
|
|
rainZa[z << 5 | x] = xa / d;
|
|
}
|
|
}
|
|
}
|
|
|
|
shared_ptr<LivingEntity> player = mc->cameraTargetPlayer;
|
|
Level *level = mc->level;
|
|
|
|
int x0 = Mth::floor(player->x);
|
|
int y0 = Mth::floor(player->y);
|
|
int z0 = Mth::floor(player->z);
|
|
|
|
Tesselator *t = Tesselator::getInstance();
|
|
glDisable(GL_CULL_FACE);
|
|
glNormal3f(0, 1, 0);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glAlphaFunc(GL_GREATER, 0.01f);
|
|
|
|
MemSect(31);
|
|
mc->textures->bindTexture(&SNOW_LOCATION); // 4J was L"/environment/snow.png"
|
|
MemSect(0);
|
|
|
|
double xo = player->xOld + (player->x - player->xOld) * a;
|
|
double yo = player->yOld + (player->y - player->yOld) * a;
|
|
double zo = player->zOld + (player->z - player->zOld) * a;
|
|
|
|
int yMin = Mth::floor(yo);
|
|
|
|
|
|
int r = 5;
|
|
// 4J - was if(mc.options.fancyGraphics) r = 10;
|
|
switch( mc->levelRenderer->activePlayers() )
|
|
{
|
|
case 1:
|
|
default:
|
|
r = 9;
|
|
break;
|
|
case 2:
|
|
r = 7;
|
|
break;
|
|
case 3:
|
|
r = 5;
|
|
break;
|
|
case 4:
|
|
r = 5;
|
|
break;
|
|
}
|
|
|
|
// 4J - some changes made here to access biome through new interface that caches results in levelchunk flags, as an optimisation
|
|
|
|
int mode = -1;
|
|
float time = _tick + a;
|
|
|
|
glColor4f(1, 1, 1, 1);
|
|
|
|
for (int x = x0 - r; x <= x0 + r; x++)
|
|
for (int z = z0 - r; z <= z0 + r; z++)
|
|
{
|
|
int rainSlot = (z - z0 + 16) * 32 + (x - x0 + 16);
|
|
float xa = rainXa[rainSlot] * 0.5f;
|
|
float za = rainZa[rainSlot] * 0.5f;
|
|
|
|
// 4J - changes here brought forward from 1.8.2
|
|
Biome *b = level->getBiome(x, z);
|
|
if (!b->hasRain() && !b->hasSnow()) continue;
|
|
|
|
int floor = level->getTopRainBlock(x, z);
|
|
|
|
int yy0 = y0 - r;
|
|
int yy1 = y0 + r;
|
|
|
|
if (yy0 < floor) yy0 = floor;
|
|
if (yy1 < floor) yy1 = floor;
|
|
float s = 1;
|
|
|
|
int yl = floor;
|
|
if (yl < yMin) yl = yMin;
|
|
|
|
if (yy0 != yy1)
|
|
{
|
|
random->setSeed((x * x * 3121 + x * 45238971) ^ (z * z * 418711 + z * 13761));
|
|
|
|
// 4J - changes here brought forward from 1.8.2
|
|
float temp = b->getTemperature();
|
|
if (level->getBiomeSource()->scaleTemp(temp, floor) >= 0.15f)
|
|
{
|
|
if (mode != 0)
|
|
{
|
|
if (mode >= 0) t->end();
|
|
mode = 0;
|
|
mc->textures->bindTexture(&RAIN_LOCATION);
|
|
t->begin();
|
|
}
|
|
|
|
float ra = (((_tick + x * x * 3121 + x * 45238971 + z * z * 418711 + z * 13761) & 31) + a) / 32.0f * (3 + random->nextFloat());
|
|
|
|
double xd = (x + 0.5f) - player->x;
|
|
double zd = (z + 0.5f) - player->z;
|
|
float dd = (float) Mth::sqrt(xd * xd + zd * zd) / r;
|
|
|
|
float br = 1;
|
|
t->offset(-xo * 1, -yo * 1, -zo * 1);
|
|
#ifdef __PSVITA__
|
|
// AP - this will set up the 4 vertices in half the time
|
|
float Alpha = ((1 - dd * dd) * 0.5f + 0.5f) * rainLevel;
|
|
int tex2 = (level->getLightColor(x, yl, z, 0) * 3 + 0xf000f0) / 4;
|
|
t->tileRainQuad(x - xa + 0.5, yy0, z - za + 0.5, 0 * s, yy0 * s / 4.0f + ra * s,
|
|
x + xa + 0.5, yy0, z + za + 0.5, 1 * s, yy0 * s / 4.0f + ra * s,
|
|
x + xa + 0.5, yy1, z + za + 0.5, 1 * s, yy1 * s / 4.0f + ra * s,
|
|
x - xa + 0.5, yy1, z - za + 0.5, 0 * s, yy1 * s / 4.0f + ra * s,
|
|
br, br, br, Alpha, br, br, br, 0, tex2);
|
|
#else
|
|
t->tex2(level->getLightColor(x, yl, z, 0));
|
|
t->color(br, br, br, ((1 - dd * dd) * 0.5f + 0.5f) * rainLevel);
|
|
t->vertexUV(x - xa + 0.5, yy0, z - za + 0.5, 0 * s, yy0 * s / 4.0f + ra * s);
|
|
t->vertexUV(x + xa + 0.5, yy0, z + za + 0.5, 1 * s, yy0 * s / 4.0f + ra * s);
|
|
t->color(br, br, br, 0.0f); // 4J - added to soften the top visible edge of the rain
|
|
t->vertexUV(x + xa + 0.5, yy1, z + za + 0.5, 1 * s, yy1 * s / 4.0f + ra * s);
|
|
t->vertexUV(x - xa + 0.5, yy1, z - za + 0.5, 0 * s, yy1 * s / 4.0f + ra * s);
|
|
#endif
|
|
t->offset(0, 0, 0);
|
|
t->end();
|
|
}
|
|
else
|
|
{
|
|
if (mode != 1)
|
|
{
|
|
if (mode >= 0) t->end();
|
|
mode = 1;
|
|
mc->textures->bindTexture(&SNOW_LOCATION);
|
|
t->begin();
|
|
}
|
|
float ra = (((_tick) & 511) + a) / 512.0f;
|
|
float uo = random->nextFloat() + time * 0.01f * static_cast<float>(random->nextGaussian());
|
|
float vo = random->nextFloat() + time * static_cast<float>(random->nextGaussian()) * 0.001f;
|
|
double xd = (x + 0.5f) - player->x;
|
|
double zd = (z + 0.5f) - player->z;
|
|
float dd = static_cast<float>(sqrt(xd * xd + zd * zd)) / r;
|
|
float br = 1;
|
|
t->offset(-xo * 1, -yo * 1, -zo * 1);
|
|
#ifdef __PSVITA__
|
|
// AP - this will set up the 4 vertices in half the time
|
|
float Alpha = ((1 - dd * dd) * 0.3f + 0.5f) * rainLevel;
|
|
int tex2 = (level->getLightColor(x, yl, z, 0) * 3 + 0xf000f0) / 4;
|
|
t->tileRainQuad(x - xa + 0.5, yy0, z - za + 0.5, 0 * s + uo, yy0 * s / 4.0f + ra * s + vo,
|
|
x + xa + 0.5, yy0, z + za + 0.5, 1 * s + uo, yy0 * s / 4.0f + ra * s + vo,
|
|
x + xa + 0.5, yy1, z + za + 0.5, 1 * s + uo, yy1 * s / 4.0f + ra * s + vo,
|
|
x - xa + 0.5, yy1, z - za + 0.5, 0 * s + uo, yy1 * s / 4.0f + ra * s + vo,
|
|
br, br, br, Alpha, br, br, br, Alpha, tex2);
|
|
#else
|
|
t->tex2((level->getLightColor(x, yl, z, 0) * 3 + 0xf000f0) / 4);
|
|
t->color(br, br, br, ((1 - dd * dd) * 0.3f + 0.5f) * rainLevel);
|
|
t->vertexUV(x - xa + 0.5, yy0, z - za + 0.5, 0 * s + uo, yy0 * s / 4.0f + ra * s + vo);
|
|
t->vertexUV(x + xa + 0.5, yy0, z + za + 0.5, 1 * s + uo, yy0 * s / 4.0f + ra * s + vo);
|
|
t->vertexUV(x + xa + 0.5, yy1, z + za + 0.5, 1 * s + uo, yy1 * s / 4.0f + ra * s + vo);
|
|
t->vertexUV(x - xa + 0.5, yy1, z - za + 0.5, 0 * s + uo, yy1 * s / 4.0f + ra * s + vo);
|
|
#endif
|
|
t->offset(0, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if( mode >= 0 ) t->end();
|
|
glEnable(GL_CULL_FACE);
|
|
glDisable(GL_BLEND);
|
|
glAlphaFunc(GL_GREATER, 0.1f);
|
|
turnOffLightLayer(a);
|
|
|
|
RenderManager.StateSetEnableViewportClipPlanes(false);
|
|
}
|
|
|
|
// 4J - added forceScale parameter
|
|
void GameRenderer::setupGuiScreen(int forceScale /*=-1*/)
|
|
{
|
|
ScreenSizeCalculator ssc(mc->options, mc->width, mc->height, forceScale);
|
|
|
|
glClear(GL_DEPTH_BUFFER_BIT);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
glOrtho(0, static_cast<float>(ssc.rawWidth), static_cast<float>(ssc.rawHeight), 0, 1000, 3000);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
glTranslatef(0, 0, -2000);
|
|
}
|
|
|
|
void GameRenderer::setupClearColor(float a)
|
|
{
|
|
Level *level = mc->level;
|
|
shared_ptr<LivingEntity> player = mc->cameraTargetPlayer;
|
|
|
|
float whiteness = 1.0f / (4 - mc->options->viewDistance);
|
|
whiteness = 1 - static_cast<float>(pow(static_cast<double>(whiteness), 0.25));
|
|
|
|
Vec3 *skyColor = level->getSkyColor(mc->cameraTargetPlayer, a);
|
|
float sr = static_cast<float>(skyColor->x);
|
|
float sg = static_cast<float>(skyColor->y);
|
|
float sb = static_cast<float>(skyColor->z);
|
|
|
|
Vec3 *fogColor = level->getFogColor(a);
|
|
fr = static_cast<float>(fogColor->x);
|
|
fg = static_cast<float>(fogColor->y);
|
|
fb = static_cast<float>(fogColor->z);
|
|
|
|
if (mc->options->viewDistance < 2)
|
|
{
|
|
Vec3 *sunAngle = Mth::sin(level->getSunAngle(a)) > 0 ? Vec3::newTemp(-1, 0, 0) : Vec3::newTemp(1, 0, 0);
|
|
float d = static_cast<float>(player->getViewVector(a)->dot(sunAngle));
|
|
if (d < 0) d = 0;
|
|
if (d > 0)
|
|
{
|
|
float *c = level->dimension->getSunriseColor(level->getTimeOfDay(a), a);
|
|
if (c != nullptr)
|
|
{
|
|
d *= c[3];
|
|
fr = fr * (1 - d) + c[0] * d;
|
|
fg = fg * (1 - d) + c[1] * d;
|
|
fb = fb * (1 - d) + c[2] * d;
|
|
}
|
|
}
|
|
}
|
|
|
|
fr += (sr - fr) * whiteness;
|
|
fg += (sg - fg) * whiteness;
|
|
fb += (sb - fb) * whiteness;
|
|
|
|
float rainLevel = level->getRainLevel(a);
|
|
if (rainLevel > 0)
|
|
{
|
|
float ba = 1 - rainLevel * 0.5f;
|
|
float bb = 1 - rainLevel * 0.4f;
|
|
fr *= ba;
|
|
fg *= ba;
|
|
fb *= bb;
|
|
}
|
|
float thunderLevel = level->getThunderLevel(a);
|
|
if (thunderLevel > 0)
|
|
{
|
|
float ba = 1 - thunderLevel * 0.5f;
|
|
fr *= ba;
|
|
fg *= ba;
|
|
fb *= ba;
|
|
}
|
|
|
|
int t = Camera::getBlockAt(mc->level, player, a);
|
|
if (isInClouds)
|
|
{
|
|
Vec3 *cc = level->getCloudColor(a);
|
|
fr = static_cast<float>(cc->x);
|
|
fg = static_cast<float>(cc->y);
|
|
fb = static_cast<float>(cc->z);
|
|
}
|
|
else if (t != 0 && Tile::tiles[t]->material == Material::water)
|
|
{
|
|
float clearness = EnchantmentHelper::getOxygenBonus(player) * 0.2f;
|
|
|
|
unsigned int colour = Minecraft::GetInstance()->getColourTable()->getColor( eMinecraftColour_Under_Water_Clear_Colour );
|
|
byte redComponent = ((colour>>16)&0xFF);
|
|
byte greenComponent = ((colour>>8)&0xFF);
|
|
byte blueComponent = ((colour)&0xFF);
|
|
|
|
fr = static_cast<float>(redComponent)/256 + clearness;//0.02f;
|
|
fg = static_cast<float>(greenComponent)/256 + clearness;//0.02f;
|
|
fb = static_cast<float>(blueComponent)/256 + clearness;//0.2f;
|
|
}
|
|
else if (t != 0 && Tile::tiles[t]->material == Material::lava)
|
|
{
|
|
unsigned int colour = Minecraft::GetInstance()->getColourTable()->getColor( eMinecraftColour_Under_Lava_Clear_Colour );
|
|
byte redComponent = ((colour>>16)&0xFF);
|
|
byte greenComponent = ((colour>>8)&0xFF);
|
|
byte blueComponent = ((colour)&0xFF);
|
|
|
|
fr = static_cast<float>(redComponent)/256;//0.6f;
|
|
fg = static_cast<float>(greenComponent)/256;//0.1f;
|
|
fb = static_cast<float>(blueComponent)/256;//0.00f;
|
|
}
|
|
|
|
float brr = fogBrO + (fogBr - fogBrO) * a;
|
|
fr *= brr;
|
|
fg *= brr;
|
|
fb *= brr;
|
|
|
|
double yy = (player->yOld + (player->y - player->yOld) * a) * level->dimension->getClearColorScale(); // 4J - getClearColorScale brought forward from 1.2.3
|
|
|
|
if (player->hasEffect(MobEffect::blindness))
|
|
{
|
|
int duration = player->getEffect(MobEffect::blindness)->getDuration();
|
|
if (duration < 20)
|
|
{
|
|
yy = yy * (1.0f - static_cast<float>(duration) / 20.0f);
|
|
}
|
|
else
|
|
{
|
|
yy = 0;
|
|
}
|
|
}
|
|
|
|
if (yy < 1)
|
|
{
|
|
if (yy < 0) yy = 0;
|
|
yy = yy * yy;
|
|
fr *= yy;
|
|
fg *= yy;
|
|
fb *= yy;
|
|
}
|
|
|
|
if (darkenWorldAmount > 0)
|
|
{
|
|
float amount = darkenWorldAmountO + (darkenWorldAmount - darkenWorldAmountO) * a;
|
|
fr = fr * (1.0f - amount) + (fr * .7f) * amount;
|
|
fg = fg * (1.0f - amount) + (fg * .6f) * amount;
|
|
fb = fb * (1.0f - amount) + (fb * .6f) * amount;
|
|
}
|
|
|
|
if (player->hasEffect(MobEffect::nightVision))
|
|
{
|
|
float scale = getNightVisionScale(mc->player, a);
|
|
{
|
|
float dist = FLT_MAX; // MGH - changed this to avoid divide by zero
|
|
if ( (fr > 0) && (dist > (1.0f / fr)) )
|
|
{
|
|
dist = (1.0f / fr);
|
|
}
|
|
if ( (fg > 0) && (dist > (1.0f / fg)) )
|
|
{
|
|
dist = (1.0f / fg);
|
|
}
|
|
if ( (fb > 0) && (dist > (1.0f / fb)) )
|
|
{
|
|
dist = (1.0f / fb);
|
|
}
|
|
fr = fr * (1.0f - scale) + (fr * dist) * scale;
|
|
fg = fg * (1.0f - scale) + (fg * dist) * scale;
|
|
fb = fb * (1.0f - scale) + (fb * dist) * scale;
|
|
}
|
|
}
|
|
|
|
if (mc->options->anaglyph3d)
|
|
{
|
|
float frr = (fr * 30 + fg * 59 + fb * 11) / 100;
|
|
float fgg = (fr * 30 + fg * 70) / (100);
|
|
float fbb = (fr * 30 + fb * 70) / (100);
|
|
|
|
fr = frr;
|
|
fg = fgg;
|
|
fb = fbb;
|
|
}
|
|
|
|
glClearColor(fr, fg, fb, 0.0f);
|
|
|
|
}
|
|
|
|
void GameRenderer::setupFog(int i, float alpha)
|
|
{
|
|
shared_ptr<LivingEntity> player = mc->cameraTargetPlayer;
|
|
|
|
// 4J - check for creative mode brought forward from 1.2.3
|
|
bool creative = false;
|
|
if ( player->instanceof(eTYPE_PLAYER) )
|
|
{
|
|
creative = (dynamic_pointer_cast<Player>(player))->abilities.instabuild;
|
|
}
|
|
|
|
if (i == 999)
|
|
{
|
|
__debugbreak();
|
|
// 4J TODO
|
|
/*
|
|
glFog(GL_FOG_COLOR, getBuffer(0, 0, 0, 1));
|
|
glFogi(GL_FOG_MODE, GL_LINEAR);
|
|
glFogf(GL_FOG_START, 0);
|
|
glFogf(GL_FOG_END, 8);
|
|
|
|
if (GLContext.getCapabilities().GL_NV_fog_distance) {
|
|
glFogi(NVFogDistance.GL_FOG_DISTANCE_MODE_NV, NVFogDistance.GL_EYE_RADIAL_NV);
|
|
}
|
|
|
|
glFogf(GL_FOG_START, 0);
|
|
*/
|
|
return;
|
|
}
|
|
|
|
glFog(GL_FOG_COLOR, getBuffer(fr, fg, fb, 1));
|
|
glNormal3f(0, -1, 0);
|
|
glColor4f(1, 1, 1, 1);
|
|
|
|
int t = Camera::getBlockAt(mc->level, player, alpha);
|
|
|
|
if (player->hasEffect(MobEffect::blindness))
|
|
{
|
|
float distance = 5.0f;
|
|
int duration = player->getEffect(MobEffect::blindness)->getDuration();
|
|
if (duration < 20)
|
|
{
|
|
distance = 5.0f + (renderDistance - 5.0f) * (1.0f - static_cast<float>(duration) / 20.0f);
|
|
}
|
|
|
|
glFogi(GL_FOG_MODE, GL_LINEAR);
|
|
if (i < 0)
|
|
{
|
|
glFogf(GL_FOG_START, 0);
|
|
glFogf(GL_FOG_END, distance * 0.8f);
|
|
}
|
|
else
|
|
{
|
|
glFogf(GL_FOG_START, distance * 0.25f);
|
|
glFogf(GL_FOG_END, distance);
|
|
}
|
|
// 4J - TODO investigate implementing this
|
|
// if (GLContext.getCapabilities().GL_NV_fog_distance)
|
|
// {
|
|
// glFogi(NVFogDistance.GL_FOG_DISTANCE_MODE_NV, NVFogDistance.GL_EYE_RADIAL_NV);
|
|
// }
|
|
}
|
|
else if (isInClouds)
|
|
{
|
|
glFogi(GL_FOG_MODE, GL_EXP);
|
|
glFogf(GL_FOG_DENSITY, 0.1f); // was 0.06
|
|
}
|
|
else if (t > 0 && Tile::tiles[t]->material == Material::water)
|
|
{
|
|
glFogi(GL_FOG_MODE, GL_EXP);
|
|
if (player->hasEffect(MobEffect::waterBreathing))
|
|
{
|
|
glFogf(GL_FOG_DENSITY, 0.05f); // was 0.06
|
|
}
|
|
else
|
|
{
|
|
glFogf(GL_FOG_DENSITY, 0.1f - (EnchantmentHelper::getOxygenBonus(player) * 0.03f)); // was 0.06
|
|
}
|
|
}
|
|
else if (t > 0 && Tile::tiles[t]->material == Material::lava)
|
|
{
|
|
glFogi(GL_FOG_MODE, GL_EXP);
|
|
glFogf(GL_FOG_DENSITY, 2.0f); // was 0.06
|
|
}
|
|
else
|
|
{
|
|
float distance = renderDistance;
|
|
if (!mc->level->dimension->hasCeiling)
|
|
{
|
|
// 4J - test for doing bedrockfog brought forward from 1.2.3
|
|
if (mc->level->dimension->hasBedrockFog() && !creative)
|
|
{
|
|
double yy = ((player->getLightColor(alpha) & 0xf00000) >> 20) / 16.0 + (player->yOld + (player->y - player->yOld) * alpha + 4) / 32;
|
|
if (yy < 1)
|
|
{
|
|
if (yy < 0) yy = 0;
|
|
yy = yy * yy;
|
|
float dist = 100 * static_cast<float>(yy);
|
|
if (dist < 5) dist = 5;
|
|
if (distance > dist) distance = dist;
|
|
}
|
|
}
|
|
}
|
|
|
|
glFogi(GL_FOG_MODE, GL_LINEAR);
|
|
glFogf(GL_FOG_START, distance * 0.25f);
|
|
glFogf(GL_FOG_END, distance);
|
|
if (i < 0)
|
|
{
|
|
glFogf(GL_FOG_START, 0);
|
|
glFogf(GL_FOG_END, distance * 0.8f);
|
|
}
|
|
else
|
|
{
|
|
glFogf(GL_FOG_START, distance * 0.25f);
|
|
glFogf(GL_FOG_END, distance);
|
|
}
|
|
/* 4J - removed - TODO investigate
|
|
if (GLContext.getCapabilities().GL_NV_fog_distance)
|
|
{
|
|
glFogi(NVFogDistance.GL_FOG_DISTANCE_MODE_NV, NVFogDistance.GL_EYE_RADIAL_NV);
|
|
}
|
|
*/
|
|
|
|
if (mc->level->dimension->isFoggyAt(static_cast<int>(player->x), static_cast<int>(player->z)))
|
|
{
|
|
glFogf(GL_FOG_START, distance * 0.05f);
|
|
glFogf(GL_FOG_END, min(distance, 16 * 16 * .75f) * .5f);
|
|
}
|
|
}
|
|
|
|
glEnable(GL_COLOR_MATERIAL);
|
|
glColorMaterial(GL_FRONT, GL_AMBIENT);
|
|
|
|
}
|
|
|
|
FloatBuffer *GameRenderer::getBuffer(float a, float b, float c, float d)
|
|
{
|
|
lb->clear();
|
|
lb->put(a)->put(b)->put(c)->put(d);
|
|
lb->flip();
|
|
return lb;
|
|
}
|
|
|
|
int GameRenderer::getFpsCap(int option)
|
|
{
|
|
int maxFps = 200;
|
|
if (option == 1) maxFps = 120;
|
|
if (option == 2) maxFps = 35;
|
|
return maxFps;
|
|
}
|
|
|
|
void GameRenderer::updateAllChunks()
|
|
{
|
|
// mc->levelRenderer->updateDirtyChunks(mc->cameraTargetPlayer, true);
|
|
}
|