2262 lines
66 KiB
C++
2262 lines
66 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 = (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 = NULL;
|
|
rainZa = NULL;
|
|
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 = NULL;
|
|
|
|
// 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, NULL, "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 != NULL) delete [] rainXa;
|
|
if(rainZa != NULL) 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 == NULL)
|
|
{
|
|
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 / ((float) SharedConstants::TICKS_PER_SECOND * 1);
|
|
if (darkenWorldAmount > 1)
|
|
{
|
|
darkenWorldAmount = 1;
|
|
}
|
|
BossMobGuiInfo::darkenWorld = false;
|
|
}
|
|
else if (darkenWorldAmount > 0)
|
|
{
|
|
darkenWorldAmount -= 1.0f / ((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 == NULL) return;
|
|
if (mc->level == NULL) 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 = NULL;
|
|
}
|
|
}
|
|
|
|
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 != NULL)
|
|
{
|
|
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);
|
|
if (e == mc->cameraTargetPlayer->riding != NULL)
|
|
{
|
|
if (nearest == 0)
|
|
{
|
|
hovered = e;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hovered = e;
|
|
nearest = dd;
|
|
}
|
|
}
|
|
delete p;
|
|
}
|
|
|
|
if (hovered != NULL)
|
|
{
|
|
if (nearest < dist || (mc->hitResult == NULL))
|
|
{
|
|
if( mc->hitResult != NULL )
|
|
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((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, (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 = (float)((i & 1) * 2 - 1);
|
|
float yo = (float)(((i >> 1) & 1) * 2 - 1);
|
|
float zo = (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 != NULL)
|
|
{
|
|
double dist = hr->pos->distanceTo(Vec3::newTemp(x, y, z));
|
|
if (dist < cameraDist) cameraDist = dist;
|
|
delete hr;
|
|
}
|
|
}
|
|
|
|
glTranslatef(0, 0, (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)
|
|
{
|
|
// 4J - split out aspect ratio and fov here so we can adjust for viewports - we might need to revisit these as
|
|
// they are maybe be too generous for performance.
|
|
aspect = mc->width / (float) mc->height;
|
|
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 = (float)(16 * 16 >> mc->options->viewDistance);
|
|
}
|
|
else
|
|
{
|
|
renderDistance = (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((float) zoom_x, (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!=NULL)
|
|
{
|
|
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((float) zoom_x, (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 += (float)((Math::random() - Math::random()) * Math::random() * Math::random());
|
|
blgt += (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()
|
|
{
|
|
for (int j = 0; j < XUSER_MAX_COUNT && j < NUM_LIGHT_TEXTURES; ++j)
|
|
{
|
|
std::shared_ptr<MultiplayerLocalPlayer> player = Minecraft::GetInstance()->localplayers[j];
|
|
if (!player)
|
|
{
|
|
m_cachedGammaPerPlayer[j] = 1.0f;
|
|
continue;
|
|
}
|
|
|
|
const float slider = app.GetGameSettings(j, eGameSetting_Gamma); // 0..100
|
|
m_cachedGammaPerPlayer[j] = ComputeGammaFromSlider(slider);
|
|
}
|
|
}
|
|
|
|
bool GameRenderer::ComputeViewportForPlayer(int j, D3D11_VIEWPORT &outViewport) const
|
|
{
|
|
int active = 0;
|
|
int indexMap[NUM_LIGHT_TEXTURES] = {-1, -1, -1, -1};
|
|
for (int i = 0; i < XUSER_MAX_COUNT && i < NUM_LIGHT_TEXTURES; ++i)
|
|
{
|
|
if (Minecraft::GetInstance()->localplayers[i])
|
|
indexMap[active++] = i;
|
|
}
|
|
|
|
if (active <= 1)
|
|
{
|
|
outViewport.TopLeftX = 0.0f;
|
|
outViewport.TopLeftY = 0.0f;
|
|
outViewport.Width = static_cast<FLOAT>(mc->width);
|
|
outViewport.Height = static_cast<FLOAT>(mc->height);
|
|
outViewport.MinDepth = 0.0f;
|
|
outViewport.MaxDepth = 1.0f;
|
|
return true;
|
|
}
|
|
|
|
int k = -1;
|
|
for (int ord = 0; ord < active; ++ord)
|
|
if (indexMap[ord] == j)
|
|
{
|
|
k = ord;
|
|
break;
|
|
}
|
|
if (k < 0)
|
|
return false;
|
|
|
|
const float width = static_cast<float>(mc->width);
|
|
const float height = static_cast<float>(mc->height);
|
|
|
|
if (active == 2)
|
|
{
|
|
const float halfH = height * 0.5f;
|
|
outViewport.TopLeftX = 0.0f;
|
|
outViewport.Width = width;
|
|
outViewport.MinDepth = 0.0f;
|
|
outViewport.MaxDepth = 1.0f;
|
|
if (k == 0)
|
|
{
|
|
outViewport.TopLeftY = 0.0f;
|
|
outViewport.Height = halfH;
|
|
}
|
|
else
|
|
{
|
|
outViewport.TopLeftY = halfH;
|
|
outViewport.Height = halfH;
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
const float halfW = width * 0.5f;
|
|
const float halfH = height * 0.5f;
|
|
const int row = (k >= 2) ? 1 : 0;
|
|
const int col = (k % 2);
|
|
outViewport.TopLeftX = col ? halfW : 0.0f;
|
|
outViewport.TopLeftY = row ? halfH : 0.0f;
|
|
outViewport.Width = halfW;
|
|
outViewport.Height = halfH;
|
|
outViewport.MinDepth = 0.0f;
|
|
outViewport.MaxDepth = 1.0f;
|
|
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( _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;
|
|
GameRenderer::anaglyph3d = mc->options->anaglyph3d;
|
|
|
|
glViewport(0, 0, mc->width, mc->height); // 4J - added
|
|
ScreenSizeCalculator ssc(mc->options, mc->width, mc->height);
|
|
int screenWidth = ssc.getWidth();
|
|
int screenHeight = ssc.getHeight();
|
|
int xMouse = Mouse::getX() * screenWidth / mc->width;
|
|
int yMouse = screenHeight - Mouse::getY() * screenHeight / mc->height - 1;
|
|
|
|
int maxFps = getFpsCap(mc->options->framerateLimit);
|
|
|
|
if (mc->level != NULL)
|
|
{
|
|
if (mc->options->framerateLimit == 0)
|
|
{
|
|
renderLevel(a, 0);
|
|
}
|
|
else
|
|
{
|
|
renderLevel(a, lastNsTime + 1000000000 / maxFps);
|
|
}
|
|
|
|
lastNsTime = System::nanoTime();
|
|
|
|
if (!mc->options->hideGui || mc->screen != NULL)
|
|
{
|
|
mc->gui->render(a, mc->screen != NULL, 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 != NULL)
|
|
{
|
|
glClear(GL_DEPTH_BUFFER_BIT);
|
|
mc->screen->render(xMouse, yMouse, a);
|
|
if (mc->screen != NULL && mc->screen->particles != NULL) 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 == NULL) // 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 != NULL) && 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 != NULL && !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 = (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( shared_ptr<SmokeParticle>( new 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( shared_ptr<WaterDropParticle>( new 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 == NULL)
|
|
{
|
|
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 * (float) random->nextGaussian();
|
|
float vo = random->nextFloat() + time * (float) random->nextGaussian() * 0.001f;
|
|
double xd = (x + 0.5f) - player->x;
|
|
double zd = (z + 0.5f) - player->z;
|
|
float dd = (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, (float)ssc.rawWidth, (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 - (float) pow((double)whiteness, 0.25);
|
|
|
|
Vec3 *skyColor = level->getSkyColor(mc->cameraTargetPlayer, a);
|
|
float sr = (float) skyColor->x;
|
|
float sg = (float) skyColor->y;
|
|
float sb = (float) skyColor->z;
|
|
|
|
Vec3 *fogColor = level->getFogColor(a);
|
|
fr = (float) fogColor->x;
|
|
fg = (float) fogColor->y;
|
|
fb = (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 = (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 != NULL)
|
|
{
|
|
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 = (float) cc->x;
|
|
fg = (float) cc->y;
|
|
fb = (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 = (float)redComponent/256 + clearness;//0.02f;
|
|
fg = (float)greenComponent/256 + clearness;//0.02f;
|
|
fb = (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 = (float)redComponent/256;//0.6f;
|
|
fg = (float)greenComponent/256;//0.1f;
|
|
fb = (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 - (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 - (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 * (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((int) player->x, (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);
|
|
}
|