Files
minecraft-pe-0.6.1/src/client/renderer/GameRenderer.cpp
Shredder aa9fa659df Extremely Big Update - fileshredder
(MAJOR)Added Java Beta/Normal Shading, toggleble in settings

Fixed and restored the unused Item Switching Animation, toggleble in tweaks too

Added Dynamic Texture for Lava

Added option to use Block Outline Selection which was unused normally

Added Split Touch Controls into Options

Mobs will now drop cooked variants of their meat if they died by fire

Fixed Untranslated Strings in Settings

(MAJOR) Ravines and Lava/Water pools have been fixed and renabled

Tweaked BasicTree to hopefully speed up generation a bit, might disable them temporarily if they keep being slow

You can now grow Fancy Oak Trees using saplings.
2026-04-11 14:45:47 +05:00

964 lines
28 KiB
C++
Executable File

#include "GameRenderer.h"
#include "client/Options.h"
#include "gles.h"
#include "Lighting.h"
#include "../../util/PerfTimer.h"
#include "LevelRenderer.h"
#include "ItemInHandRenderer.h"
#include "culling/AllowAllCuller.h"
#include "culling/FrustumCuller.h"
#include "entity/EntityRenderDispatcher.h"
#include "../Minecraft.h"
#include "../gamemode/GameMode.h"
#include "../particle/ParticleEngine.h"
#include "../player/LocalPlayer.h"
#include "../gui/Screen.h"
#include "../../world/level/Level.h"
#include "../../world/entity/Mob.h"
#include "../../world/level/chunk/ChunkCache.h"
#include "../../world/level/material/Material.h"
#include "../../world/Facing.h"
#include "../../platform/input/Controller.h"
#include "../../platform/input/Mouse.h"
#include "../../platform/input/Multitouch.h"
#include "../../NinecraftApp.h"
#include "../../world/level/tile/Tile.h"
#include "../player/input/IInputHolder.h"
#include "Textures.h"
#include "../gui/components/ImageButton.h"
#include "Tesselator.h"
static int _shTicks = -1;
GameRenderer::GameRenderer( Minecraft* mc )
: mc(mc),
renderDistance(0),
_tick(0),
_lastTickT(0),
fovOffset(0),
fovOffsetO(0),
fov(1), oFov(1),
_setupCameraFov(0),
zoom(1), zoom_x(0), zoom_y(0),
cameraRoll(0), cameraRollO(0),
pickDirection(1, 0, 0),
thirdDistance(4), thirdDistanceO(4),
thirdRotation(0), thirdRotationO(0),
thirdTilt(0), thirdTiltO(0),
fogBr(0), fogBrO(0),
fr(0), fg(0), fb(0),
_rotX(0), _rotY(0),
_rotXlast(0), _rotYlast(0),
useScreenScissor(false)
{
saveMatrices();
itemInHandRenderer = new ItemInHandRenderer(mc);
EntityRenderDispatcher* e = EntityRenderDispatcher::getInstance();
e->itemInHandRenderer = itemInHandRenderer;
e->textures = mc->textures;
}
GameRenderer::~GameRenderer() {
delete itemInHandRenderer;
}
void renderCursor(float x, float y, Minecraft* minecraft) {
Tesselator& t = Tesselator::instance;
minecraft->textures->loadAndBindTexture("gui/cursor.png");
glEnable(GL_BLEND);
const float s = 32;
const float width = 16;
const float height = 16;
t.begin();
t.color(0xffffffff);
t.vertexUV(x, y + (float)height, 0, 0, 1);
t.vertexUV(x + (float)width, y + (float)height, 0, 1, 1);
t.vertexUV(x + (float)width, y, 0, 1, 0);
t.vertexUV(x, y, 0, 0, 0);
t.draw();
glDisable(GL_BLEND);
}
/*private*/
void GameRenderer::setupCamera(float a, int eye) {
renderDistance = (float) (16 * 16 >> (mc->options.getIntValue(OPTIONS_VIEW_DISTANCE)));
#if defined(ANDROID)
if (mc->isPowerVR() && mc->options.getIntValue(OPTIONS_VIEW_DISTANCE) <= 2)
renderDistance *= 0.8f;
#endif
glMatrixMode(GL_PROJECTION);
glLoadIdentity2();
float stereoScale = 0.07f;
if (mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) glTranslatef2(-(eye * 2 - 1) * stereoScale, 0, 0);
if (zoom != 1) {
glTranslatef2((float) zoom_x, (float) -zoom_y, 0);
glScalef2(zoom, zoom, 1);
gluPerspective(_setupCameraFov = getFov(a, true), mc->width / (float) mc->height, 0.05f, renderDistance);
} else {
gluPerspective(_setupCameraFov = getFov(a, true), mc->width / (float) mc->height, 0.05f, renderDistance);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity2();
if (mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) glTranslatef2((eye * 2 - 1) * 0.10f, 0, 0);
bobHurt(a);
if (mc->options.getBooleanValue(OPTIONS_VIEW_BOBBING)) bobView(a);
moveCameraToPlayer(a);
}
extern int _t_keepPic;
/*public*/
void GameRenderer::render(float a) {
TIMER_PUSH("mouse");
if (mc->player && mc->mouseGrabbed) {
mc->mouseHandler.poll();
//printf("Controller.x,y : %f,%f\n", Controller::getX(0), Controller::getY(0));
float ss = mc->options.getProgressValue(OPTIONS_SENSITIVITY) * 0.6f + 0.2f;
float sens = (ss * ss * ss) * 8;
float xo = mc->mouseHandler.xd * sens * 4.f;
float yo = mc->mouseHandler.yd * sens * 4.f;
const float now = _tick + a;
float deltaT = now - _lastTickT;
if (deltaT > 3.0f) deltaT = 3.0f;
_lastTickT = now;
_rotX += xo;
_rotY += yo;
int yAxis = -1;
if (mc->options.getBooleanValue(OPTIONS_INVERT_Y_MOUSE)) yAxis = 1;
bool screenCovering = mc->screen && !mc->screen->passEvents;
if (!screenCovering)
{
mc->player->turn(deltaT * _rotXlast, deltaT * _rotYlast * yAxis);
}
}
int xMouse = (int)(Mouse::getX() * Gui::InvGuiScale);
int yMouse = (int)(Mouse::getY() * Gui::InvGuiScale);
if (mc->useTouchscreen()) {
const int pid = Multitouch::getFirstActivePointerIdExThisUpdate();
if (pid >= 0) {
xMouse = (int)(Multitouch::getX(pid) * Gui::InvGuiScale);
yMouse = (int)(Multitouch::getY(pid) * Gui::InvGuiScale);
} else {
xMouse = -9999;
yMouse = -9999;
}
}
TIMER_POP();
bool hasClearedColorBuffer = false;
bool hasSetupGuiScreen = false;
useScreenScissor = false;
if (mc->isLevelGenerated()) {
TIMER_PUSH("level");
if (_t_keepPic < 0) {
if (!(mc->screen && !mc->screen->renderGameBehind())) {
if (mc->screen && mc->screen->hasClippingArea(screenScissorArea))
useScreenScissor = true;
renderLevel(a);
hasClearedColorBuffer = true;
if (!mc->options.getBooleanValue(OPTIONS_HIDEGUI)) {
TIMER_POP_PUSH("gui");
setupGuiScreen(false);
hasSetupGuiScreen = true;
mc->gui.render(a, mc->screen != NULL, xMouse, yMouse);
}
}}
TIMER_POP();
} else {
glViewport(0, 0, mc->width, mc->height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity2();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity2();
setupGuiScreen(true);
hasSetupGuiScreen = true;
hasClearedColorBuffer = true;
}
//@todo
if (!hasSetupGuiScreen)
setupGuiScreen(!hasClearedColorBuffer);
if (mc->player && mc->screen == NULL) {
if (mc->inputHolder) mc->inputHolder->render(a);
if (mc->player->input) mc->player->input->render(a);
}
if (mc->screen != NULL) {
if (useScreenScissor)
glDisable2(GL_SCISSOR_TEST);
mc->screen->render(xMouse, yMouse, a);
mc->platform()->hideCursor(!mc->options.getBooleanValue(OPTIONS_RPI_CURSOR));
if (mc->options.getBooleanValue(OPTIONS_RPI_CURSOR))
renderCursor(xMouse, yMouse, mc);
// Screen might have been removed, so check it again
if (mc->screen && !mc->screen->isInGameScreen())
sleepMs(15);
}
}
/*public*/
void GameRenderer::renderLevel(float a) {
if (mc->cameraTargetPlayer == NULL) {
if (mc->player)
{
mc->cameraTargetPlayer = mc->player;
}
else
{
return;
}
}
TIMER_PUSH("pick");
pick(a);
Mob* cameraEntity = mc->cameraTargetPlayer;
LevelRenderer* levelRenderer = mc->levelRenderer;
ParticleEngine* particleEngine = mc->particleEngine;
float xOff = cameraEntity->xOld + (cameraEntity->x - cameraEntity->xOld) * a;
float yOff = cameraEntity->yOld + (cameraEntity->y - cameraEntity->yOld) * a;
float zOff = cameraEntity->zOld + (cameraEntity->z - cameraEntity->zOld) * a;
for (int i = 0; i < 2; i++) {
if (mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) {
if (i == 0) glColorMask(false, true, true, false);
else glColorMask(true, false, false, false);
}
TIMER_POP_PUSH("clear");
glViewport(0, 0, mc->width, mc->height);
setupClearColor(a);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable2(GL_CULL_FACE);
TIMER_POP_PUSH("camera");
setupCamera(a, i);
saveMatrices();
if (useScreenScissor) {
glEnable2(GL_SCISSOR_TEST);
glScissor( screenScissorArea.x, screenScissorArea.y,
screenScissorArea.w, screenScissorArea.h);
}
if(mc->options.getBooleanValue(OPTIONS_FANCY_GRAPHICS)) {
setupFog(-1);
TIMER_POP_PUSH("sky");
glFogf(GL_FOG_START, renderDistance * 0.2f);
glFogf(GL_FOG_END, renderDistance *0.75);
levelRenderer->renderSky(a);
glFogf(GL_FOG_START, renderDistance * 0.6f);
glFogf(GL_FOG_END, renderDistance);
}
glEnable2(GL_FOG);
setupFog(1);
if (mc->options.getBooleanValue(OPTIONS_AMBIENT_OCCLUSION)) {
glShadeModel2(GL_SMOOTH);
}
TIMER_POP_PUSH("frustrum");
FrustumCuller frustum;
frustum.prepare(xOff, yOff, zOff);
TIMER_POP_PUSH("culling");
mc->levelRenderer->cull(&frustum, a);
mc->levelRenderer->updateDirtyChunks(cameraEntity, false);
if(mc->options.getBooleanValue(OPTIONS_FANCY_GRAPHICS)) {
prepareAndRenderClouds(levelRenderer, a);
}
setupFog(0);
glEnable2(GL_FOG);
mc->textures->loadAndBindTexture("terrain.png");
Lighting::turnOff();
glDisable2(GL_ALPHA_TEST);
glDisable2(GL_BLEND);
glEnable2(GL_CULL_FACE);
TIMER_POP_PUSH("terrain-0");
levelRenderer->render(cameraEntity, 0, a);
TIMER_POP_PUSH("terrain-1");
glEnable2(GL_ALPHA_TEST);
levelRenderer->render(cameraEntity, 1, a);
glShadeModel2(GL_FLAT);
Lighting::turnOn(mc);
TIMER_POP_PUSH("entities");
mc->levelRenderer->renderEntities(cameraEntity->getPos(a), &frustum, a);
// setupFog(0);
TIMER_POP_PUSH("particles");
particleEngine->render(cameraEntity, a);
Lighting::turnOff();
glDisable2(GL_BLEND);
glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
setupFog(0);
glEnable2(GL_BLEND);
glDisable2(GL_CULL_FACE);
glDepthMask(GL_FALSE);
glDisable2(GL_ALPHA_TEST);
mc->textures->loadAndBindTexture("terrain.png");
//if (mc->options.fancyGraphics) {
// glColorMask(false, false, false, false);
// int visibleWaterChunks = levelRenderer->render(cameraEntity, 1, a);
// glColorMask(true, true, true, true);
// if (mc->options.anaglyph3d) {
// if (i == 0) glColorMask(false, true, true, false);
// else glColorMask(true, false, false, false);
// }
// if (visibleWaterChunks > 0) {
// levelRenderer->renderSameAsLast(1, a);
// }
//} else
{
//glDepthRangef(0.1f, 1.0f);
//glDepthMask(GL_FALSE);
TIMER_POP_PUSH("terrain-water");
glEnable2(GL_DEPTH_TEST);
levelRenderer->render(cameraEntity, 2, a);
//glDepthRangef(0, 1);
}
glDepthMask(GL_TRUE);
glEnable2(GL_CULL_FACE);
glDisable2(GL_BLEND);
glEnable2(GL_ALPHA_TEST);
if (/*!Minecraft::FLYBY_MODE &&*/ zoom == 1 && cameraEntity->isPlayer()) {
if (mc->hitResult.isHit() && !cameraEntity->isUnderLiquid(Material::water)) {
TIMER_POP_PUSH("select");
Player* player = (Player*) cameraEntity;
// if (mc->useTouchscreen()) {
if (mc->options.getBooleanValue(OPTIONS_BLOCK_OUTLINE)){
levelRenderer->renderHitOutline(player, mc->hitResult, 0, NULL, a); //player.inventory->getSelected(), a); // java block outline one
} else {
levelRenderer->renderHitSelect(player, mc->hitResult, 0, NULL, a); //player.inventory->getSelected(), a); // normal pe one - shredder
}
levelRenderer->renderHit(player, mc->hitResult, 0, NULL, a);//player->inventory.getSelected(), a);
}
}
glDisable2(GL_FOG);
//
// setupFog(0);
// glEnable2(GL_FOG);
//// levelRenderer->renderClouds(a);
// glDisable2(GL_FOG);
setupFog(1);
if (zoom == 1 && !mc->options.getBooleanValue(OPTIONS_HIDEGUI)) {
TIMER_POP_PUSH("hand");
glClear(GL_DEPTH_BUFFER_BIT);
renderItemInHand(a, i);
}
if (!mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) {
TIMER_POP();
return;
}
}
glColorMask(true, true, true, false);
TIMER_POP();
}
void GameRenderer::tickFov() {
if (mc->cameraTargetPlayer != mc->player)
return;
oFov = fov;
fov += (mc->player->getFieldOfViewModifier() - fov) * 0.5f;
}
/*private*/
float GameRenderer::getFov(float a, bool applyEffects) {
Mob* player = mc->cameraTargetPlayer;
float fov = 70;
if (applyEffects)
fov *= this->oFov + (this->fov - this->oFov) * a;
if (player->isUnderLiquid(Material::water)) fov = 60;
if (player->health <= 0) {
float duration = player->deathTime + a;
fov /= ((1 - 500 / (duration + 500)) * 2.0f + 1);
}
return fov + fovOffsetO + (fovOffset - fovOffsetO) * a;
}
/*private*/
void GameRenderer::moveCameraToPlayer(float a) {
Entity* player = mc->cameraTargetPlayer;
float heightOffset = player->heightOffset - 1.62f;
float x = player->xo + (player->x - player->xo) * a;
float y = player->yo + (player->y - player->yo) * a - heightOffset;
//printf("camera y: %f\n", y);
float z = player->zo + (player->z - player->zo) * a;
//printf("rot: %f %f\n", cameraRollO, cameraRoll);
glRotatef2(cameraRollO + (cameraRoll - cameraRollO) * a, 0, 0, 1);
//LOGI("player. alive, removed: %d, %d\n", player->isAlive(), player->removed);
if(player->isPlayer() && ((Player*)player)->isSleeping()) {
heightOffset += 1.0;
glTranslatef(0.0f, 0.3f, 0);
if (!mc->options.getBooleanValue(OPTIONS_FIXED_CAMERA)) {
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, 1, 0);
}
glRotatef(player->yRotO + (player->yRot - player->yRotO) * a + 180, 0, -1, 0);
glRotatef(player->xRotO + (player->xRot - player->xRotO) * a, -1, 0, 0);
}
} else if (mc->options.getBooleanValue(OPTIONS_THIRD_PERSON_VIEW)/* || (player->isPlayer() && !player->isAlive())*/) {
float cameraDist = thirdDistanceO + (thirdDistance - thirdDistanceO) * a;
if (mc->options.getBooleanValue(OPTIONS_FIXED_CAMERA)) {
float rotationY = thirdRotationO + (thirdRotation - thirdRotationO) * a;
float xRot = thirdTiltO + (thirdTilt - thirdTiltO) * a;
glTranslatef2(0, 0, (float) -cameraDist);
glRotatef2(xRot, 1, 0, 0);
glRotatef2(rotationY, 0, 1, 0);
} else {
float yRot = player->yRot;
float xRot = player->xRot/* + 180.0f*/;
float xd = -Mth::sin(yRot / 180 * Mth::PI) * Mth::cos(xRot / 180 * Mth::PI) * cameraDist;
float zd = Mth::cos(yRot / 180 * Mth::PI) * Mth::cos(xRot / 180 * Mth::PI) * cameraDist;
float yd = -Mth::sin(xRot / 180 * Mth::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;
HitResult hr = mc->level->clip(Vec3(x + xo, y + yo, z + zo), Vec3(x - xd + xo + zo, y - yd + yo, z - zd + zo)); // newTemp
if (hr.type != NO_HIT) {
float dist = hr.pos.distanceTo(Vec3(x, y, z)); // newTemp
if (dist < cameraDist) cameraDist = dist;
}
}
//glRotatef2(180, 0, 1, 0);
glRotatef2(player->xRot - xRot, 1, 0, 0);
glRotatef2(player->yRot - yRot, 0, 1, 0);
glTranslatef2(0, 0, (float) -cameraDist);
glRotatef2(yRot - player->yRot, 0, 1, 0);
glRotatef2(xRot - player->xRot, 1, 0, 0);
}
} else {
glTranslatef2(0, 0, -0.1f);
}
if (!mc->options.getBooleanValue(OPTIONS_FIXED_CAMERA)) {
glRotatef2(player->xRotO + (player->xRot - player->xRotO) * a, 1.0f, 0.0f, 0.0f);
glRotatef2(player->yRotO + (player->yRot - player->yRotO) * a + 180, 0, 1, 0);
//if (_t_keepPic > 0)
}
glTranslatef2(0, heightOffset, 0);
}
/*private*/
void GameRenderer::bobHurt(float a) {
Mob* player = mc->cameraTargetPlayer;
float hurt = player->hurtTime - a;
if (player->health <= 0) {
float duration = player->deathTime + a;
glRotatef2(40 - (40 * 200) / (duration + 200), 0, 0, 1);
}
if (player->hurtTime <= 0) return;
hurt /= player->hurtDuration;
hurt = (float) Mth::sin(hurt * hurt * hurt * hurt * Mth::PI);
float rr = player->hurtDir;
glRotatef2(-rr, 0, 1, 0);
glRotatef2(-hurt * 14, 0, 0, 1);
glRotatef2(+rr, 0, 1, 0);
}
/*private*/
void GameRenderer::bobView(float a) {
//if (mc->options.thirdPersonView) return;
if (!(mc->cameraTargetPlayer->isPlayer())) {
return;
}
Player* player = (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;
glTranslatef2((float) Mth::sin(b * Mth::PI) * bob * 0.5f, -(float) std::abs(Mth::cos(b * Mth::PI) * bob), 0);
glRotatef2((float) Mth::sin(b * Mth::PI) * bob * 3, 0, 0, 1);
glRotatef2((float) std::abs(Mth::cos(b * Mth::PI - 0.2f) * bob) * 5, 1, 0, 0);
glRotatef2((float) tilt, 1, 0, 0);
}
/*private*/
void GameRenderer::setupFog(int i) {
Mob* player = mc->cameraTargetPlayer;
float fogBuffer[4] = {fr, fg, fb, 1};
glFogfv(GL_FOG_COLOR, (GLfloat*)fogBuffer);
glColor4f2(1, 1, 1, 1);
if (player->isUnderLiquid(Material::water)) {
glFogx(GL_FOG_MODE, GL_EXP);
glFogf(GL_FOG_DENSITY, 0.1f); // was 0.06
// float rr = 0.4f;
// float gg = 0.4f;
// float bb = 0.9f;
//
// if (mc->options.anaglyph3d) {
// float rrr = (rr * 30 + gg * 59 + bb * 11) / 100;
// float ggg = (rr * 30 + gg * 70) / (100);
// float bbb = (rr * 30 + bb * 70) / (100);
//
// rr = rrr;
// gg = ggg;
// bb = bbb;
// }
} else if (player->isUnderLiquid(Material::lava)) {
glFogx(GL_FOG_MODE, GL_EXP);
glFogf(GL_FOG_DENSITY, 2.f); // was 0.06
// float rr = 0.4f;
// float gg = 0.3f;
// float bb = 0.3f;
//
// if (mc->options.anaglyph3d) {
// float rrr = (rr * 30 + gg * 59 + bb * 11) / 100;
// float ggg = (rr * 30 + gg * 70) / (100);
// float bbb = (rr * 30 + bb * 70) / (100);
//
// rr = rrr;
// gg = ggg;
// bb = bbb;
// }
} else {
glFogx(GL_FOG_MODE, GL_LINEAR);
glFogf(GL_FOG_START, renderDistance * 0.6f);
glFogf(GL_FOG_END, renderDistance);
if (i < 0) {
glFogf(GL_FOG_START, 0);
glFogf(GL_FOG_END, renderDistance * 1.0f);
}
if (mc->level->dimension->foggy) {
glFogf(GL_FOG_START, 0);
}
}
glEnable2(GL_COLOR_MATERIAL);
//glColorMaterial(GL_FRONT, GL_AMBIENT);
}
void GameRenderer::updateAllChunks() {
mc->levelRenderer->updateDirtyChunks(mc->cameraTargetPlayer, true);
}
bool GameRenderer::updateFreeformPickDirection(float a, Vec3& outDir) {
if (!mc->inputHolder->allowPicking()) {
_shTicks = 1;
return false;
}
Vec3 c = mc->cameraTargetPlayer->getPos(a);
bool firstPerson = !mc->options.getBooleanValue(OPTIONS_THIRD_PERSON_VIEW);
const float PickingDistance = firstPerson? 6.0f : 12.0f;
_shTicks = -1;
int vp[4] = {0, 0, mc->width, mc->height};
float pt[3];
float x = mc->inputHolder->mousex;
float y = mc->height - mc->inputHolder->mousey;
//sw.start();
if (!glhUnProjectf(x, y, 1, lastModelMatrix, lastProjMatrix, vp, pt)) {
return false;
}
Vec3 p1(pt[0] + c.x, pt[1] + c.y, pt[2] + c.z);
glhUnProjectf(x, y, 0, lastModelMatrix, lastProjMatrix, vp, pt);
Vec3 p0(pt[0] + c.x, pt[1] + c.y, pt[2] + c.z);
outDir = (p1 - p0).normalized();
p1 = p0 + outDir * PickingDistance;
//sw.stop();
//sw.printEvery(30, "unproject ");
const HitResult& hit = mc->hitResult = mc->level->clip(p0, p1, false);
// If in 3rd person view - verify that the hit target is within range
if (!firstPerson && hit.isHit()) {
const float MaxSqrDist = PickingDistance*PickingDistance;
if (mc->cameraTargetPlayer->distanceToSqr((float)hit.x, (float)hit.y, (float)hit.z) > MaxSqrDist)
mc->hitResult.type = NO_HIT;
}
return true;
}
/*public*/
void GameRenderer::pick(float a) {
if (mc->level == NULL) return;
if (mc->cameraTargetPlayer == NULL) return;
if (!mc->cameraTargetPlayer->isAlive()) return;
float range = mc->gameMode->getPickRange();
bool isPicking = true;
bool freeform = mc->useTouchscreen(); //&& !mc->options.getBooleanValue(OPTIONS_IS_JOY_TOUCH_AREA);
if (freeform) {
isPicking = updateFreeformPickDirection(a, pickDirection);
} else {
mc->hitResult = mc->cameraTargetPlayer->pick(range, a);
pickDirection = mc->cameraTargetPlayer->getViewVector(a);
}
Vec3 from = mc->cameraTargetPlayer->getPos(a);
float dist = range;
if (mc->hitResult.isHit()) {
dist = mc->hitResult.pos.distanceTo(from);
}
if (mc->gameMode->isCreativeType()) {
/*dist =*/ range = 12;
} else {
if (dist > 3) dist = 3;
range = dist;
}
Vec3 pv = (pickDirection * range);
Vec3 to = from + pv;
mc->cameraTargetPlayer->aimDirection = pickDirection;
Entity* hovered = NULL;
const float g = 1;
AABB aabb = mc->cameraTargetPlayer->bb.expand(pv.x, pv.y, pv.z).grow(g, g, g);
EntityList& objects = mc->level->getEntities(mc->cameraTargetPlayer, aabb);
float nearest = 0;
for (unsigned int i = 0; i < objects.size(); i++) {
Entity* e = objects[i];
if (!e->isPickable()) continue;
float rr = e->getPickRadius();
AABB bb = e->bb.grow(rr, rr, rr);
HitResult p = bb.clip(from, to);
//printf("Clip Hitresult %d (%d)\n", p.type, p.isHit());
if (bb.contains(from)) {
//@todo: hovered = e; break; ?
if (nearest >= 0) {
hovered = e;
nearest = 0;
}
} else if (p.isHit()) {
float dd = from.distanceTo(p.pos);
if (dd < nearest || nearest == 0) {
hovered = e;
nearest = dd;
}
}
}
if (hovered != NULL) {
if(nearest < dist) {
mc->hitResult = HitResult(hovered);
}
}
else if (isPicking && !mc->hitResult.isHit()) {
// if we don't have a hit result, attempt to hit the edge of the block we are standing on
// (this is an pocket edition simplification to help building floors)
//LOGI("hovered : %d (%f)\n", mc->hitResult.type, viewVec.y);
if (pickDirection.y < -.7f) {
// looking down by more than roughly 45 degrees, fetch a hit to the block standing on
Vec3 to = from.add(0, -2.0f, 0);
HitResult downHitResult = mc->level->clip(from, to);
if (downHitResult.isHit()) {
mc->hitResult = downHitResult;
mc->hitResult.indirectHit = true;
// change face (not up)
if (std::abs(pickDirection.x) > std::abs(pickDirection.z)) {
mc->hitResult.f = (pickDirection.x < 0)? 4 : 5;
} else {
mc->hitResult.f = (pickDirection.z < 0)? 2 : 3;
}
}
}
}
}
/*public*/
void GameRenderer::tick(int nTick, int maxTick) {
--_t_keepPic;
if (!mc->player)
{
return;
}
if (--_shTicks == 0)
mc->hitResult.type = NO_HIT;
//_rotXlast = _rotX;
//_rotYlast = _rotY;
//LOGI("x: %f\n", _rotX);
if (nTick == maxTick) {
const float tickMult = 1.0f / (float)(1 + maxTick);
_rotXlast = 0.4f * std::pow(std::abs(_rotX), 1.2f) * tickMult;
if (_rotX < 0) _rotXlast = -_rotXlast;
_rotYlast = 0.4f * std::pow(std::abs(_rotY), 1.2f) * tickMult;
if (_rotY < 0) _rotYlast = -_rotYlast;
_rotX = 0;
_rotY = 0;
}
fogBrO = fogBr;
thirdDistanceO = thirdDistance;
thirdRotationO = thirdRotation;
thirdTiltO = thirdTilt;
fovOffsetO = fovOffset;
cameraRollO = cameraRoll;
if (mc->cameraTargetPlayer == NULL) {
mc->cameraTargetPlayer = mc->player;
}
tickFov();
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.getIntValue(OPTIONS_VIEW_DISTANCE)) / 3.0f;
float fogBrT = brr * (1 - whiteness) + whiteness;
fogBr += (fogBrT - fogBr) * 0.1f;
_tick++;
itemInHandRenderer->tick();
// if (mc->isRaining) tickRain();
}
/*private*/
void GameRenderer::setupClearColor(float a) {
Level* level = mc->level;
Mob* player = mc->cameraTargetPlayer;
float whiteness = 1.0f / (4 - mc->options.getIntValue(OPTIONS_VIEW_DISTANCE));
whiteness = 1 - (float) pow(whiteness, 0.25f);
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;
fr += (sr - fr) * whiteness;
fg += (sg - fg) * whiteness;
fb += (sb - fb) * whiteness;
if (player->isUnderLiquid(Material::water)) {
fr = 0.02f;
fg = 0.02f;
fb = 0.2f;
} else if (player->isUnderLiquid(Material::lava)) {
fr = 0.6f;
fg = 0.1f;
fb = 0.00f;
}
float brr = fogBrO + (fogBr - fogBrO) * a;
fr *= brr;
fg *= brr;
fb *= brr;
if (mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) {
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, 1.0f);
}
void GameRenderer::zoomRegion( float zoom, float xa, float ya )
{
this->zoom = zoom;
this->zoom_x = xa;
this->zoom_y = ya;
}
void GameRenderer::unZoomRegion()
{
zoom = 1;
}
void GameRenderer::setupGuiScreen( bool clearColorBuffer )
{
int screenWidth = (int)(mc->width * Gui::InvGuiScale);
int screenHeight = (int)(mc->height * Gui::InvGuiScale);
// Setup GUI render mode
GLbitfield clearBits = clearColorBuffer?
GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT
: GL_DEPTH_BUFFER_BIT;
glClear(clearBits);
glMatrixMode(GL_PROJECTION);
glLoadIdentity2();
glOrthof(0, (GLfloat)screenWidth, (GLfloat)screenHeight, 0, 2000, 3000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity2();
glTranslatef2(0, 0, -2000);
}
/*private*/
void GameRenderer::renderItemInHand(float a, int eye) {
glLoadIdentity2();
if (mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) glTranslatef2((eye * 2 - 1) * 0.10f, 0, 0);
glPushMatrix2();
bobHurt(a);
if (mc->options.getBooleanValue(OPTIONS_VIEW_BOBBING)) bobView(a);
if (!mc->options.getBooleanValue(OPTIONS_THIRD_PERSON_VIEW) && (mc->cameraTargetPlayer->isPlayer() && !((Player*)mc->cameraTargetPlayer)->isSleeping())) {
if (!mc->options.getBooleanValue(OPTIONS_HIDEGUI)) {
float fov = getFov(a, false);
if (fov != _setupCameraFov) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fov, mc->width / (float) mc->height, 0.05f, renderDistance);
glMatrixMode(GL_MODELVIEW);
}
itemInHandRenderer->render(a);
}
}
glPopMatrix2();
if (!mc->options.getBooleanValue(OPTIONS_THIRD_PERSON_VIEW) && (mc->cameraTargetPlayer->isPlayer() && !((Player*)mc->cameraTargetPlayer)->isSleeping())) {
itemInHandRenderer->renderScreenEffect(a);
bobHurt(a);
}
if (mc->options.getBooleanValue(OPTIONS_VIEW_BOBBING)) bobView(a);
}
void GameRenderer::onGraphicsReset()
{
if (itemInHandRenderer) itemInHandRenderer->onGraphicsReset();
}
void GameRenderer::saveMatrices()
{
#if defined(RPI)
return;
#endif
static bool saved = false;
//if (saved) return;
saved = true;
glGetFloatv(GL_PROJECTION_MATRIX, lastProjMatrix);
glGetFloatv(GL_MODELVIEW_MATRIX, lastModelMatrix);
}
void GameRenderer::prepareAndRenderClouds( LevelRenderer* levelRenderer, float a ) {
//if(mc->options.isCloudsOn()) {
TIMER_PUSH("clouds");
glMatrixMode(GL_PROJECTION);
glPushMatrix2();
glLoadIdentity2();
gluPerspective(_setupCameraFov = getFov(a, true), mc->width / (float) mc->height, 2, renderDistance * 512);
glMatrixMode(GL_MODELVIEW);
glPushMatrix2();
setupFog(0);
glDepthMask(false);
glEnable2(GL_FOG);
glFogf(GL_FOG_START, renderDistance * 0.2f);
glFogf(GL_FOG_END, renderDistance * 0.75f);
levelRenderer->renderSky(a);
glFogf(GL_FOG_START, renderDistance * 4.2f * 0.6f);
glFogf(GL_FOG_END, renderDistance * 4.2f);
levelRenderer->renderClouds(a);
glFogf(GL_FOG_START, renderDistance * 0.6f);
glFogf(GL_FOG_END, renderDistance);
glDisable2(GL_FOG);
glDepthMask(true);
setupFog(1);
glPopMatrix2();
glMatrixMode(GL_PROJECTION);
glPopMatrix2();
glMatrixMode(GL_MODELVIEW);
TIMER_POP();
//}
}