4jcraft/Minecraft.Client/Rendering/GameRenderer.cpp
2026-03-26 13:37:01 -05:00

2138 lines
76 KiB
C++

#include "../Platform/stdafx.h"
#include "GameRenderer.h"
#include "EntityRenderers/ItemInHandRenderer.h"
#include "LevelRenderer.h"
#include "Frustum.h"
#include "FrustumCuller.h"
#include "../Textures/Textures.h"
#include "Tesselator.h"
#include "Particles/ParticleEngine.h"
#include "Particles/SmokeParticle.h"
#include "Particles/WaterDropParticle.h"
#include "../GameState/GameMode.h"
#include "../GameState/CreativeMode.h"
#include "Lighting.h"
#include "../GameState/Options.h"
#include "../Player/MultiPlayerLocalPlayer.h"
#include "Particles/GuiParticles.h"
#include "../Level/MultiPlayerLevel.h"
#include "Chunk.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.entity.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.entity.player.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.item.enchantment.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.material.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.tile.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.chunk.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.biome.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.dimension.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.phys.h"
#include "../../Minecraft.World/Platform/System.h"
#include "../../Minecraft.World/IO/Streams/FloatBuffer.h"
#include "../../Minecraft.World/Util/ThreadName.h"
#include "../../Minecraft.World/Level/Storage/SparseLightStorage.h"
#include "../../Minecraft.World/Level/Storage/CompressedTileStorage.h"
#include "../../Minecraft.World/Level/Storage/SparseDataStorage.h"
#include "../../Minecraft.World/Util/JavaMath.h"
#include "../../Minecraft.World/Util/Facing.h"
#include "../../Minecraft.World/Entities/MobEffect.h"
#include "../../Minecraft.World/Util/SmoothFloat.h"
#include "../../Minecraft.World/Entities/MobEffectInstance.h"
#include "../../Minecraft.World/Items/Item.h"
#include "Camera.h"
#include "../../Minecraft.World/Util/SoundTypes.h"
#include "Models/HumanoidModel.h"
#include "../../Minecraft.World/Items/Item.h"
#include "../../Minecraft.World/IO/Streams/Compression.h"
#include "PS3/PS3Extras/ShutdownManager.h"
#include "../UI/BossMobGuiInfo.h"
#include "../Textures/Packs/TexturePackRepository.h"
#include "../Textures/Packs/TexturePack.h"
#include "../Textures/TextureAtlas.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;
std::vector<uint8_t*> GameRenderer::m_deleteStackByte;
std::vector<SparseLightStorage*> GameRenderer::m_deleteStackSparseLightStorage;
std::vector<CompressedTileStorage*>
GameRenderer::m_deleteStackCompressedTileStorage;
std::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 = 0;
_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 = new Vec3(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 = std::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(b.x * range, b.y * range, b.z * range);
to = to.add(from.x, from.y, from.z);
hovered = nullptr;
float overlap = 1;
std::vector<std::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;
AUTO_VAR(itEnd, objects->end());
for (AUTO_VAR(it, objects->begin()); it != itEnd; it++) {
std::shared_ptr<Entity> e = *it; // objects->at(i);
if (!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 != NULL) {
double dd = from.distanceTo(p->pos);
std::shared_ptr<Entity> ridingEntity =
mc->cameraTargetPlayer->riding;
// 4jcraft: compare the mounted entity explicitly so riding the hit
// target does not get collapsed into a boolean/null comparison.
if (ridingEntity != nullptr && e == ridingEntity) {
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 =
std::dynamic_pointer_cast<LivingEntity>(hovered);
}
}
}
}
void GameRenderer::SetFovVal(float fov) { m_fov = fov; }
float GameRenderer::GetFovVal() { return m_fov; }
void GameRenderer::tickFov() {
std::shared_ptr<LocalPlayer> player =
std::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;
std::shared_ptr<LocalPlayer> player =
std::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) {
std::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;
std::shared_ptr<Player> player =
std::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) {
std::shared_ptr<LivingEntity> player = mc->cameraTargetPlayer;
std::shared_ptr<LocalPlayer> localplayer =
std::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 playerYRot =
player->yRotO + (player->yRot - player->yRotO) * a;
float playerXRot =
player->xRotO + (player->xRot - player->xRotO) * a;
float yRot = playerYRot;
float xRot = playerXRot;
// Thirdperson view values are now 0 for disabled, 1 for original
// mode, 2 for reversed.
if (localplayer->ThirdPersonView() == 2) {
// Reverse x 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
xRot += 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;
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
Vec3 a(x + xo, y + yo, z + zo);
Vec3 b(x - xd + xo, y - yd + yo, z - zd + zo);
HitResult* hr = mc->level->clip(&a, &b);
if (hr != NULL) {
Vec3 p(x, y, z);
double dist = hr->pos.distanceTo(p);
if (dist < cameraDist) cameraDist = dist;
delete hr;
}
}
if (localplayer->ThirdPersonView() == 2) {
glRotatef(180, 0, 1, 0);
}
glRotatef(playerXRot - xRot, 1, 0, 0);
glRotatef(playerYRot - yRot, 0, 1, 0);
glTranslatef(0, 0, (float)-cameraDist);
glRotatef(yRot - playerYRot, 0, 1, 0);
glRotatef(xRot - playerXRot, 1, 0, 0);
}
} else {
glTranslatef(0, 0, -0.1f);
}
if (!mc->options->fixedCamera) {
glRotatef(player->xRotO + (player->xRot - player->xRotO) * a, 1, 0, 0);
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) {
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.
std::shared_ptr<LocalPlayer> localplayer =
mc->cameraTargetPlayer->instanceof(eTYPE_LOCALPLAYER)
? std::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) {
std::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, true);
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
#ifdef __linux__
if (SharedConstants::TEXTURE_LIGHTING) {
LinuxLogStubLightmapProbe();
RenderManager.TextureBindVertex(-1);
LinuxGLLogLightmapState("turnOffLightLayer", -1, false);
}
#else
// 4jcraft: manually handle this in order to ensure that the light layer is
// turned off correctly
#if 1
if (SharedConstants::TEXTURE_LIGHTING) {
glClientActiveTexture(GL_TEXTURE1);
glActiveTexture(GL_TEXTURE1);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
glClientActiveTexture(GL_TEXTURE0);
glActiveTexture(GL_TEXTURE0);
}
#else
RenderManager.TextureBindVertex(-1);
#endif
#endif
}
// 4J - change brought forward from 1.8.2
void GameRenderer::turnOnLightLayer(
double alpha,
bool scaleLight) { // 4jcraft: added scaleLight for entity lighting
#ifdef __linux__
if (!SharedConstants::TEXTURE_LIGHTING) return;
LinuxLogStubLightmapProbe();
const int textureId = getLightTexture(mc->player->GetXboxPad(), mc->level);
static int logCount = 0;
if (logCount < 16) {
++logCount;
app.DebugPrintf("[linux-lightmap] turnOnLightLayer tex=%d scale=%d\n",
textureId, scaleLight ? 1 : 0);
}
RenderManager.TextureBindVertex(textureId, scaleLight);
LinuxGLLogLightmapState("turnOnLightLayer", textureId, scaleLight);
#else
#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
// 4jcraft: update light texture
// todo: check implementation of getLightTexture.
RenderManager.TextureBindVertex(
getLightTexture(mc->player->GetXboxPad(), mc->level), scaleLight);
#if 0
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);
#endif
#endif
}
// 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) {
// 4J-JEV: Now doing light textures on PER PLAYER basis.
// 4J - we *had* added separate light textures for all dimensions, and this
// loop to update them all here
for (int j = 0; j < XUSER_MAX_COUNT; j++) {
// Loop over all the players
std::shared_ptr<MultiplayerLocalPlayer> player =
Minecraft::GetInstance()->localplayers[j];
if (player == NULL) continue;
Level* level = player->level; // 4J - was mc->level when it was just to
// update the one light texture
float skyDarken1 = level->getSkyDarken((float)1);
for (int i = 0; i < 256; i++) {
float darken = skyDarken1 * 0.95f + 0.05f;
float sky = level->dimension->brightnessRamp[i / 16] * darken;
float block =
level->dimension->brightnessRamp[i % 16] * (blr * 0.1f + 1.5f);
if (level->skyFlashTime > 0) {
sky = level->dimension->brightnessRamp[i / 16];
}
float rs = sky * (skyDarken1 * 0.65f + 0.35f);
float gs = sky * (skyDarken1 * 0.65f + 0.35f);
float bs = sky;
float rb = block;
float gb = block * ((block * 0.6f + 0.4f) * 0.6f + 0.4f);
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) {
float amount = darkenWorldAmountO +
(darkenWorldAmount - darkenWorldAmountO) * a;
_r = _r * (1.0f - amount) + (_r * .7f) * amount;
_g = _g * (1.0f - amount) + (_g * .6f) * amount;
_b = _b * (1.0f - amount) + (_b * .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)) {
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) _r = 1;
if (_g > 1) _g = 1;
if (_b > 1) _b = 1;
float brightness = 0.0f; // 4J - TODO - was mc->options->gamma;
float ir = 1 - _r;
float ig = 1 - _g;
float ib = 1 - _b;
ir = 1 - (ir * ir * ir * ir);
ig = 1 - (ig * ig * ig * ig);
ib = 1 - (ib * ib * ib * ib);
_r = _r * (1 - brightness) + ir * brightness;
_g = _g * (1 - brightness) + ig * brightness;
_b = _b * (1 - brightness) + ib * brightness;
_r = _r * 0.96f + 0.03f;
_g = _g * 0.96f + 0.03f;
_b = _b * 0.96f + 0.03f;
if (_r > 1) _r = 1;
if (_g > 1) _g = 1;
if (_b > 1) _b = 1;
if (_r < 0) _r = 0;
if (_g < 0) _g = 0;
if (_b < 0) _b = 0;
int alpha = 255;
int r = (int)(_r * 255);
int g = (int)(_g * 255);
int b = (int)(_b * 255);
#if (defined _DURANGO || defined _WIN64 || __PSVITA__ || __linux__)
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));
// lightTexture->upload(); // 4J: not relevant
//_updateLightTexture = false;
}
}
float GameRenderer::getNightVisionScale(std::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 = std::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 = InputManager.GetMouseX() * screenWidth / mc->width;
int yMouse = InputManager.GetMouseY() * 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(uint8_t* 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(void* lpParam) {
Minecraft* minecraft = Minecraft::GetInstance();
AABB::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();
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);
std::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);
}
// 4jcraft: needs to be enabled for proper transparent texturing on low
// render dists this was done in renderSky() for the far and normal
// dists but was missing here, UPDATE: Also needed for the nether, so
// just enable it unconditionally
glEnable(GL_ALPHA_TEST);
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)
{
std::shared_ptr<Player> player =
std::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)) {
std::shared_ptr<Player> player =
std::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(),
std::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);
std::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(
std::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(std::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;
}
}
}
std::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);
// 4jcraft: this color call made rain invisible
// 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*/) {
int fbw, fbh;
RenderManager.GetFramebufferSize(fbw, fbh);
// 4jcraft: use actual framebuffer dimensions instead of mc->width/height
// to ensure GUI scales correctly after a window resize.
ScreenSizeCalculator ssc(mc->options, fbw, fbh, 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;
std::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(-1, 0, 0)
: Vec3(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);
uint8_t redComponent = ((colour >> 16) & 0xFF);
uint8_t greenComponent = ((colour >> 8) & 0xFF);
uint8_t 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);
uint8_t redComponent = ((colour >> 16) & 0xFF);
uint8_t greenComponent = ((colour >> 8) & 0xFF);
uint8_t 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) {
std::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 =
(std::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, std::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);
}