mirror of
https://github.com/celisej567/mcpe.git
synced 2025-12-31 17:49:17 +03:00
* Visual Studio Project Overhaul + Cleanup * SDL2 project for Windows * Re-added game client icon to SDL2 code * Renamed "AppPlatform_windows" to "AppPlatform_win32" (this is the name of the Windows API and is not representative of the architecture type) * Renamed "LoggerWindows" to "LoggerWin32" * Renamed "SoundSystemWindows to "SoundSystemDS" (DirectSound). This may be used for the 360, so it wouldn't really be Windows-specific then. * Moved "ClientSideNetworkHandler" from "network" to "client/network". We don't need it being compiled for the server if the client's the only thing that needs it. * I wonder if this still works on macOS... * Bugfixes & Fixed for macOS * Options::savePropertiesToFile Logging Bugfix * Silence Winsock Deprecation Warnings in RakNet * VS Project Improvements - Replaced 50 billion relative paths with $(MC_ROOT) - Added $(RAKNET_PATH) variable to override RakNet location - Re-added gitignore for .vcxproj.user files - Added debugging config to Directory.Builds.props - Slimmed down project configurations for SDL2 * VS Project Config Bugfixes - Fixed RakNet header path for additional includes * RakNet Target for XCode * XCode Project Config Fixes * Packet logging * Network VS Project Filter Fix * Fix RakNet Packet ID Length We previously didn't have consistency between old and new C++ regarding PacketType enum length. Now we do. This is required or else it completely breaks networking between the versions. * Additional RakNet Error Handling * Disable packet logging * * Fix CMakeLists.txt This reflects the relocation of ClientSideNetworkHandler.cpp. * * Also add renderer/GL/GL.cpp to the CMakeLists.txt * * Replace libpng with stb_image * * Fix buggy water behavior. * * Put the CMakeLists of the SDL project in debug mode * Visual Studio 2010 Support * * Change the SdlIoCallbacks from an array to a single member. This fixes compilation of the sdl2 target on VS. * * Fix missing _error label. * Revert "* Fix missing _error label." This reverts commit 99a057fc84049a16c864bd840fb439a008af5c74. * Revert "* Replace libpng with stb_image" * info_updateGame Tiles --------- Co-authored-by: Brent Da Mage <BrentDaMage@users.noreply.github.com> Co-authored-by: iProgramInCpp <iprogramincpp@gmail.com>
1320 lines
29 KiB
C++
1320 lines
29 KiB
C++
/********************************************************************
|
|
Minecraft: Pocket Edition - Decompilation Project
|
|
Copyright (C) 2023 iProgramInCpp
|
|
|
|
The following code is licensed under the BSD 1 clause license.
|
|
SPDX-License-Identifier: BSD-1-Clause
|
|
********************************************************************/
|
|
|
|
#include "LevelRenderer.hpp"
|
|
#include "client/app/Minecraft.hpp"
|
|
#include "renderer/GL/GL.hpp"
|
|
#include "world/tile/LeafTile.hpp"
|
|
|
|
LevelRenderer::LevelRenderer(Minecraft* pMC, Textures* pTexs)
|
|
{
|
|
field_4 = -9999.0f;
|
|
field_8 = -9999.0f;
|
|
field_C = -9999.0f;
|
|
field_10 = 0.0f;
|
|
field_14 = 2;
|
|
field_18 = 0;
|
|
field_1C = 0;
|
|
field_20 = 0;
|
|
field_30 = 0;
|
|
field_54 = 0;
|
|
field_58 = 0;
|
|
field_5C = 0;
|
|
field_60 = 0;
|
|
field_64 = 0;
|
|
field_68 = 0;
|
|
field_6C = 0;
|
|
field_70 = 0;
|
|
field_74 = 0;
|
|
field_78 = 0;
|
|
field_7C = 0;
|
|
field_80 = 0;
|
|
m_pLevel = nullptr;
|
|
m_chunks = nullptr;
|
|
field_98 = nullptr;
|
|
m_chunksLength = 0;
|
|
m_pTileRenderer = nullptr;
|
|
field_A4 = 0;
|
|
field_A8 = 0;
|
|
field_AC = 0;
|
|
field_B0 = 0;
|
|
field_B8 = false;
|
|
field_BC = -1;
|
|
m_ticksSinceStart = 0;
|
|
m_nBuffers = 26136;
|
|
|
|
m_pMinecraft = pMC;
|
|
m_pTextures = pTexs;
|
|
|
|
m_pBuffers = new GLuint[m_nBuffers];
|
|
xglGenBuffers(m_nBuffers, m_pBuffers);
|
|
|
|
LOG_I("numBuffers: %d", m_nBuffers);
|
|
xglGenBuffers(1, &field_D8);
|
|
|
|
generateSky(); // inlined in the 0.1.0 demo
|
|
}
|
|
|
|
void LevelRenderer::generateSky()
|
|
{
|
|
Tesselator& t = Tesselator::instance;
|
|
t.begin();
|
|
field_DC = 0;
|
|
|
|
//float m = 16.0f;
|
|
int n = 4;
|
|
int p = 128;
|
|
|
|
for (int i = n * -p; i <= n * p; i += p)
|
|
{
|
|
for (int j = n * -p; j <= n * p; j += p)
|
|
{
|
|
t.vertex(float(i + 0.0f), 16.0f, float(j + 0.0f));
|
|
t.vertex(float(i + p) , 16.0f, float(j + 0.0f));
|
|
t.vertex(float(i + p) , 16.0f, float(j + p) );
|
|
t.vertex(float(i + 0.0f), 16.0f, float(j + p) );
|
|
|
|
field_DC += 4;
|
|
}
|
|
}
|
|
|
|
t.end(field_D8);
|
|
}
|
|
|
|
void LevelRenderer::deleteChunks()
|
|
{
|
|
for (int i = 0; i < field_AC; i++)
|
|
{
|
|
for (int j = 0; j < field_A8; j++)
|
|
{
|
|
for (int k = 0; k < field_A4; k++)
|
|
{
|
|
int index = k + field_A4 * (j + field_A8 * i);
|
|
delete m_chunks[index];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_chunks)
|
|
delete[] m_chunks;
|
|
m_chunks = nullptr;
|
|
|
|
if (field_98)
|
|
delete[] field_98;
|
|
field_98 = nullptr;
|
|
}
|
|
|
|
void LevelRenderer::cull(Culler* pCuller, float f)
|
|
{
|
|
for (int i = 0; i < m_chunksLength; i++)
|
|
{
|
|
Chunk* pChunk = m_chunks[i];
|
|
if (pChunk->isEmpty())
|
|
continue;
|
|
|
|
//@TODO: What does the shift do? (x % 4 == 0)?
|
|
if (!pChunk->m_bVisible || !((i + field_30) << 28))
|
|
{
|
|
pChunk->cull(pCuller);
|
|
}
|
|
}
|
|
|
|
field_30++;
|
|
}
|
|
|
|
void LevelRenderer::allChanged()
|
|
{
|
|
deleteChunks();
|
|
|
|
LeafTile* pLeaves = (LeafTile*)Tile::leaves;
|
|
|
|
pLeaves->m_bTransparent = m_pMinecraft->getOptions()->m_bFancyGraphics;
|
|
pLeaves->m_TextureFrame = !pLeaves->m_bTransparent + pLeaves->field_74;
|
|
|
|
field_BC = m_pMinecraft->getOptions()->m_iViewDistance;
|
|
|
|
int x1 = 64 << (3 - field_BC);
|
|
if (x1 >= 400)
|
|
x1 = 400;
|
|
|
|
field_A4 = x1 / 16 + 1;
|
|
field_AC = x1 / 16 + 1;
|
|
field_A8 = 8;
|
|
|
|
m_chunksLength = field_A8 * field_A4 * field_AC;
|
|
LOG_I("chunksLength: %d", m_chunksLength);
|
|
m_chunks = new Chunk* [m_chunksLength];
|
|
field_98 = new Chunk* [m_chunksLength];
|
|
|
|
field_6C = 0;
|
|
field_70 = 0;
|
|
field_74 = 0;
|
|
|
|
field_88.clear();
|
|
|
|
field_78 = field_A4;
|
|
field_80 = field_AC;
|
|
field_7C = field_A8;
|
|
|
|
int x2 = 0, x3 = 0;
|
|
|
|
for (int i = 0; i < field_A4; i++)
|
|
{
|
|
if (field_A8 <= 0)
|
|
continue;
|
|
|
|
for (int j = 0; j < field_A8; j++)
|
|
{
|
|
for (int k = 0; k < field_AC; k++)
|
|
{
|
|
int index = i + field_A4 * (j + field_A8 * k);
|
|
|
|
Chunk* pChunk = new Chunk(m_pLevel, 16 * i, 16 * j, 16 * k, 16, x3 + field_B0, &m_pBuffers[x3]);
|
|
|
|
if (field_B8)
|
|
pChunk->field_50 = 0;
|
|
|
|
pChunk->field_4E = false;
|
|
pChunk->field_4D = true;
|
|
pChunk->m_bVisible = true;
|
|
pChunk->field_48 = x2++;
|
|
pChunk->setDirty();
|
|
m_chunks[index] = pChunk;
|
|
field_98[index] = pChunk;
|
|
|
|
x3 += 3;
|
|
field_88.push_back(pChunk);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_pLevel)
|
|
{
|
|
Mob* pMob = m_pMinecraft->m_pMobPersp;
|
|
if (pMob)
|
|
{
|
|
resortChunks(Mth::floor(pMob->m_pos.x), Mth::floor(pMob->m_pos.y), Mth::floor(pMob->m_pos.z));
|
|
|
|
std::sort(&field_98[0], &field_98[m_chunksLength], DistanceChunkSorter(pMob));
|
|
}
|
|
}
|
|
|
|
field_14 = 2;
|
|
}
|
|
|
|
void LevelRenderer::resortChunks(int x, int y, int z)
|
|
{
|
|
int field_A4; // r11
|
|
int z1; // r2
|
|
int field_AC; // r10
|
|
int x2; // r0
|
|
int x3; // r9
|
|
int x5; // r3
|
|
int x9; // r0
|
|
int x10; // r0
|
|
int field_78; // r3
|
|
int x11; // r7
|
|
int field_AC_1; // r5
|
|
int field_A8; // r6
|
|
int x12; // r0
|
|
int x13; // r8
|
|
int field_80; // r3
|
|
int x14; // r5
|
|
int field_A4_1; // r2
|
|
int x15; // r6
|
|
int x16; // r11
|
|
int field_7C; // r3
|
|
bool v25; // cc
|
|
Chunk** m_chunks; // r3
|
|
int x17; // r2
|
|
bool bIsDirty; // r6
|
|
int x6_1; // [sp+0h] [bp-58h]
|
|
int x8_1; // [sp+4h] [bp-54h]
|
|
int x1; // [sp+8h] [bp-50h]
|
|
int x10_1; // [sp+Ch] [bp-4Ch]
|
|
int x4; // [sp+10h] [bp-48h]
|
|
int x7; // [sp+1Ch] [bp-3Ch]
|
|
int x6; // [sp+20h] [bp-38h]
|
|
int x8; // [sp+24h] [bp-34h]
|
|
Chunk* pChunk; // [sp+2Ch] [bp-2Ch] BYREF
|
|
|
|
field_A4 = this->field_A4;
|
|
z1 = 8 - z;
|
|
this->field_6C = 0x7FFFFFFF;
|
|
this->field_70 = 0x7FFFFFFF;
|
|
this->field_74 = 0x7FFFFFFF;
|
|
this->field_78 = 0x80000000;
|
|
this->field_7C = 0x80000000;
|
|
this->field_80 = 0x80000000;
|
|
if (field_A4 > 0)
|
|
{
|
|
x1 = 16 * field_A4;
|
|
field_AC = this->field_AC;
|
|
x2 = (16 * field_A4) >> 1;
|
|
x3 = 0;
|
|
x4 = x2 + 8 - x;
|
|
x5 = 1 - 16 * field_A4;
|
|
x6 = z1 + x2;
|
|
x7 = x5 + x4;
|
|
x8 = z1 + x2 + x5;
|
|
while (1)
|
|
{
|
|
x9 = x4 & ~(x4 >> 31);
|
|
if (x4 < 0)
|
|
x9 = x7;
|
|
x10 = 16 * x3 - x1 * (x9 / x1);
|
|
field_78 = this->field_78;
|
|
x10_1 = x10;
|
|
if (x10 < this->field_6C)
|
|
this->field_6C = x10;
|
|
if (x10 > field_78)
|
|
this->field_78 = x10;
|
|
if (field_AC > 0)
|
|
break;
|
|
LABEL_32:
|
|
++x3;
|
|
x4 += 16;
|
|
x7 += 16;
|
|
if (field_A4 <= x3)
|
|
return;
|
|
}
|
|
x11 = 0;
|
|
field_AC_1 = field_AC;
|
|
field_A8 = this->field_A8;
|
|
x6_1 = x6;
|
|
x8_1 = x8;
|
|
while (1)
|
|
{
|
|
x12 = x6_1 & ~(x6_1 >> 31);
|
|
if (x6_1 < 0)
|
|
x12 = x8_1;
|
|
x13 = 16 * x11 - x1 * (x12 / x1);
|
|
field_80 = this->field_80;
|
|
if (x13 < this->field_74)
|
|
this->field_74 = x13;
|
|
if (x13 > field_80)
|
|
this->field_80 = x13;
|
|
if (field_A8 > 0)
|
|
break;
|
|
LABEL_30:
|
|
++x11;
|
|
x6_1 += 16;
|
|
x8_1 += 16;
|
|
if (field_AC_1 <= x11)
|
|
{
|
|
field_AC = field_AC_1;
|
|
goto LABEL_32;
|
|
}
|
|
}
|
|
x14 = 0;
|
|
for (field_A4_1 = field_A4; ; field_A4_1 = this->field_A4)
|
|
{
|
|
x15 = x14 + field_A8 * x11;
|
|
x16 = 16 * x14;
|
|
field_7C = this->field_7C;
|
|
if (this->field_70 > 16 * x14)
|
|
this->field_70 = x16;
|
|
v25 = field_7C < x16;
|
|
m_chunks = this->m_chunks;
|
|
x17 = x3 + field_A4_1 * x15;
|
|
if (v25)
|
|
this->field_7C = x16;
|
|
pChunk = m_chunks[x17];
|
|
bIsDirty = pChunk->isDirty();
|
|
pChunk->Chunk::setPos(x10_1, 16 * x14, x13);
|
|
if (bIsDirty || !pChunk->isDirty())
|
|
goto LABEL_19;
|
|
|
|
if (true) // need to expand
|
|
break;
|
|
|
|
++x14;
|
|
|
|
field_A8 = this->field_A8;
|
|
|
|
if (field_A8 <= x14)
|
|
{
|
|
LABEL_29:
|
|
field_A4 = this->field_A4;
|
|
field_AC_1 = this->field_AC;
|
|
goto LABEL_30;
|
|
}
|
|
LABEL_20:
|
|
;
|
|
}
|
|
this->field_88.push_back(pChunk);
|
|
LABEL_19:
|
|
field_A8 = this->field_A8;
|
|
if (field_A8 <= ++x14)
|
|
goto LABEL_29;
|
|
goto LABEL_20;
|
|
}
|
|
}
|
|
|
|
void LevelRenderer::entityAdded(Entity* pEnt)
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
std::string LevelRenderer::gatherStats1()
|
|
{
|
|
//@NOTE: This data is based on the Java Edition pre-1.8 legend. This may not be accurate, but it's a good guideline.
|
|
//See https://minecraft.fandom.com/wiki/Debug_screen#Pre-1.8_legend
|
|
std::stringstream ss;
|
|
ss << "C: " << field_60 << "/" << field_54 // Number of chunk sections rendered over total number of chunks.
|
|
<< ". F: " << field_58 // Number of chunk sections loaded outside the viewing distance.
|
|
<< ", O: " << field_5C // Number of occluded chunk sections.
|
|
<< ", E: " << field_64 // Number of empty chunk sections.
|
|
<< "\n";
|
|
|
|
return ss.str();
|
|
}
|
|
|
|
void LevelRenderer::onGraphicsReset()
|
|
{
|
|
xglGenBuffers(m_nBuffers, m_pBuffers);
|
|
allChanged();
|
|
}
|
|
|
|
void LevelRenderer::render(const AABB& aabb) const
|
|
{
|
|
Tesselator& t = Tesselator::instance;
|
|
|
|
t.begin(GL_LINE_STRIP);
|
|
t.vertex(aabb.min.x, aabb.min.y, aabb.min.z);
|
|
t.vertex(aabb.max.x, aabb.min.y, aabb.min.z);
|
|
t.vertex(aabb.max.x, aabb.min.y, aabb.max.z);
|
|
t.vertex(aabb.min.x, aabb.min.y, aabb.max.z);
|
|
t.vertex(aabb.min.x, aabb.min.y, aabb.min.z);
|
|
t.draw();
|
|
t.begin(GL_LINE_STRIP);
|
|
t.vertex(aabb.min.x, aabb.max.y, aabb.min.z);
|
|
t.vertex(aabb.max.x, aabb.max.y, aabb.min.z);
|
|
t.vertex(aabb.max.x, aabb.max.y, aabb.max.z);
|
|
t.vertex(aabb.min.x, aabb.max.y, aabb.max.z);
|
|
t.vertex(aabb.min.x, aabb.max.y, aabb.min.z);
|
|
t.draw();
|
|
t.begin(GL_LINES);
|
|
t.vertex(aabb.min.x, aabb.min.y, aabb.min.z);
|
|
t.vertex(aabb.min.x, aabb.max.y, aabb.min.z);
|
|
t.vertex(aabb.max.x, aabb.min.y, aabb.min.z);
|
|
t.vertex(aabb.max.x, aabb.max.y, aabb.min.z);
|
|
t.vertex(aabb.max.x, aabb.min.y, aabb.max.z);
|
|
t.vertex(aabb.max.x, aabb.max.y, aabb.max.z);
|
|
t.vertex(aabb.min.x, aabb.min.y, aabb.max.z);
|
|
t.vertex(aabb.min.x, aabb.max.y, aabb.max.z);
|
|
t.draw();
|
|
}
|
|
|
|
void LevelRenderer::checkQueryResults(int a, int b)
|
|
{
|
|
}
|
|
|
|
void LevelRenderer::renderSameAsLast(int a, float b)
|
|
{
|
|
m_renderList.render();
|
|
}
|
|
|
|
int LevelRenderer::renderChunks(int start, int end, int a, float b)
|
|
{
|
|
field_24.clear();
|
|
|
|
int result = 0;
|
|
for (int i = start; i < end; i++)
|
|
{
|
|
Chunk* pChunk = field_98[i];
|
|
if (!a)
|
|
{
|
|
field_54++;
|
|
if (pChunk->field_1C[0])
|
|
{
|
|
field_64++;
|
|
}
|
|
else if (pChunk->m_bVisible)
|
|
{
|
|
if (!field_B8 || pChunk->field_4D)
|
|
field_60++;
|
|
else
|
|
field_5C++;
|
|
}
|
|
else
|
|
{
|
|
field_58++;
|
|
}
|
|
}
|
|
|
|
if (!pChunk->field_1C[a] && pChunk->m_bVisible && pChunk->field_4D && pChunk->getList(a) >= 0)
|
|
{
|
|
result++;
|
|
field_24.push_back(pChunk);
|
|
}
|
|
}
|
|
|
|
Mob* pMob = m_pMinecraft->m_pMobPersp;
|
|
|
|
float fPosX = pMob->field_98.x + (pMob->m_pos.x - pMob->field_98.x) * b;
|
|
float fPosY = pMob->field_98.y + (pMob->m_pos.y - pMob->field_98.y) * b;
|
|
float fPosZ = pMob->field_98.z + (pMob->m_pos.z - pMob->field_98.z) * b;
|
|
|
|
m_renderList.clear();
|
|
m_renderList.init(fPosX, fPosY, fPosZ);
|
|
|
|
for (int i = 0; i < int(field_24.size()); i++)
|
|
{
|
|
Chunk* pChk = field_24[i];
|
|
m_renderList.addR(*pChk->getRenderChunk(a));
|
|
m_renderList.field_14++;
|
|
}
|
|
|
|
renderSameAsLast(a, b);
|
|
return result;
|
|
}
|
|
|
|
void LevelRenderer::render(Mob* pMob, int a, float b)
|
|
{
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
field_68 = (field_68 + 1) % m_chunksLength;
|
|
Chunk* pChunk = m_chunks[field_68];
|
|
|
|
if (!pChunk->m_bDirty)
|
|
continue;
|
|
|
|
std::vector<Chunk*>::iterator iter = std::find(field_88.begin(), field_88.end(), pChunk);
|
|
if (iter != field_88.end())
|
|
continue;
|
|
|
|
field_88.push_back(pChunk);
|
|
}
|
|
|
|
if (m_pMinecraft->getOptions()->m_iViewDistance != field_BC)
|
|
allChanged();
|
|
|
|
if (!a)
|
|
field_54 = field_58 = field_5C = field_60 = field_64 = 0;
|
|
|
|
//float mobX1 = pMob->m_pos.x;
|
|
float mobX2 = pMob->field_98.x + (pMob->m_pos.x - pMob->field_98.x) * b;
|
|
//float mobY1 = pMob->m_pos.y;
|
|
float mobY2 = pMob->field_98.y + (pMob->m_pos.y - pMob->field_98.y) * b;
|
|
//float mobZ1 = pMob->m_pos.z;
|
|
float mobZ2 = pMob->field_98.z + (pMob->m_pos.z - pMob->field_98.z) * b;
|
|
|
|
float dX = pMob->m_pos.x - field_4, dY = pMob->m_pos.y - field_8, dZ = pMob->m_pos.z - field_C;
|
|
|
|
if (dX * dX + dY * dY + dZ * dZ > 16.0f)
|
|
{
|
|
field_4 = pMob->m_pos.x;
|
|
field_8 = pMob->m_pos.y;
|
|
field_C = pMob->m_pos.z;
|
|
|
|
resortChunks(Mth::floor(pMob->m_pos.x), Mth::floor(pMob->m_pos.y), Mth::floor(pMob->m_pos.z));
|
|
std::sort(&field_98[0], &field_98[m_chunksLength], DistanceChunkSorter(pMob));
|
|
}
|
|
|
|
// @TODO: Fix goto hell
|
|
|
|
// @NOTE: Field_B8 doesn't appear to be used??
|
|
if (field_B8 && !a && !m_pMinecraft->getOptions()->m_bAnaglyphs)
|
|
{
|
|
checkQueryResults(0, 16);
|
|
|
|
// @HUH: why 16?
|
|
for (int i = 0; i < 16; i++)
|
|
{
|
|
field_98[i]->field_4D = true;
|
|
}
|
|
|
|
int x1 = renderChunks(0, 16, 0, b);
|
|
int x2 = 16, x3;
|
|
|
|
while (true)
|
|
{
|
|
x3 = 2 * x2;
|
|
if (x3 >= m_chunksLength)
|
|
x3 = m_chunksLength;
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDisable(GL_ALPHA_TEST);
|
|
glDisable(GL_FOG);
|
|
glColorMask(false, false, false, false);
|
|
glDepthMask(false);
|
|
if (x2 < x3)
|
|
break;
|
|
label_37:
|
|
glDepthMask(true);
|
|
glColorMask(true, true, true, true);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glEnable(GL_ALPHA_TEST);
|
|
glEnable(GL_FOG);
|
|
|
|
int res = renderChunks(x2, x3, 0, b);
|
|
x1 += res;
|
|
if (x3 >= m_chunksLength)
|
|
return;
|
|
x2 = x3;
|
|
}
|
|
|
|
float y1 = 0.0f;
|
|
int y2 = x2;
|
|
int y3 = x2;
|
|
float y4 = 0.0f, y5 = 0.0f;
|
|
|
|
while (true)
|
|
{
|
|
while (!field_98[y2]->isEmpty())
|
|
{
|
|
Chunk* pChunk = field_98[y2];
|
|
|
|
if (!pChunk->m_bVisible)
|
|
{
|
|
pChunk->field_4D = true;
|
|
goto label_26;
|
|
}
|
|
|
|
if (pChunk->field_4E)
|
|
goto label_26;
|
|
|
|
float y6 = pChunk->distanceToSqr(pMob);
|
|
int y7 = int(Mth::sqrt(y6) / 128.0f + 1.0f);
|
|
|
|
if (m_ticksSinceStart % y7 != y3 % y7)
|
|
goto label_26;
|
|
|
|
float fXdiff, fYdiff, fZdiff;
|
|
fXdiff = float(pChunk->m_pos.x) - mobX2 - y5;
|
|
fYdiff = float(pChunk->m_pos.y) - mobY2 - y4;
|
|
fZdiff = float(pChunk->m_pos.z) - mobZ2 - y1;
|
|
|
|
if (fXdiff != 0.0f || fYdiff != 0.0f || fZdiff != 0.0f)
|
|
{
|
|
y5 += fXdiff;
|
|
y4 += fYdiff;
|
|
y1 += fZdiff;
|
|
glTranslatef(fXdiff, fYdiff, fZdiff);
|
|
}
|
|
|
|
pChunk->renderBB();
|
|
|
|
y3++;
|
|
y2++;
|
|
//pChunk->field_4E++;
|
|
pChunk->field_4E = true;
|
|
if (y3 == x3)
|
|
goto label_37;
|
|
}
|
|
|
|
field_98[y2]->m_bVisible = 0;
|
|
label_26:
|
|
y3++;
|
|
y2++;
|
|
|
|
if (y3 == x3)
|
|
goto label_37;
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
renderChunks(0, m_chunksLength, a, b);
|
|
}
|
|
|
|
void LevelRenderer::setLevel(Level* level)
|
|
{
|
|
if (m_pLevel)
|
|
m_pLevel->removeListener(this);
|
|
|
|
field_4 = -9999.0f;
|
|
field_8 = -9999.0f;
|
|
field_C = -9999.0f;
|
|
|
|
EntityRenderDispatcher::getInstance()->setLevel(level);
|
|
EntityRenderDispatcher::getInstance()->setMinecraft(m_pMinecraft);
|
|
|
|
m_pLevel = level;
|
|
|
|
delete m_pTileRenderer;
|
|
m_pTileRenderer = new TileRenderer(m_pLevel);
|
|
|
|
if (level)
|
|
{
|
|
level->addListener(this);
|
|
allChanged();
|
|
}
|
|
}
|
|
|
|
void LevelRenderer::setDirty(int x1, int y1, int z1, int x2, int y2, int z2)
|
|
{
|
|
int x1c = Mth::intFloorDiv(x1, 16);
|
|
int y1c = Mth::intFloorDiv(y1, 16);
|
|
int z1c = Mth::intFloorDiv(z1, 16);
|
|
int x2c = Mth::intFloorDiv(x2, 16);
|
|
int y2c = Mth::intFloorDiv(y2, 16);
|
|
int z2c = Mth::intFloorDiv(z2, 16);
|
|
|
|
for (int x = x1c; x <= x2c; x++)
|
|
{
|
|
int x1 = x % field_A4;
|
|
if (x1 < 0)
|
|
x1 += field_A4;
|
|
|
|
for (int y = y1c; y <= y2c; y++)
|
|
{
|
|
int y1 = y % field_A8;
|
|
if (y1 < 0)
|
|
y1 += field_A8;
|
|
|
|
for (int z = z1c; z <= z2c; z++)
|
|
{
|
|
int z1 = z % field_AC;
|
|
if (z1 < 0)
|
|
z1 += field_AC;
|
|
|
|
Chunk* pChunk = m_chunks[x1 + field_A4 * (y1 + field_A8 * z1)];
|
|
if (pChunk->isDirty())
|
|
continue;
|
|
|
|
field_88.push_back(pChunk);
|
|
pChunk->setDirty();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void LevelRenderer::setTilesDirty(int x1, int y1, int z1, int x2, int y2, int z2)
|
|
{
|
|
setDirty(x1 - 1, y1 - 1, z1 - 1, x2 + 1, y2 + 1, z2 + 1);
|
|
}
|
|
|
|
void LevelRenderer::tick()
|
|
{
|
|
m_ticksSinceStart++;
|
|
}
|
|
|
|
/*
|
|
void LevelRenderer::updateDirtyChunks(Mob* pMob, bool b)
|
|
{
|
|
// @TODO This updates 16 chunks per frame. Not good.
|
|
|
|
int updated = 0;
|
|
for (int i = 0; i < 16 && i < int(field_88.size()); i++)
|
|
{
|
|
Chunk* pChk = field_88[i];
|
|
pChk->rebuild();
|
|
pChk->setClean();
|
|
updated++;
|
|
}
|
|
|
|
field_88.erase(field_88.begin(), field_88.begin() + updated);
|
|
}
|
|
*/
|
|
|
|
typedef std::vector<Chunk*> ChunkVector;
|
|
typedef ChunkVector::iterator ChunkVectorIterator;
|
|
|
|
bool LevelRenderer::updateDirtyChunks(Mob* pMob, bool b)
|
|
{
|
|
// @TODO: untangle this thing
|
|
|
|
int v3; // r4
|
|
ChunkVectorIterator field_88_Beg; // r3
|
|
size_t size; // r9
|
|
int v8; // r11
|
|
Chunk* v9; // r0
|
|
ChunkVector* xvec; // r5
|
|
int v11; // r7
|
|
ChunkVectorIterator v12; // r1
|
|
int v13; // r7
|
|
Chunk* v14; // r1
|
|
bool v15; // r0
|
|
int v16; // r3
|
|
int v17; // r7
|
|
int v18; // r2
|
|
ChunkVectorIterator v19; // r1
|
|
ChunkVectorIterator v20; // r0
|
|
size_t v21; // r8
|
|
size_t v22; // r4
|
|
ChunkVector* v23; // r10
|
|
size_t v24; // r8
|
|
Chunk* v25; // r5
|
|
int v26; // r4
|
|
int v27; // r8
|
|
Chunk* v28; // r5
|
|
bool v29; // r3
|
|
ChunkVectorIterator v31; // r1
|
|
size_t v32; // r5
|
|
int v33; // r0
|
|
int v34; // r3
|
|
Chunk* v35; // r2
|
|
Chunk** v38; // r3
|
|
Chunk* v39; // r2
|
|
ChunkVector* v40; // r0
|
|
Chunk* v42[3]; // [sp+1Ch] [bp+0h] BYREF
|
|
Chunk* a3; // [sp+28h] [bp+Ch] BYREF
|
|
Entity* pMob_1; // [sp+2Ch] [bp+10h] BYREF
|
|
|
|
v3 = 0;
|
|
pMob_1 = pMob;
|
|
DirtyChunkSorter dcs(pMob);
|
|
memset(v42, 0, sizeof v42);
|
|
field_88_Beg = this->field_88.begin();
|
|
size = this->field_88.end() - field_88_Beg;
|
|
if (size <= 0)
|
|
{
|
|
v8 = 0;
|
|
goto LABEL_28;
|
|
}
|
|
v8 = 0;
|
|
v9 = *field_88_Beg;
|
|
xvec = 0;
|
|
v11 = 0;
|
|
a3 = *field_88_Beg;
|
|
if (!b)
|
|
goto LABEL_11;
|
|
while (1)
|
|
{
|
|
if (!v9->m_bVisible)
|
|
goto LABEL_9;
|
|
LABEL_5:
|
|
if (!xvec)
|
|
{
|
|
++v8;
|
|
v40 = new ChunkVector;
|
|
v12 = v40->end();
|
|
xvec = v40;
|
|
LABEL_55:
|
|
xvec->insert(v12, a3);
|
|
goto LABEL_8;
|
|
}
|
|
v12 = xvec->end();
|
|
++v8;
|
|
if (true) // (v12 == xvec->capacity)
|
|
goto LABEL_55;
|
|
xvec->insert(v12, a3);
|
|
LABEL_8:
|
|
field_88[v11] = 0;
|
|
LABEL_9:
|
|
|
|
if (++v3 == size)
|
|
break;
|
|
while (1)
|
|
{
|
|
v11 = v3;
|
|
v9 = field_88[v3];
|
|
a3 = v9;
|
|
if (b)
|
|
break;
|
|
LABEL_11:
|
|
if (v9->distanceToSqr(pMob) <= 1024.0f)
|
|
goto LABEL_5;
|
|
v13 = b;
|
|
while (1)
|
|
{
|
|
v14 = v42[v13];
|
|
if (v14)
|
|
{
|
|
v15 = dcs(v14, a3);
|
|
v16 = v13;
|
|
if (!v15)
|
|
break;
|
|
}
|
|
if (++v13 == 3)
|
|
{
|
|
v17 = 2;
|
|
v18 = 1;
|
|
v16 = 3;
|
|
goto LABEL_51;
|
|
}
|
|
}
|
|
v17 = v13 - 1;
|
|
if (v17 <= 0)
|
|
goto LABEL_9;
|
|
v18 = v17 - 1;
|
|
if (v17 == 1)
|
|
{
|
|
v42[1] = a3;
|
|
goto LABEL_18;
|
|
}
|
|
LABEL_51:
|
|
v38 = &v42[v16];
|
|
v39 = v42[v18];
|
|
do
|
|
{
|
|
*(v38 - 3) = v39;
|
|
--v38;
|
|
} while (v38 != &v42[2]);
|
|
v42[v17] = a3;
|
|
LABEL_18:
|
|
if (++v3 == size)
|
|
goto LABEL_19;
|
|
}
|
|
}
|
|
LABEL_19:
|
|
if (xvec)
|
|
{
|
|
v19 = xvec->end();
|
|
v20 = xvec->begin();
|
|
v21 = v19 - xvec->begin();
|
|
if (v21 > 1)
|
|
{
|
|
std::sort(v20, v19, dcs);
|
|
v20 = xvec->begin();
|
|
v21 = xvec->end() - xvec->begin();
|
|
}
|
|
v22 = v21 - 1;
|
|
if ((int)(v21 - 1) >= 0)
|
|
{
|
|
v23 = xvec;
|
|
v24 = v21 - 1;// v21 + 0x3FFFFFFF;
|
|
while (1)
|
|
{
|
|
v25 = v20[v24--];
|
|
v25->rebuild();
|
|
v25->setClean();
|
|
if ((--v22 & 0x80000000) != 0)
|
|
break;
|
|
v20 = v23->begin();
|
|
}
|
|
xvec = v23;
|
|
}
|
|
|
|
delete xvec;
|
|
}
|
|
LABEL_28:
|
|
v26 = 2;
|
|
v27 = 0;
|
|
while (2)
|
|
{
|
|
v28 = v42[v26];
|
|
if (!v28)
|
|
{
|
|
LABEL_33:
|
|
if (v26-- == 0)
|
|
goto LABEL_34;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
v29 = v28->m_bVisible;
|
|
if (v28->m_bVisible || v26 == 2)
|
|
{
|
|
++v27;
|
|
v42[v26]->rebuild();
|
|
v28->setClean();
|
|
goto LABEL_33;
|
|
}
|
|
v42[v26] = (Chunk*)v29;
|
|
v42[0] = (Chunk*)v29;
|
|
LABEL_34:
|
|
v31 = this->field_88.begin();
|
|
v32 = this->field_88.end() - v31;
|
|
if (v32)
|
|
{
|
|
v33 = 0;
|
|
v34 = 0;
|
|
while (1)
|
|
{
|
|
v35 = v31[v34];
|
|
if (v35 && v42[0] != v35 && v42[1] != v35 && v42[2] != v35)
|
|
{
|
|
if (v33 != v34)
|
|
v31[v33] = v35;
|
|
++v33;
|
|
}
|
|
if (++v34 == v32)
|
|
break;
|
|
v31 = this->field_88.begin();
|
|
}
|
|
if (v34 > v33)
|
|
{
|
|
field_88.resize(v33);
|
|
}
|
|
}
|
|
return v27 + v8 == size;
|
|
}
|
|
|
|
void LevelRenderer::renderHit(Player* pPlayer, const HitResult& hr, int i, void* vp, float f)
|
|
{
|
|
glEnable(GL_BLEND);
|
|
glEnable(GL_ALPHA_TEST);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
|
|
|
// @BUG: possible leftover from Minecraft Classic? This is overridden anyways
|
|
glColor4f(1.0f, 1.0f, 1.0f, 0.5f * (0.4f + 0.2f * Mth::sin(float(getTimeMs()) / 100.0f)));
|
|
|
|
if (!i && field_10 > 0.0f)
|
|
{
|
|
glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
|
|
|
|
m_pTextures->loadAndBindTexture(C_TERRAIN_NAME);
|
|
glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
|
|
glPushMatrix();
|
|
Tile* pTile = nullptr;
|
|
TileID tile = m_pLevel->getTile(hr.m_tileX, hr.m_tileY, hr.m_tileZ);
|
|
if (tile > 0)
|
|
pTile = Tile::tiles[tile];
|
|
glDisable(GL_ALPHA_TEST);
|
|
glPolygonOffset(-3.0f, -3.0f);
|
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
|
|
|
float px = pPlayer->field_98.x + (pPlayer->m_pos.x - pPlayer->field_98.x) * f;
|
|
float py = pPlayer->field_98.y + (pPlayer->m_pos.y - pPlayer->field_98.y) * f;
|
|
float pz = pPlayer->field_98.z + (pPlayer->m_pos.z - pPlayer->field_98.z) * f;
|
|
|
|
Tesselator& t = Tesselator::instance;
|
|
t.begin();
|
|
t.offset(-px, -py, -pz);
|
|
t.noColor();
|
|
if (!pTile)
|
|
pTile = Tile::rock;
|
|
|
|
m_pTileRenderer->tesselateInWorld(pTile, hr.m_tileX, hr.m_tileY, hr.m_tileZ, 240 + int(field_10 * 10.0f));
|
|
|
|
t.draw();
|
|
t.offset(0, 0, 0);
|
|
|
|
glPolygonOffset(0.0f, 0.0f);
|
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
|
|
|
glDepthMask(true); //@HUH: What is the reason for this? You never disable the depth mask.
|
|
glPopMatrix();
|
|
}
|
|
|
|
glDisable(GL_BLEND);
|
|
glDisable(GL_ALPHA_TEST);
|
|
}
|
|
|
|
void LevelRenderer::renderHitSelect(Player* pPlayer, const HitResult& hr, int i, void* vp, float f)
|
|
{
|
|
if (i) return;
|
|
|
|
glEnable(GL_BLEND);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
|
glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
m_pMinecraft->m_pTextures->loadAndBindTexture(C_TERRAIN_NAME);
|
|
|
|
Tile* pTile = nullptr;
|
|
TileID tileID = m_pLevel->getTile(hr.m_tileX, hr.m_tileY, hr.m_tileZ);
|
|
if (tileID > 0)
|
|
pTile = Tile::tiles[tileID];
|
|
|
|
glDisable(GL_ALPHA_TEST);
|
|
glColor4f(0.65f, 0.65f, 0.65f, 0.65f);
|
|
glPushMatrix();
|
|
glPolygonOffset(-0.3f, -0.3f);
|
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
|
|
|
float px = pPlayer->field_98.x + (pPlayer->m_pos.x - pPlayer->field_98.x) * f;
|
|
float py = pPlayer->field_98.y + (pPlayer->m_pos.y - pPlayer->field_98.y) * f;
|
|
float pz = pPlayer->field_98.z + (pPlayer->m_pos.z - pPlayer->field_98.z) * f;
|
|
|
|
Tesselator& t = Tesselator::instance;
|
|
t.begin();
|
|
t.offset(-px, -py, -pz);
|
|
t.noColor();
|
|
if (!pTile)
|
|
pTile = Tile::rock;
|
|
|
|
m_pTileRenderer->tesselateInWorld(pTile, hr.m_tileX, hr.m_tileY, hr.m_tileZ);
|
|
|
|
t.draw();
|
|
t.offset(0, 0, 0);
|
|
|
|
glPolygonOffset(0.0f, 0.0f);
|
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glDepthMask(true);
|
|
glPopMatrix();
|
|
glEnable(GL_ALPHA_TEST);
|
|
glDisable(GL_BLEND);
|
|
}
|
|
|
|
void LevelRenderer::renderHitOutline(Player* pPlayer, const HitResult& hr, int i, void* vp, float f)
|
|
{
|
|
if (i != 0 || hr.m_hitType != 0)
|
|
return;
|
|
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glColor4f(1.0f, 1.0f, 1.0f, 0.4f);
|
|
glLineWidth(10.0f);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDepthMask(false);
|
|
|
|
TileID tile = m_pLevel->getTile(hr.m_tileX, hr.m_tileY, hr.m_tileZ);
|
|
if (tile > 0)
|
|
{
|
|
Tile::tiles[tile]->updateShape(
|
|
m_pLevel,
|
|
hr.m_tileX,
|
|
hr.m_tileY,
|
|
hr.m_tileZ);
|
|
float posX = pPlayer->field_98.x + ((pPlayer->m_pos.x - pPlayer->field_98.x) * f);
|
|
float posY = pPlayer->field_98.y + ((pPlayer->m_pos.y - pPlayer->field_98.y) * f);
|
|
float posZ = pPlayer->field_98.z + ((pPlayer->m_pos.z - pPlayer->field_98.z) * f);
|
|
AABB aabb, tileAABB = Tile::tiles[tile]->getTileAABB(m_pLevel, hr.m_tileX, hr.m_tileY, hr.m_tileZ);
|
|
aabb.min.y = tileAABB.min.y - 0.002f - posY;
|
|
aabb.max.y = tileAABB.max.y + 0.002f - posY;
|
|
aabb.min.z = tileAABB.min.z - 0.002f - posZ;
|
|
aabb.max.z = tileAABB.max.z + 0.002f - posZ;
|
|
aabb.min.x = tileAABB.min.x - 0.002f - posX;
|
|
aabb.max.x = tileAABB.max.x + 0.002f - posX;
|
|
render(aabb);
|
|
}
|
|
|
|
glDepthMask(true);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glDisable(GL_BLEND);
|
|
}
|
|
|
|
void LevelRenderer::tileChanged(int x, int y, int z)
|
|
{
|
|
setDirty(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1);
|
|
}
|
|
|
|
void LevelRenderer::renderEntities(Vec3 pos, Culler* culler, float f)
|
|
{
|
|
if (field_14 > 0)
|
|
{
|
|
field_14--;
|
|
return;
|
|
}
|
|
|
|
Mob* mob = m_pMinecraft->m_pMobPersp;
|
|
|
|
EntityRenderDispatcher::getInstance()->prepare(m_pLevel, m_pMinecraft->m_pTextures, m_pMinecraft->m_pFont, mob, m_pMinecraft->getOptions(), f);
|
|
|
|
field_18 = 0;
|
|
field_1C = 0;
|
|
field_20 = 0;
|
|
|
|
EntityRenderDispatcher::xOff = mob->field_98.x + (mob->m_pos.x - mob->field_98.x) * f;
|
|
EntityRenderDispatcher::yOff = mob->field_98.y + (mob->m_pos.y - mob->field_98.y) * f;
|
|
EntityRenderDispatcher::zOff = mob->field_98.z + (mob->m_pos.z - mob->field_98.z) * f;
|
|
|
|
EntityVector* pVec = m_pLevel->getAllEntities();
|
|
field_18 = int(pVec->size());
|
|
|
|
for (int i = 0; i < field_18; i++)
|
|
{
|
|
Entity* pEnt = (*pVec)[i];
|
|
if (!pEnt->shouldRender(pos))
|
|
continue;
|
|
|
|
if (!culler->isVisible(pEnt->m_hitbox))
|
|
continue;
|
|
|
|
if (m_pMinecraft->m_pMobPersp == pEnt && !m_pMinecraft->getOptions()->m_bThirdPerson)
|
|
continue;
|
|
|
|
if (m_pLevel->hasChunkAt(Mth::floor(pEnt->m_pos.x), Mth::floor(pEnt->m_pos.y), Mth::floor(pEnt->m_pos.z)))
|
|
{
|
|
field_1C++;
|
|
EntityRenderDispatcher::getInstance()->render(pEnt, f);
|
|
}
|
|
}
|
|
}
|
|
|
|
extern int t_keepPic;
|
|
|
|
void LevelRenderer::takePicture(TripodCamera* pCamera, Entity* pOwner)
|
|
{
|
|
Mob* pOldMob = m_pMinecraft->m_pMobPersp;
|
|
bool bOldDontRenderGui = m_pMinecraft->getOptions()->m_bDontRenderGui;
|
|
bool bOldThirdPerson = m_pMinecraft->getOptions()->m_bThirdPerson;
|
|
|
|
#ifdef ENH_CAMERA_NO_PARTICLES
|
|
extern bool g_bDisableParticles;
|
|
g_bDisableParticles = true;
|
|
#endif
|
|
|
|
m_pMinecraft->m_pMobPersp = pCamera;
|
|
m_pMinecraft->getOptions()->m_bDontRenderGui = true;
|
|
m_pMinecraft->getOptions()->m_bThirdPerson = false; // really from the perspective of the camera
|
|
m_pMinecraft->m_pGameRenderer->render(0.0f);
|
|
m_pMinecraft->m_pMobPersp = pOldMob;
|
|
m_pMinecraft->getOptions()->m_bDontRenderGui = bOldDontRenderGui;
|
|
m_pMinecraft->getOptions()->m_bThirdPerson = bOldThirdPerson;
|
|
|
|
#ifdef ENH_CAMERA_NO_PARTICLES
|
|
g_bDisableParticles = false;
|
|
#endif
|
|
|
|
t_keepPic = -1;
|
|
|
|
static char str[256];
|
|
// @HUH: This has the potential to overwrite a file
|
|
#ifdef ORIGINAL_CODE
|
|
sprintf(str, "%s/games/com.mojang/img_%.4d.jpg", m_pMinecraft->m_externalStorageDir.c_str(), getTimeMs());
|
|
#else
|
|
sprintf(str, "img_%.4d.png", getTimeMs());
|
|
#endif
|
|
|
|
m_pMinecraft->platform()->saveScreenshot(std::string(str), Minecraft::width, Minecraft::height);
|
|
}
|
|
|
|
void LevelRenderer::addParticle(const std::string& name, float x, float y, float z, float vx, float vy, float vz)
|
|
{
|
|
// TODO: Who's the genius who decided it'd be better to check a name string rather than an enum?
|
|
if (m_pMinecraft->m_pMobPersp->distanceToSqr_inline(x, y, z) > 256.0f)
|
|
return;
|
|
|
|
ParticleEngine* pe = m_pMinecraft->m_pParticleEngine;
|
|
if (name == "bubble")
|
|
{
|
|
pe->add(new BubbleParticle(m_pLevel, x, y, z, vx, vy, vz));
|
|
return;
|
|
}
|
|
if (name == "smoke")
|
|
{
|
|
pe->add(new SmokeParticle(m_pLevel, x, y, z, vx, vy, vz, 1.0f));
|
|
return;
|
|
}
|
|
if (name == "explode")
|
|
{
|
|
pe->add(new ExplodeParticle(m_pLevel, x, y, z, vx, vy, vz));
|
|
return;
|
|
}
|
|
if (name == "flame")
|
|
{
|
|
pe->add(new FlameParticle(m_pLevel, x, y, z, vx, vy, vz));
|
|
return;
|
|
}
|
|
if (name == "lava")
|
|
{
|
|
pe->add(new LavaParticle(m_pLevel, x, y, z));
|
|
return;
|
|
}
|
|
if (name == "largesmoke")
|
|
{
|
|
pe->add(new SmokeParticle(m_pLevel, x, y, z, vx, vy, vz, 2.5f));
|
|
return;
|
|
}
|
|
if (name == "reddust")
|
|
{
|
|
pe->add(new RedDustParticle(m_pLevel, x, y, z, vx, vy, vz));
|
|
return;
|
|
}
|
|
|
|
LOG_W("Unknown particle type: %s", name.c_str());
|
|
}
|
|
|
|
void LevelRenderer::playSound(const std::string& name, float x, float y, float z, float a, float b)
|
|
{
|
|
// TODO: Who's the genius who decided it'd be better to check a name string rather than an enum?
|
|
float mult = 1.0f, dist = 16.0f;
|
|
|
|
if (a > 1.0f)
|
|
{
|
|
mult = 16.0f;
|
|
dist = a * mult;
|
|
}
|
|
|
|
if (dist * dist > m_pMinecraft->m_pMobPersp->distanceToSqr(x, y, z))
|
|
m_pMinecraft->m_pSoundEngine->play(name, x, y, z, a, b);
|
|
}
|
|
|
|
void LevelRenderer::renderSky(float f)
|
|
{
|
|
if (m_pMinecraft->m_pLevel->m_pDimension->field_C)
|
|
return;
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
Vec3 skyColor = m_pLevel->getSkyColor(m_pMinecraft->m_pMobPersp, f);
|
|
if (m_pMinecraft->getOptions()->m_bAnaglyphs)
|
|
{
|
|
skyColor.x = (((skyColor.x * 30.0f) + (skyColor.y * 59.0f)) + (skyColor.z * 11.0f)) / 100.0f;
|
|
skyColor.y = ((skyColor.x * 30.0f) + (skyColor.y * 70.0f)) / 100.0f;
|
|
skyColor.z = ((skyColor.x * 30.0f) + (skyColor.z * 70.0f)) / 100.0f;
|
|
}
|
|
|
|
glColor4f(skyColor.x, skyColor.y, Mth::Min(1.0f, skyColor.z), 1.0f);
|
|
glDepthMask(false);
|
|
glColor4f(skyColor.x, skyColor.y, skyColor.z, 1.0f);
|
|
drawArrayVT(field_D8, field_DC, sizeof(Tesselator::Vertex));
|
|
glEnable(GL_TEXTURE_2D);
|
|
glDepthMask(true);
|
|
}
|
|
|
|
// TODO: This should be inside of an initialized "Minecraft" instance rather than the global namespace
|
|
bool g_bAreCloudsAvailable = false; // false because 0.1 didn't have them
|
|
|
|
void LevelRenderer::renderClouds(float f)
|
|
{
|
|
if (!g_bAreCloudsAvailable)
|
|
return;
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
float yPos = Lerp(m_pMinecraft->m_pMobPersp->field_98.y, m_pMinecraft->m_pMobPersp->m_pos.y, f); // not certain if this old pos Y is used
|
|
m_pTextures->loadAndBindTexture("environment/clouds.png");
|
|
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
Vec3 cloudColor = m_pLevel->getCloudColor(f);
|
|
|
|
float offX = Lerp(m_pMinecraft->m_pMobPersp->field_3C.x, m_pMinecraft->m_pMobPersp->m_pos.x, f) + (float(m_ticksSinceStart) + f) * 0.3f;
|
|
float offZ = Lerp(m_pMinecraft->m_pMobPersp->field_3C.z, m_pMinecraft->m_pMobPersp->m_pos.z, f);
|
|
|
|
int dx2048 = Mth::floor(offX / 2048.0f);
|
|
int dz2048 = Mth::floor(offZ / 2048.0f);
|
|
|
|
offX -= float(dx2048 * 2048);
|
|
offZ -= float(dz2048 * 2048);
|
|
|
|
Tesselator& t = Tesselator::instance;
|
|
|
|
float fYPos = (128.0f - yPos) + 0.33f;
|
|
offX /= 2048.0f;
|
|
offZ /= 2048.0f;
|
|
t.begin();
|
|
t.color(cloudColor.x, cloudColor.y, cloudColor.z, 0.8f);
|
|
|
|
const int incr = 32;
|
|
const int in2 = 256 / incr;
|
|
for (int x = -incr * in2; x < incr * in2; x += incr)
|
|
{
|
|
for (int z = -incr * in2; z < incr * in2; z += incr)
|
|
{
|
|
t.vertexUV(float(x) + 0.0f, fYPos, float(z) + incr, float(x + 0.0f) / 2048.0f + offX, float(z + incr) / 2048.0f + offZ);
|
|
t.vertexUV(float(x) + incr, fYPos, float(z) + incr, float(x + incr) / 2048.0f + offX, float(z + incr) / 2048.0f + offZ);
|
|
t.vertexUV(float(x) + incr, fYPos, float(z) + 0.0f, float(x + incr) / 2048.0f + offX, float(z + 0.0f) / 2048.0f + offZ);
|
|
t.vertexUV(float(x) + 0.0f, fYPos, float(z) + 0.0f, float(x + 0.0f) / 2048.0f + offX, float(z + 0.0f) / 2048.0f + offZ);
|
|
}
|
|
|
|
}
|
|
|
|
t.voidBeginAndEndCalls(false); // why??
|
|
t.draw();
|
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
|
glDisable(GL_BLEND);
|
|
glEnable(GL_CULL_FACE);
|
|
}
|
|
|
|
void LevelRenderer::skyColorChanged()
|
|
{
|
|
for (int i = 0; i < m_chunksLength; i++)
|
|
{
|
|
Chunk* pChunk = m_chunks[i];
|
|
if (!pChunk->field_54)
|
|
continue;
|
|
|
|
if (pChunk->isDirty())
|
|
continue;
|
|
|
|
field_88.push_back(pChunk);
|
|
pChunk->setDirty();
|
|
}
|
|
}
|