Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6215e1365f | |||
| d30e18ef4d |
@@ -66,8 +66,8 @@ jobs:
|
||||
|
||||
- name: Package artifact
|
||||
run: |
|
||||
cd build/targets/app
|
||||
zip -r ../../../minecraft-client-linux.zip . --exclude "./Minecraft.Client.p/*"
|
||||
cd build/targets
|
||||
zip -r ../minecraft-client-linux.zip app --exclude "app/Minecraft.Client.p/*"
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
|
||||
Generated
+9
-9
@@ -3,11 +3,11 @@
|
||||
"4jlibs": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1774845485,
|
||||
"narHash": "sha256-6lZrYkW0hX5jQDUy0lb2Qtsst3+lMfJviYUVfuNlEzk=",
|
||||
"lastModified": 1774836469,
|
||||
"narHash": "sha256-ukp6tLThQugPlREYFDDB6IaunjGte08f0Ler/c8cvaY=",
|
||||
"owner": "4jcraft",
|
||||
"repo": "4jlibs",
|
||||
"rev": "db73929667eb0607821e38b57d01e6954a7df36d",
|
||||
"rev": "ab37891dabba90cf1e568660f750cebf46ba83f6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -62,11 +62,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1775036866,
|
||||
"narHash": "sha256-ZojAnPuCdy657PbTq5V0Y+AHKhZAIwSIT2cb8UgAz/U=",
|
||||
"lastModified": 1774386573,
|
||||
"narHash": "sha256-4hAV26quOxdC6iyG7kYaZcM3VOskcPUrdCQd/nx8obc=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "6201e203d09599479a3b3450ed24fa81537ebc4e",
|
||||
"rev": "46db2e09e1d3f113a13c0d7b81e2f221c63b8ce9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -108,11 +108,11 @@
|
||||
"simdutf": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1775095916,
|
||||
"narHash": "sha256-eKMjANt0fbqemtll6iSiFHwYzGWAsuZoVqOXqXNfodc=",
|
||||
"lastModified": 1773677002,
|
||||
"narHash": "sha256-kq53Jz9zm2bfs8x/74FQbzYrUc+VD7JlnBoYHnEHuSY=",
|
||||
"owner": "simdutf",
|
||||
"repo": "simdutf",
|
||||
"rev": "1ac2c2245ce9df6a7d26550e34734882c4a16e9b",
|
||||
"rev": "04a9b596de943ea9e4d4c833e39740edf3c11e88",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/share/4jcraft
|
||||
cp -r targets/app/. $out/share/4jcraft/
|
||||
cp -r Minecraft.Client/. $out/share/4jcraft/
|
||||
|
||||
mkdir -p $out/bin
|
||||
makeWrapper $out/share/4jcraft/Minecraft.Client $out/bin/4jcraft \
|
||||
|
||||
+32
-36
@@ -1,16 +1,16 @@
|
||||
project(
|
||||
'4jcraft',
|
||||
['cpp', 'c'],
|
||||
version: '0.1.0',
|
||||
meson_version: '>= 1.3',
|
||||
default_options: [
|
||||
'cpp_std=c++23',
|
||||
'warning_level=0',
|
||||
'buildtype=debugoptimized', # for now
|
||||
'unity=on', # merge source files per target
|
||||
'unity_size=8', # TODO: mess around with this
|
||||
'b_pch=true', # precompiled headers
|
||||
],
|
||||
'4jcraft',
|
||||
['cpp', 'c'],
|
||||
version: '0.1.0',
|
||||
meson_version: '>= 1.3',
|
||||
default_options: [
|
||||
'cpp_std=c++23',
|
||||
'warning_level=0',
|
||||
'buildtype=debugoptimized', # for now
|
||||
'unity=on', # merge source files per target
|
||||
'unity_size=8', # TODO: mess around with this
|
||||
'b_pch=true', # precompiled headers
|
||||
],
|
||||
)
|
||||
|
||||
pymod = import('python')
|
||||
@@ -19,30 +19,30 @@ python = pymod.find_installation('python3', required: true)
|
||||
cc = meson.get_compiler('cpp')
|
||||
|
||||
global_cpp_defs = [
|
||||
'-DSPLIT_SAVES',
|
||||
'-D_LARGE_WORLDS',
|
||||
'-D_EXTENDED_ACHIEVEMENTS',
|
||||
'-D_DEBUG_MENUS_ENABLED',
|
||||
'-D_DEBUG',
|
||||
'-D_FORTIFY_SOURCE=2',
|
||||
'-DDEBUG',
|
||||
'-DSPLIT_SAVES',
|
||||
'-D_LARGE_WORLDS',
|
||||
'-D_EXTENDED_ACHIEVEMENTS',
|
||||
'-D_DEBUG_MENUS_ENABLED',
|
||||
'-D_DEBUG',
|
||||
'-D_FORTIFY_SOURCE=2',
|
||||
'-DDEBUG',
|
||||
]
|
||||
|
||||
if host_machine.system() == 'linux'
|
||||
global_cpp_defs += ['-Dlinux', '-D__linux', '-D__linux__']
|
||||
global_cpp_defs += ['-Dlinux', '-D__linux', '-D__linux__']
|
||||
endif
|
||||
|
||||
if get_option('renderer') == 'gles'
|
||||
global_cpp_defs += ['-DGLES']
|
||||
gl_dep = dependency('glesv2', required: true)
|
||||
glu_dep = dependency('', required: false)
|
||||
global_cpp_defs += ['-DGLES']
|
||||
gl_dep = dependency('glesv2', required: true)
|
||||
glu_dep = dependency('', required: false)
|
||||
else
|
||||
gl_dep = dependency('gl', required: true)
|
||||
glu_dep = dependency('glu', required: true)
|
||||
gl_dep = dependency('gl', required: true)
|
||||
glu_dep = dependency('glu', required: true)
|
||||
endif
|
||||
|
||||
if get_option('enable_vsync')
|
||||
global_cpp_defs += ['-DENABLE_VSYNC']
|
||||
global_cpp_defs += ['-DENABLE_VSYNC']
|
||||
endif
|
||||
|
||||
if get_option('classic_panorama')
|
||||
@@ -50,26 +50,22 @@ if get_option('classic_panorama')
|
||||
endif
|
||||
|
||||
if get_option('enable_frame_profiler')
|
||||
global_cpp_defs += ['-DENABLE_FRAME_PROFILER']
|
||||
endif
|
||||
|
||||
if get_option('enable_greedy_meshing')
|
||||
global_cpp_defs += ['-DENABLE_GREEDY_MESHING']
|
||||
global_cpp_defs += ['-DENABLE_FRAME_PROFILER']
|
||||
endif
|
||||
|
||||
if get_option('ui_backend') == 'shiggy'
|
||||
global_cpp_defs += ['-D_ENABLEIGGY']
|
||||
global_cpp_defs += ['-D_ENABLEIGGY']
|
||||
endif
|
||||
|
||||
if get_option('ui_backend') == 'java'
|
||||
global_cpp_defs += '-DENABLE_JAVA_GUIS'
|
||||
global_cpp_defs += '-DENABLE_JAVA_GUIS'
|
||||
endif
|
||||
|
||||
add_project_arguments(global_cpp_defs, language: ['cpp', 'c'])
|
||||
|
||||
global_cpp_args = [
|
||||
'-Wshift-count-overflow',
|
||||
'-pipe',
|
||||
'-Wshift-count-overflow',
|
||||
'-pipe',
|
||||
]
|
||||
add_project_arguments(global_cpp_args, language: 'cpp')
|
||||
|
||||
@@ -90,4 +86,4 @@ subdir('targets/platform')
|
||||
|
||||
subdir('targets/resources')
|
||||
subdir('targets/minecraft')
|
||||
subdir('targets/app')
|
||||
subdir('targets/app')
|
||||
|
||||
+2
-9
@@ -7,8 +7,8 @@ option(
|
||||
)
|
||||
|
||||
option('classic_panorama',
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
type : 'boolean',
|
||||
value : false,
|
||||
description : 'Enable classic java edition panorama (ui_backend=java ONLY).')
|
||||
|
||||
option(
|
||||
@@ -40,10 +40,3 @@ option(
|
||||
value: 'frustum',
|
||||
description: 'Occlusion culling mode. Off disables ALL CULLING (debug only!), Frustum disables offscreen rendering (default), BFS is experimental connectivity culling, hardware uses GPU queries.',
|
||||
)
|
||||
|
||||
option(
|
||||
'enable_greedy_meshing',
|
||||
type: 'boolean',
|
||||
value: true,
|
||||
description: 'Enable greedy meshing for chunks and liquid tops.',
|
||||
)
|
||||
|
||||
@@ -547,13 +547,43 @@ void UIScene_LoadOrJoinMenu::tick() {
|
||||
m_iState = e_SavesIdle;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
if (!m_bSavesDisplayed) {
|
||||
AddDefaultButtons();
|
||||
m_bSavesDisplayed = true;
|
||||
m_controlSavesTimer.setVisible(false);
|
||||
}
|
||||
#endif
|
||||
// 4jcraft: the game literally defaulted to nothing but default buttons
|
||||
// if the game was on a non console / recognized platform.
|
||||
#else
|
||||
if (!m_bSavesDisplayed) {
|
||||
m_pSaveDetails = StorageManager.ReturnSavesInfo();
|
||||
if (m_pSaveDetails != nullptr) {
|
||||
AddDefaultButtons();
|
||||
|
||||
if (m_saveDetails != nullptr) {
|
||||
for (unsigned int i = 0; i < m_iSaveDetailsCount; ++i) {
|
||||
if (m_saveDetails[i].pbThumbnailData != nullptr)
|
||||
delete m_saveDetails[i].pbThumbnailData;
|
||||
}
|
||||
delete[] m_saveDetails;
|
||||
}
|
||||
|
||||
m_saveDetails = new SaveListDetails[m_pSaveDetails->iSaveC];
|
||||
m_iSaveDetailsCount = m_pSaveDetails->iSaveC;
|
||||
|
||||
for (unsigned int i = 0; i < m_pSaveDetails->iSaveC; ++i) {
|
||||
m_buttonListSaves.addItem(
|
||||
m_pSaveDetails->SaveInfoA[i].UTF8SaveTitle, L"");
|
||||
|
||||
m_saveDetails[i].saveId = i;
|
||||
memcpy(m_saveDetails[i].UTF8SaveName,
|
||||
m_pSaveDetails->SaveInfoA[i].UTF8SaveTitle, 128);
|
||||
memcpy(m_saveDetails[i].UTF8SaveFilename,
|
||||
m_pSaveDetails->SaveInfoA[i].UTF8SaveFilename,
|
||||
MAX_SAVEFILENAME_LENGTH);
|
||||
}
|
||||
|
||||
m_bSavesDisplayed = true;
|
||||
m_controlSavesTimer.setVisible(false);
|
||||
UpdateGamesList();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// SAVE TRANSFERS
|
||||
}
|
||||
|
||||
@@ -8,9 +8,14 @@
|
||||
#include <system_error>
|
||||
#include <vector>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "util/StringHelpers.h" // 4jcraft TODO
|
||||
#include "platform/PlatformServices.h"
|
||||
#include "java/FileFilter.h"
|
||||
#include "platform/StdFileIO.h"
|
||||
|
||||
const wchar_t File::pathSeparator = L'/';
|
||||
|
||||
@@ -64,11 +69,11 @@ File::File(const std::wstring& pathname) {
|
||||
m_abstractPathName = fixedPath;
|
||||
|
||||
#if defined(__linux__)
|
||||
std::string request = std::filesystem::path(m_abstractPathName).string();
|
||||
std::string request = wstringtofilename(m_abstractPathName);
|
||||
while (!request.empty() && request[0] == '/') request.erase(0, 1);
|
||||
if (request.find("res/") == 0) request.erase(0, 4);
|
||||
|
||||
std::string exeDir = PlatformFileIO.getBasePath().string();
|
||||
std::string exeDir = StdFileIO().getBasePath().string();
|
||||
std::string fileName = request;
|
||||
size_t lastSlash = fileName.find_last_of('/');
|
||||
if (lastSlash != std::string::npos)
|
||||
@@ -78,21 +83,24 @@ File::File(const std::wstring& pathname) {
|
||||
"/Common/res/TitleUpdate/res/",
|
||||
"/Common/Media/",
|
||||
"/Common/res/",
|
||||
"/Common/",
|
||||
"resources/"};
|
||||
"/Common/"};
|
||||
|
||||
for (const char* base : bases) {
|
||||
std::string tryFull = exeDir + base + request;
|
||||
std::string tryFile = exeDir + base + fileName;
|
||||
if (PlatformFileIO.exists(tryFull)) {
|
||||
if (access(tryFull.c_str(), F_OK) != -1) {
|
||||
m_abstractPathName = convStringToWstring(tryFull);
|
||||
return;
|
||||
}
|
||||
if (PlatformFileIO.exists(tryFile)) {
|
||||
if (access(tryFile.c_str(), F_OK) != -1) {
|
||||
m_abstractPathName = convStringToWstring(tryFile);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 4jcraft: If it's not a core asset, anchor it to the executable directory
|
||||
// so save files don't break
|
||||
m_abstractPathName = convStringToWstring(exeDir + "/" + request);
|
||||
#endif
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
@@ -155,7 +163,8 @@ this->parent = nullptr;
|
||||
// deleted; false otherwise
|
||||
bool File::_delete() {
|
||||
std::error_code error;
|
||||
const bool result = fs::remove(ToFilesystemPath(getPath()), error);
|
||||
// 4jcraft: remove all better
|
||||
const bool result = fs::remove_all(ToFilesystemPath(getPath()), error);
|
||||
if (!result || error) {
|
||||
#ifndef _CONTENT_PACKAGE
|
||||
printf("File::_delete - Error code %d (%#0.8X)\n", error.value(),
|
||||
@@ -401,4 +410,4 @@ int File::hash_fnct(const File& k) {
|
||||
}
|
||||
|
||||
return (int)hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,34 +3,28 @@
|
||||
#include <GL/gl.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "platform/sdl2/Render.h"
|
||||
#include "LevelRenderer.h"
|
||||
#include "TileRenderer.h"
|
||||
#include "app/include/FrameProfiler.h"
|
||||
#include "app/linux/LinuxGame.h"
|
||||
#include "app/linux/Stubs/winapi_stubs.h"
|
||||
#include "minecraft/SharedConstants.h"
|
||||
#include "minecraft/client/renderer/GameRenderer.h"
|
||||
#include "app/include/FrameProfiler.h"
|
||||
#include "TileRenderer.h"
|
||||
#include "minecraft/client/renderer/Tesselator.h"
|
||||
#include "minecraft/client/renderer/culling/Culler.h"
|
||||
#include "minecraft/client/renderer/tileentity/TileEntityRenderDispatcher.h"
|
||||
#include "minecraft/world/Icon.h"
|
||||
#include "minecraft/world/entity/Entity.h"
|
||||
#include "minecraft/world/level/Level.h"
|
||||
#include "minecraft/world/level/LevelSource.h"
|
||||
#include "minecraft/world/level/Region.h"
|
||||
#include "minecraft/world/level/chunk/LevelChunk.h"
|
||||
#include "minecraft/world/level/tile/LiquidTile.h"
|
||||
#include "minecraft/world/level/tile/Tile.h"
|
||||
#include "minecraft/world/level/tile/entity/TileEntity.h"
|
||||
#include "minecraft/world/phys/AABB.h"
|
||||
#include "platform/sdl2/Render.h"
|
||||
|
||||
int Chunk::updates = 0;
|
||||
|
||||
@@ -434,88 +428,6 @@ void Chunk::rebuild() {
|
||||
// 4J - optimisation ends
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Binary Mesh Greedy implementation
|
||||
// https://gedge.ca/blog/2014-08-17-greedy-voxel-meshing/
|
||||
// https://github.com/cgerikj/binary-greedy-meshing/tree/master
|
||||
// https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/
|
||||
// also https://github.com/whleucka/voxel/blob/main/src/chunk/chunk_mesh.cpp
|
||||
// ^ real useful thanks
|
||||
// also known as the "spongebob! why doesn't my AO work?"
|
||||
int greedyEligibleCount = 0;
|
||||
std::vector<uint8_t> greedyEligible(16 * 16 * 16, 0);
|
||||
std::vector<uint8_t> greedyLiquidTop(16 * 16 * 16, 0);
|
||||
#if defined(ENABLE_GREEDY_MESHING)
|
||||
{
|
||||
const double greedyEps = 1e-6;
|
||||
auto greedyIndex = [](int lx, int ly, int lz) {
|
||||
return (ly << 8) | (lz << 4) | lx;
|
||||
};
|
||||
|
||||
for (int z = z0; z < z1; z++) {
|
||||
for (int x = x0; x < x1; x++) {
|
||||
for (int y = y0; y < y1; y++) {
|
||||
int indexY = y;
|
||||
int offset = 0;
|
||||
if (indexY >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT) {
|
||||
indexY -= Level::COMPRESSED_CHUNK_SECTION_HEIGHT;
|
||||
offset = Level::COMPRESSED_CHUNK_SECTION_TILES;
|
||||
}
|
||||
|
||||
unsigned char tileId =
|
||||
tileIds[offset +
|
||||
(((x - x0) << 11) | ((z - z0) << 7) | indexY)];
|
||||
if (tileId == 0 || tileId == 0xff) continue;
|
||||
|
||||
Tile* tile = Tile::tiles[tileId];
|
||||
if (tile == nullptr) continue;
|
||||
if (tile->getRenderLayer() != 0) continue;
|
||||
if (tile->getRenderShape() != Tile::SHAPE_BLOCK) continue;
|
||||
if (tile->isEntityTile()) continue;
|
||||
if (!tile->isSolidRender()) continue;
|
||||
if (Tile::transculent[tileId]) continue;
|
||||
if (tileId == Tile::grass_Id) continue;
|
||||
|
||||
tile->updateShape(level, x, y, z, -1,
|
||||
std::shared_ptr<TileEntity>());
|
||||
|
||||
double x0s = tile->getShapeX0();
|
||||
double x1s = tile->getShapeX1();
|
||||
double y0s = tile->getShapeY0();
|
||||
double y1s = tile->getShapeY1();
|
||||
double z0s = tile->getShapeZ0();
|
||||
double z1s = tile->getShapeZ1();
|
||||
|
||||
if (std::fabs(x0s) > greedyEps ||
|
||||
std::fabs(y0s) > greedyEps ||
|
||||
std::fabs(z0s) > greedyEps ||
|
||||
std::fabs(x1s - 1.0) > greedyEps ||
|
||||
std::fabs(y1s - 1.0) > greedyEps ||
|
||||
std::fabs(z1s - 1.0) > greedyEps)
|
||||
continue;
|
||||
|
||||
bool ok = true;
|
||||
for (int face = 0; face < 6; face++) {
|
||||
if (tile->getTexture(level, x, y, z, face) == nullptr) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok) continue;
|
||||
|
||||
int lx = x - x0;
|
||||
int ly = y - y0;
|
||||
int lz = z - z0;
|
||||
greedyEligible[greedyIndex(lx, ly, lz)] = 1;
|
||||
greedyEligibleCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tileRenderer->setWaterTopSkipMask(greedyLiquidTop.data());
|
||||
#else
|
||||
tileRenderer->setWaterTopSkipMask(nullptr);
|
||||
#endif
|
||||
|
||||
Tesselator::Bounds bounds; // 4J MGH - added
|
||||
{
|
||||
// this was the old default clip bounds for the chunk, set in
|
||||
@@ -531,704 +443,8 @@ void Chunk::rebuild() {
|
||||
for (int currentLayer = 0; currentLayer < 2; currentLayer++) {
|
||||
bool renderNextLayer = false;
|
||||
bool rendered = false;
|
||||
// second part of the greedy mesh implementation
|
||||
bool listStarted = false;
|
||||
bool normalTessActive = false;
|
||||
bool greedyTessActive = false;
|
||||
int greedyMergedQuads = 0;
|
||||
int greedyTilesEmitted = 0;
|
||||
int greedyLiquidMergedQuads = 0;
|
||||
int greedyLiquidTilesEmitted = 0;
|
||||
|
||||
auto startListIfNeeded = [&]() {
|
||||
if (listStarted) return;
|
||||
listStarted = true;
|
||||
|
||||
glNewList(lists + currentLayer, GL_COMPILE);
|
||||
glDepthMask(true);
|
||||
};
|
||||
|
||||
auto beginNormal = [&]() {
|
||||
if (normalTessActive) return;
|
||||
startListIfNeeded();
|
||||
|
||||
t->useCompactVertices(true);
|
||||
t->useTileUV(false);
|
||||
t->begin();
|
||||
t->offset((float)(-this->x), (float)(-this->y), (float)(-this->z));
|
||||
normalTessActive = true;
|
||||
};
|
||||
|
||||
auto endNormal = [&]() {
|
||||
if (!normalTessActive) return;
|
||||
t->end();
|
||||
bounds.addBounds(t->bounds);
|
||||
t->offset(0, 0, 0);
|
||||
normalTessActive = false;
|
||||
};
|
||||
|
||||
auto beginGreedy = [&]() {
|
||||
if (greedyTessActive) return;
|
||||
startListIfNeeded();
|
||||
|
||||
t->useCompactVertices(false);
|
||||
t->useTileUV(true);
|
||||
t->begin();
|
||||
t->offset((float)(-this->x), (float)(-this->y), (float)(-this->z));
|
||||
greedyTessActive = true;
|
||||
};
|
||||
|
||||
auto endGreedy = [&]() {
|
||||
if (!greedyTessActive) return;
|
||||
t->end();
|
||||
bounds.addBounds(t->bounds);
|
||||
t->useTileUV(false);
|
||||
t->offset(0, 0, 0);
|
||||
greedyTessActive = false;
|
||||
};
|
||||
|
||||
auto greedyIndex = [](int lx, int ly, int lz) {
|
||||
return (ly << 8) | (lz << 4) | lx;
|
||||
};
|
||||
|
||||
auto getTileIdLocal = [&](int lx, int ly, int lz) -> unsigned char {
|
||||
int worldY = y0 + ly;
|
||||
int indexY = worldY;
|
||||
int offset = 0;
|
||||
if (indexY >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT) {
|
||||
indexY -= Level::COMPRESSED_CHUNK_SECTION_HEIGHT;
|
||||
offset = Level::COMPRESSED_CHUNK_SECTION_TILES;
|
||||
}
|
||||
return tileIds[offset +
|
||||
(((lx + 0) << 11) | ((lz + 0) << 7) | indexY)];
|
||||
};
|
||||
// bread taste better than key
|
||||
auto computeFaceKey = [&](Tile* tile, int wx, int wy, int wz, int face,
|
||||
uint32_t& colorKey, int& lightKey) {
|
||||
int col = tile->getColor(level, wx, wy, wz);
|
||||
float r = ((col >> 16) & 0xff) / 255.0f;
|
||||
float g = ((col >> 8) & 0xff) / 255.0f;
|
||||
float b = ((col) & 0xff) / 255.0f;
|
||||
|
||||
|
||||
if (GameRenderer::anaglyph3d) {
|
||||
// todo: this will DEF break anaglyph rendering
|
||||
// do we still need it?????????
|
||||
}
|
||||
|
||||
float shade = 1.0f;
|
||||
switch (face) {
|
||||
case 0:
|
||||
shade = 0.5f;
|
||||
break;
|
||||
case 1:
|
||||
shade = 1.0f;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
shade = 0.8f;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
shade = 0.6f;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
r *= shade;
|
||||
g *= shade;
|
||||
b *= shade;
|
||||
|
||||
if (SharedConstants::TEXTURE_LIGHTING) {
|
||||
int nx = wx, ny = wy, nz = wz;
|
||||
if (face == 0) ny--;
|
||||
if (face == 1) ny++;
|
||||
if (face == 2) nz--;
|
||||
if (face == 3) nz++;
|
||||
if (face == 4) nx--;
|
||||
if (face == 5) nx++;
|
||||
lightKey = tileRenderer->getLightColor(tile, level, nx, ny, nz);
|
||||
} else {
|
||||
int nx = wx, ny = wy, nz = wz;
|
||||
if (face == 0) ny--;
|
||||
if (face == 1) ny++;
|
||||
if (face == 2) nz--;
|
||||
if (face == 3) nz++;
|
||||
if (face == 4) nx--;
|
||||
if (face == 5) nx++;
|
||||
float br = tile->getBrightness(level, nx, ny, nz);
|
||||
r *= br;
|
||||
g *= br;
|
||||
b *= br;
|
||||
lightKey = 0;
|
||||
}
|
||||
|
||||
auto clampByte = [](float v) -> uint8_t {
|
||||
int iv = (int)(v * 255.0f + 0.5f);
|
||||
if (iv < 0) iv = 0;
|
||||
if (iv > 255) iv = 255;
|
||||
return (uint8_t)iv;
|
||||
};
|
||||
|
||||
colorKey =
|
||||
(clampByte(r) << 16) | (clampByte(g) << 8) | (clampByte(b));
|
||||
};
|
||||
|
||||
auto shadeAt = [&](Tile* tile, int ax, int ay, int az) {
|
||||
return tileRenderer->getShadeBrightness(tile, level, ax, ay, az);
|
||||
};
|
||||
|
||||
auto aoCorner = [&](float s1, float s2, float s3) {
|
||||
if (s1 < 1.0f && s2 < 1.0f) return 0.2f;
|
||||
return (s1 + s2 + s3) / 3.0f;
|
||||
};
|
||||
|
||||
auto computeFaceAO = [&](Tile* tile, int wx, int wy, int wz, int face,
|
||||
float outAo[4]) {
|
||||
switch (face) {
|
||||
case 0: { // Down (y-1)
|
||||
float sW = shadeAt(tile, wx - 1, wy - 1, wz);
|
||||
float sE = shadeAt(tile, wx + 1, wy - 1, wz);
|
||||
float sN = shadeAt(tile, wx, wy - 1, wz - 1);
|
||||
float sS = shadeAt(tile, wx, wy - 1, wz + 1);
|
||||
float sWN = shadeAt(tile, wx - 1, wy - 1, wz - 1);
|
||||
float sWS = shadeAt(tile, wx - 1, wy - 1, wz + 1);
|
||||
float sEN = shadeAt(tile, wx + 1, wy - 1, wz - 1);
|
||||
float sES = shadeAt(tile, wx + 1, wy - 1, wz + 1);
|
||||
|
||||
outAo[0] = aoCorner(sW, sS, sWS);
|
||||
outAo[1] = aoCorner(sW, sN, sWN);
|
||||
outAo[2] = aoCorner(sE, sN, sEN);
|
||||
outAo[3] = aoCorner(sE, sS, sES);
|
||||
} break;
|
||||
case 1: { // Up (y+1)
|
||||
float sW = shadeAt(tile, wx - 1, wy + 1, wz);
|
||||
float sE = shadeAt(tile, wx + 1, wy + 1, wz);
|
||||
float sN = shadeAt(tile, wx, wy + 1, wz - 1);
|
||||
float sS = shadeAt(tile, wx, wy + 1, wz + 1);
|
||||
float sWN = shadeAt(tile, wx - 1, wy + 1, wz - 1);
|
||||
float sWS = shadeAt(tile, wx - 1, wy + 1, wz + 1);
|
||||
float sEN = shadeAt(tile, wx + 1, wy + 1, wz - 1);
|
||||
float sES = shadeAt(tile, wx + 1, wy + 1, wz + 1);
|
||||
|
||||
outAo[0] = aoCorner(sE, sS, sES);
|
||||
outAo[1] = aoCorner(sE, sN, sEN);
|
||||
outAo[2] = aoCorner(sW, sN, sWN);
|
||||
outAo[3] = aoCorner(sW, sS, sWS);
|
||||
} break;
|
||||
case 2: { // North (z-1)
|
||||
float sW = shadeAt(tile, wx - 1, wy, wz - 1);
|
||||
float sE = shadeAt(tile, wx + 1, wy, wz - 1);
|
||||
float sU = shadeAt(tile, wx, wy + 1, wz - 1);
|
||||
float sD = shadeAt(tile, wx, wy - 1, wz - 1);
|
||||
float sWU = shadeAt(tile, wx - 1, wy + 1, wz - 1);
|
||||
float sWD = shadeAt(tile, wx - 1, wy - 1, wz - 1);
|
||||
float sEU = shadeAt(tile, wx + 1, wy + 1, wz - 1);
|
||||
float sED = shadeAt(tile, wx + 1, wy - 1, wz - 1);
|
||||
|
||||
outAo[0] = aoCorner(sW, sU, sWU);
|
||||
outAo[1] = aoCorner(sE, sU, sEU);
|
||||
outAo[2] = aoCorner(sE, sD, sED);
|
||||
outAo[3] = aoCorner(sW, sD, sWD);
|
||||
} break;
|
||||
case 3: { // South (z+1)
|
||||
float sW = shadeAt(tile, wx - 1, wy, wz + 1);
|
||||
float sE = shadeAt(tile, wx + 1, wy, wz + 1);
|
||||
float sU = shadeAt(tile, wx, wy + 1, wz + 1);
|
||||
float sD = shadeAt(tile, wx, wy - 1, wz + 1);
|
||||
float sWU = shadeAt(tile, wx - 1, wy + 1, wz + 1);
|
||||
float sWD = shadeAt(tile, wx - 1, wy - 1, wz + 1);
|
||||
float sEU = shadeAt(tile, wx + 1, wy + 1, wz + 1);
|
||||
float sED = shadeAt(tile, wx + 1, wy - 1, wz + 1);
|
||||
|
||||
outAo[0] = aoCorner(sW, sU, sWU);
|
||||
outAo[1] = aoCorner(sW, sD, sWD);
|
||||
outAo[2] = aoCorner(sE, sD, sED);
|
||||
outAo[3] = aoCorner(sE, sU, sEU);
|
||||
} break;
|
||||
case 4: { // West (x-1)
|
||||
float sN = shadeAt(tile, wx - 1, wy, wz - 1);
|
||||
float sS = shadeAt(tile, wx - 1, wy, wz + 1);
|
||||
float sU = shadeAt(tile, wx - 1, wy + 1, wz);
|
||||
float sD = shadeAt(tile, wx - 1, wy - 1, wz);
|
||||
float sNU = shadeAt(tile, wx - 1, wy + 1, wz - 1);
|
||||
float sND = shadeAt(tile, wx - 1, wy - 1, wz - 1);
|
||||
float sSU = shadeAt(tile, wx - 1, wy + 1, wz + 1);
|
||||
float sSD = shadeAt(tile, wx - 1, wy - 1, wz + 1);
|
||||
|
||||
outAo[0] = aoCorner(sS, sU, sSU);
|
||||
outAo[1] = aoCorner(sN, sU, sNU);
|
||||
outAo[2] = aoCorner(sN, sD, sND);
|
||||
outAo[3] = aoCorner(sS, sD, sSD);
|
||||
} break;
|
||||
case 5: { // East (x+1)
|
||||
float sN = shadeAt(tile, wx + 1, wy, wz - 1);
|
||||
float sS = shadeAt(tile, wx + 1, wy, wz + 1);
|
||||
float sU = shadeAt(tile, wx + 1, wy + 1, wz);
|
||||
float sD = shadeAt(tile, wx + 1, wy - 1, wz);
|
||||
float sNU = shadeAt(tile, wx + 1, wy + 1, wz - 1);
|
||||
float sND = shadeAt(tile, wx + 1, wy - 1, wz - 1);
|
||||
float sSU = shadeAt(tile, wx + 1, wy + 1, wz + 1);
|
||||
float sSD = shadeAt(tile, wx + 1, wy - 1, wz + 1);
|
||||
|
||||
outAo[0] = aoCorner(sS, sD, sSD);
|
||||
outAo[1] = aoCorner(sN, sD, sND);
|
||||
outAo[2] = aoCorner(sN, sU, sNU);
|
||||
outAo[3] = aoCorner(sS, sU, sSU);
|
||||
} break;
|
||||
default:
|
||||
outAo[0] = outAo[1] = outAo[2] = outAo[3] = 1.0f;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
struct GreedyFaceKey {
|
||||
Tile* tile;
|
||||
Icon* tex;
|
||||
uint32_t colorKey;
|
||||
uint32_t aoKey;
|
||||
int lightKey;
|
||||
bool mipmap;
|
||||
bool operator==(const GreedyFaceKey& other) const {
|
||||
return tile == other.tile && tex == other.tex &&
|
||||
colorKey == other.colorKey && aoKey == other.aoKey &&
|
||||
lightKey == other.lightKey && mipmap == other.mipmap;
|
||||
}
|
||||
};
|
||||
|
||||
auto greedyMeshFace = [&](int face) {
|
||||
const int U = 16;
|
||||
const int V = 16;
|
||||
std::vector<uint8_t> valid(U * V, 0);
|
||||
std::vector<GreedyFaceKey> keys(U * V);
|
||||
bool faceRendered = false;
|
||||
|
||||
for (int slice = 0; slice < 16; slice++) {
|
||||
memset(valid.data(), 0, valid.size());
|
||||
|
||||
for (int v = 0; v < V; v++) {
|
||||
for (int u = 0; u < U; u++) {
|
||||
int lx = 0, ly = 0, lz = 0;
|
||||
switch (face) {
|
||||
case 0:
|
||||
case 1:
|
||||
lx = u;
|
||||
ly = slice;
|
||||
lz = v;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
lx = u;
|
||||
ly = v;
|
||||
lz = slice;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
lx = slice;
|
||||
ly = v;
|
||||
lz = u;
|
||||
break;
|
||||
}
|
||||
|
||||
int idx = greedyIndex(lx, ly, lz);
|
||||
if (greedyEligible[idx] == 0) continue;
|
||||
|
||||
int wx = x0 + lx;
|
||||
int wy = y0 + ly;
|
||||
int wz = z0 + lz;
|
||||
|
||||
unsigned char tileId = getTileIdLocal(lx, ly, lz);
|
||||
if (tileId == 0 || tileId == 0xff) continue;
|
||||
|
||||
Tile* tile = Tile::tiles[tileId];
|
||||
if (tile == nullptr) continue;
|
||||
if (tile->getRenderLayer() != currentLayer) continue;
|
||||
|
||||
bool visible = false;
|
||||
if (face == 0)
|
||||
visible = tile->shouldRenderFace(level, wx, wy - 1,
|
||||
wz, 0);
|
||||
else if (face == 1)
|
||||
visible = tile->shouldRenderFace(level, wx, wy + 1,
|
||||
wz, 1);
|
||||
else if (face == 2)
|
||||
visible = tile->shouldRenderFace(level, wx, wy,
|
||||
wz - 1, 2);
|
||||
else if (face == 3)
|
||||
visible = tile->shouldRenderFace(level, wx, wy,
|
||||
wz + 1, 3);
|
||||
else if (face == 4)
|
||||
visible = tile->shouldRenderFace(level, wx - 1, wy,
|
||||
wz, 4);
|
||||
else if (face == 5)
|
||||
visible = tile->shouldRenderFace(level, wx + 1, wy,
|
||||
wz, 5);
|
||||
|
||||
if (!visible) continue;
|
||||
|
||||
Icon* tex = tile->getTexture(level, wx, wy, wz, face);
|
||||
if (tex == nullptr) continue;
|
||||
|
||||
GreedyFaceKey key{};
|
||||
key.tile = tile;
|
||||
key.tex = tex;
|
||||
key.mipmap = Tile::mipmapEnable[tileId];
|
||||
|
||||
uint32_t colorKey = 0;
|
||||
int lightKey = 0;
|
||||
computeFaceKey(tile, wx, wy, wz, face, colorKey,
|
||||
lightKey);
|
||||
key.colorKey = colorKey;
|
||||
key.lightKey = lightKey;
|
||||
|
||||
float ao[4];
|
||||
computeFaceAO(tile, wx, wy, wz, face, ao);
|
||||
auto aoByte = [](float v) -> uint32_t {
|
||||
int iv = (int)(v * 255.0f + 0.5f);
|
||||
if (iv < 0) iv = 0;
|
||||
if (iv > 255) iv = 255;
|
||||
return (uint32_t)iv;
|
||||
};
|
||||
key.aoKey = (aoByte(ao[0]) << 24) |
|
||||
(aoByte(ao[1]) << 16) |
|
||||
(aoByte(ao[2]) << 8) | aoByte(ao[3]);
|
||||
|
||||
valid[u + v * U] = 1;
|
||||
keys[u + v * U] = key;
|
||||
}
|
||||
}
|
||||
|
||||
for (int v = 0; v < V; v++) {
|
||||
for (int u = 0; u < U; u++) {
|
||||
int idx = u + v * U;
|
||||
if (!valid[idx]) continue;
|
||||
|
||||
GreedyFaceKey key = keys[idx];
|
||||
|
||||
int w = 1;
|
||||
while (u + w < U && valid[idx + w] &&
|
||||
keys[idx + w] == key) {
|
||||
w++;
|
||||
}
|
||||
|
||||
int h = 1;
|
||||
bool done = false;
|
||||
while (v + h < V && !done) {
|
||||
for (int k = 0; k < w; k++) {
|
||||
int idx2 = (u + k) + (v + h) * U;
|
||||
if (!valid[idx2] || !(keys[idx2] == key)) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!done) h++;
|
||||
}
|
||||
|
||||
for (int dv = 0; dv < h; dv++) {
|
||||
for (int du = 0; du < w; du++) {
|
||||
valid[(u + du) + (v + dv) * U] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
greedyMergedQuads++;
|
||||
greedyTilesEmitted += (w * h);
|
||||
|
||||
beginGreedy();
|
||||
|
||||
t->setMipmapEnable(key.mipmap);
|
||||
if (SharedConstants::TEXTURE_LIGHTING) {
|
||||
t->tex2(key.lightKey);
|
||||
}
|
||||
|
||||
float rr = ((key.colorKey >> 16) & 0xff) / 255.0f;
|
||||
float gg = ((key.colorKey >> 8) & 0xff) / 255.0f;
|
||||
float bb = (key.colorKey & 0xff) / 255.0f;
|
||||
|
||||
float ao1 = ((key.aoKey >> 24) & 0xff) / 255.0f;
|
||||
float ao2 = ((key.aoKey >> 16) & 0xff) / 255.0f;
|
||||
float ao3 = ((key.aoKey >> 8) & 0xff) / 255.0f;
|
||||
float ao4 = (key.aoKey & 0xff) / 255.0f;
|
||||
|
||||
tileRenderer->setGreedyAO(
|
||||
rr, gg, bb, ao1, ao2, ao3, ao4,
|
||||
SharedConstants::TEXTURE_LIGHTING ? key.lightKey
|
||||
: 0);
|
||||
|
||||
int baseX = 0, baseY = 0, baseZ = 0;
|
||||
switch (face) {
|
||||
case 0:
|
||||
case 1:
|
||||
baseX = x0 + u;
|
||||
baseY = y0 + slice;
|
||||
baseZ = z0 + v;
|
||||
tileRenderer->setShape(
|
||||
0.0f, 0.0f, 0.0f, (float)w, 1.0f, (float)h);
|
||||
if (face == 0) {
|
||||
t->normal(0.0f, -1.0f, 0.0f);
|
||||
tileRenderer->renderFaceDown(
|
||||
key.tile, baseX, baseY, baseZ, key.tex);
|
||||
} else {
|
||||
t->normal(0.0f, 1.0f, 0.0f);
|
||||
tileRenderer->renderFaceUp(
|
||||
key.tile, baseX, baseY, baseZ, key.tex);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
baseX = x0 + u;
|
||||
baseY = y0 + v;
|
||||
baseZ = z0 + slice;
|
||||
tileRenderer->setShape(
|
||||
0.0f, 0.0f, 0.0f, (float)w, (float)h, 1.0f);
|
||||
if (face == 2) {
|
||||
t->normal(0.0f, 0.0f, -1.0f);
|
||||
tileRenderer->renderNorth(
|
||||
key.tile, baseX, baseY, baseZ, key.tex);
|
||||
} else {
|
||||
t->normal(0.0f, 0.0f, 1.0f);
|
||||
tileRenderer->renderSouth(
|
||||
key.tile, baseX, baseY, baseZ, key.tex);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
baseX = x0 + slice;
|
||||
baseY = y0 + v;
|
||||
baseZ = z0 + u;
|
||||
tileRenderer->setShape(0.0f, 0.0f, 0.0f, 1.0f,
|
||||
(float)h, (float)w);
|
||||
if (face == 4) {
|
||||
t->normal(-1.0f, 0.0f, 0.0f);
|
||||
tileRenderer->renderWest(
|
||||
key.tile, baseX, baseY, baseZ, key.tex);
|
||||
} else {
|
||||
t->normal(1.0f, 0.0f, 0.0f);
|
||||
tileRenderer->renderEast(
|
||||
key.tile, baseX, baseY, baseZ, key.tex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// who the fuck at 4j named those functions.
|
||||
tileRenderer->setApplyAmbienceOcclusion(false);
|
||||
faceRendered = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return faceRendered;
|
||||
};
|
||||
|
||||
struct LiquidTopKey {
|
||||
Tile* tile;
|
||||
Icon* tex;
|
||||
uint32_t colorKey;
|
||||
int lightKey;
|
||||
bool mipmap;
|
||||
int heightQ;
|
||||
float height;
|
||||
bool operator==(const LiquidTopKey& other) const {
|
||||
return tile == other.tile && tex == other.tex &&
|
||||
colorKey == other.colorKey &&
|
||||
lightKey == other.lightKey && mipmap == other.mipmap &&
|
||||
heightQ == other.heightQ;
|
||||
}
|
||||
};
|
||||
// liquids & oceans are usually flat, so they can definitively benefit from having this optimization.
|
||||
auto greedyMeshLiquidTop = [&]() {
|
||||
const int U = 16;
|
||||
const int V = 16;
|
||||
bool faceRendered = false;
|
||||
const float hEps = 1e-4f;
|
||||
|
||||
for (int ly = 0; ly < 16; ly++) {
|
||||
std::vector<uint8_t> valid(U * V, 0);
|
||||
std::vector<LiquidTopKey> keys(U * V);
|
||||
|
||||
for (int lz = 0; lz < V; lz++) {
|
||||
for (int lx = 0; lx < U; lx++) {
|
||||
unsigned char tileId = getTileIdLocal(lx, ly, lz);
|
||||
if (tileId == 0 || tileId == 0xff) continue;
|
||||
|
||||
Tile* tile = Tile::tiles[tileId];
|
||||
if (tile == nullptr) continue;
|
||||
if (tile->getRenderShape() != Tile::SHAPE_WATER)
|
||||
continue;
|
||||
if (tile->getRenderLayer() != currentLayer) continue;
|
||||
|
||||
int wx = x0 + lx;
|
||||
int wy = y0 + ly;
|
||||
int wz = z0 + lz;
|
||||
|
||||
if (!tile->shouldRenderFace(level, wx, wy + 1, wz, 1))
|
||||
continue;
|
||||
|
||||
if (LiquidTile::getSlopeAngle(level, wx, wy, wz,
|
||||
tile->material) > -999)
|
||||
continue;
|
||||
|
||||
float h0 = tileRenderer->getWaterHeightAt(
|
||||
wx, wy, wz, tile->material);
|
||||
float h1 = tileRenderer->getWaterHeightAt(
|
||||
wx, wy, wz + 1, tile->material);
|
||||
float h2 = tileRenderer->getWaterHeightAt(
|
||||
wx + 1, wy, wz + 1, tile->material);
|
||||
float h3 = tileRenderer->getWaterHeightAt(
|
||||
wx + 1, wy, wz, tile->material);
|
||||
|
||||
float hmin = h0;
|
||||
if (h1 < hmin) hmin = h1;
|
||||
if (h2 < hmin) hmin = h2;
|
||||
if (h3 < hmin) hmin = h3;
|
||||
float hmax = h0;
|
||||
if (h1 > hmax) hmax = h1;
|
||||
if (h2 > hmax) hmax = h2;
|
||||
if (h3 > hmax) hmax = h3;
|
||||
|
||||
if (hmax - hmin > hEps) continue;
|
||||
|
||||
float height = hmax - 0.001f;
|
||||
if (height < 0.0f) height = hmax;
|
||||
int heightQ = (int)(height * 4096.0f + 0.5f);
|
||||
|
||||
int data = level->getData(wx, wy, wz);
|
||||
Icon* tex = tileRenderer->getTexture(tile, 1, data);
|
||||
if (tex == nullptr) continue;
|
||||
|
||||
LiquidTopKey key{};
|
||||
key.tile = tile;
|
||||
key.tex = tex;
|
||||
key.mipmap = Tile::mipmapEnable[tileId];
|
||||
key.heightQ = heightQ;
|
||||
key.height = height;
|
||||
|
||||
int col = tile->getColor(level, wx, wy, wz);
|
||||
float r = ((col >> 16) & 0xff) / 255.0f;
|
||||
float g = ((col >> 8) & 0xff) / 255.0f;
|
||||
float b = ((col) & 0xff) / 255.0f;
|
||||
|
||||
if (GameRenderer::anaglyph3d) {
|
||||
float cr = (r * 30 + g * 59 + b * 11) / 100;
|
||||
float cg = (r * 30 + g * 70) / (100);
|
||||
float cb = (r * 30 + b * 70) / (100);
|
||||
r = cr;
|
||||
g = cg;
|
||||
b = cb;
|
||||
}
|
||||
|
||||
if (SharedConstants::TEXTURE_LIGHTING) {
|
||||
key.lightKey = tileRenderer->getLightColor(
|
||||
tile, level, wx, wy, wz);
|
||||
} else {
|
||||
float br = tile->getBrightness(level, wx, wy, wz);
|
||||
r *= br;
|
||||
g *= br;
|
||||
b *= br;
|
||||
key.lightKey = 0;
|
||||
}
|
||||
|
||||
auto clampByte = [](float v) -> uint8_t {
|
||||
int iv = (int)(v * 255.0f + 0.5f);
|
||||
if (iv < 0) iv = 0;
|
||||
if (iv > 255) iv = 255;
|
||||
return (uint8_t)iv;
|
||||
};
|
||||
key.colorKey = (clampByte(r) << 16) |
|
||||
(clampByte(g) << 8) | (clampByte(b));
|
||||
|
||||
valid[lx + lz * U] = 1;
|
||||
keys[lx + lz * U] = key;
|
||||
}
|
||||
}
|
||||
|
||||
for (int v = 0; v < V; v++) {
|
||||
for (int u = 0; u < U; u++) {
|
||||
int idx = u + v * U;
|
||||
if (!valid[idx]) continue;
|
||||
|
||||
LiquidTopKey key = keys[idx];
|
||||
|
||||
int w = 1;
|
||||
while (u + w < U && valid[idx + w] &&
|
||||
keys[idx + w] == key) {
|
||||
w++;
|
||||
}
|
||||
|
||||
int h = 1;
|
||||
bool done = false;
|
||||
while (v + h < V && !done) {
|
||||
for (int k = 0; k < w; k++) {
|
||||
int idx2 = (u + k) + (v + h) * U;
|
||||
if (!valid[idx2] || !(keys[idx2] == key)) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!done) h++;
|
||||
}
|
||||
|
||||
for (int dv = 0; dv < h; dv++) {
|
||||
for (int du = 0; du < w; du++) {
|
||||
valid[(u + du) + (v + dv) * U] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
greedyLiquidMergedQuads++;
|
||||
greedyLiquidTilesEmitted += (w * h);
|
||||
|
||||
beginGreedy();
|
||||
tileRenderer->setApplyAmbienceOcclusion(false);
|
||||
|
||||
t->setMipmapEnable(key.mipmap);
|
||||
if (SharedConstants::TEXTURE_LIGHTING) {
|
||||
t->tex2(key.lightKey);
|
||||
}
|
||||
|
||||
float rr = ((key.colorKey >> 16) & 0xff) / 255.0f;
|
||||
float gg = ((key.colorKey >> 8) & 0xff) / 255.0f;
|
||||
float bb = (key.colorKey & 0xff) / 255.0f;
|
||||
t->color(rr, gg, bb);
|
||||
|
||||
int baseX = x0 + u;
|
||||
int baseY = y0 + ly;
|
||||
int baseZ = z0 + v;
|
||||
tileRenderer->setShape(0.0f, 0.0f, 0.0f, (float)w,
|
||||
key.height, (float)h);
|
||||
t->normal(0.0f, 1.0f, 0.0f);
|
||||
tileRenderer->renderFaceUp(key.tile, baseX, baseY,
|
||||
baseZ, key.tex);
|
||||
|
||||
for (int dv = 0; dv < h; dv++) {
|
||||
for (int du = 0; du < w; du++) {
|
||||
int lx = u + du;
|
||||
int lz = v + dv;
|
||||
int maskIdx = (ly << 8) | (lz << 4) | lx;
|
||||
greedyLiquidTop[maskIdx] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
faceRendered = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return faceRendered;
|
||||
};
|
||||
|
||||
#if defined(ENABLE_GREEDY_MESHING)
|
||||
rendered |= greedyMeshLiquidTop();
|
||||
|
||||
if (currentLayer == 0) {
|
||||
tileRenderer->setApplyAmbienceOcclusion(false);
|
||||
rendered |= greedyMeshFace(0);
|
||||
rendered |= greedyMeshFace(1);
|
||||
rendered |= greedyMeshFace(2);
|
||||
rendered |= greedyMeshFace(3);
|
||||
rendered |= greedyMeshFace(4);
|
||||
rendered |= greedyMeshFace(5);
|
||||
}
|
||||
endGreedy();
|
||||
#endif
|
||||
bool started = false;
|
||||
|
||||
// 4J - changed loop order here to leave y as the innermost loop for
|
||||
// better cache performance
|
||||
@@ -1254,6 +470,17 @@ void Chunk::rebuild() {
|
||||
// int tileId =
|
||||
// region->getTile(x,y,z);
|
||||
if (tileId > 0) {
|
||||
if (!started) {
|
||||
started = true;
|
||||
|
||||
glNewList(lists + currentLayer, GL_COMPILE);
|
||||
glDepthMask(true); // 4J added
|
||||
t->useCompactVertices(true); // 4J added
|
||||
t->begin();
|
||||
t->offset((float)(-this->x), (float)(-this->y),
|
||||
(float)(-this->z));
|
||||
}
|
||||
|
||||
Tile* tile = Tile::tiles[tileId];
|
||||
if (currentLayer == 0 && tile->isEntityTile()) {
|
||||
std::shared_ptr<TileEntity> et =
|
||||
@@ -1268,19 +495,6 @@ void Chunk::rebuild() {
|
||||
if (renderLayer != currentLayer) {
|
||||
renderNextLayer = true;
|
||||
} else if (renderLayer == currentLayer) {
|
||||
#if defined(ENABLE_GREEDY_MESHING)
|
||||
if (currentLayer == 0) {
|
||||
int lx = x - x0;
|
||||
int ly = y - y0;
|
||||
int lz = z - z0;
|
||||
if (greedyEligible[greedyIndex(lx, ly, lz)] !=
|
||||
0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
beginNormal();
|
||||
rendered |=
|
||||
tileRenderer->tesselateInWorld(tile, x, y, z);
|
||||
}
|
||||
@@ -1289,14 +503,12 @@ void Chunk::rebuild() {
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(ENABLE_GREEDY_MESHING)
|
||||
endGreedy();
|
||||
#endif
|
||||
endNormal();
|
||||
|
||||
if (listStarted) {
|
||||
if (started) {
|
||||
t->end();
|
||||
bounds.addBounds(t->bounds); // 4J MGH - added
|
||||
glEndList();
|
||||
t->useCompactVertices(false); // 4J added
|
||||
t->offset(0, 0, 0);
|
||||
} else {
|
||||
rendered = false;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,6 @@ Tesselator::Tesselator(int size) {
|
||||
useCompactFormat360 = false; // 4J added
|
||||
mipmapEnable = true; // 4J added
|
||||
useProjectedTexturePixelShader = false; // 4J added
|
||||
useTileUVEnabled = false;
|
||||
|
||||
this->size = size;
|
||||
|
||||
@@ -111,9 +110,7 @@ void Tesselator::end() {
|
||||
_array->data(),
|
||||
useCompactFormat360
|
||||
? C4JRender::VERTEX_TYPE_COMPRESSED
|
||||
: (useTileUVEnabled
|
||||
? C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_TILEUV
|
||||
: C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1),
|
||||
: C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1,
|
||||
useProjectedTexturePixelShader
|
||||
? C4JRender::PIXEL_SHADER_TYPE_PROJECTION
|
||||
: C4JRender::PIXEL_SHADER_TYPE_STANDARD);
|
||||
@@ -141,9 +138,7 @@ void Tesselator::end() {
|
||||
RenderManager.DrawVertices(
|
||||
(C4JRender::ePrimitiveType)mode, vertexCount,
|
||||
_array->data(),
|
||||
useTileUVEnabled
|
||||
? C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_TILEUV
|
||||
: C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1,
|
||||
C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1,
|
||||
C4JRender::PIXEL_SHADER_TYPE_STANDARD);
|
||||
}
|
||||
}
|
||||
@@ -182,8 +177,6 @@ void Tesselator::useCompactVertices(bool enable) {
|
||||
useCompactFormat360 = enable;
|
||||
}
|
||||
|
||||
void Tesselator::useTileUV(bool enable) { useTileUVEnabled = enable; }
|
||||
|
||||
bool Tesselator::getCompactVertices() { return useCompactFormat360; }
|
||||
|
||||
bool Tesselator::setMipmapEnable(bool enable) {
|
||||
@@ -607,4 +600,4 @@ void Tesselator::addOffset(float x, float y, float z) {
|
||||
zo += z;
|
||||
}
|
||||
|
||||
bool Tesselator::hasMaxVertices() { return false; }
|
||||
bool Tesselator::hasMaxVertices() { return false; }
|
||||
@@ -33,7 +33,6 @@ private:
|
||||
int p;
|
||||
bool useCompactFormat360; // 4J - added
|
||||
bool useProjectedTexturePixelShader; // 4J - added
|
||||
bool useTileUVEnabled;
|
||||
public:
|
||||
int count;
|
||||
|
||||
@@ -126,7 +125,6 @@ public:
|
||||
void useCompactVertices(bool enable); // 4J added
|
||||
bool getCompactVertices(); // AP added
|
||||
void useProjectedTexture(bool enable); // 4J added
|
||||
void useTileUV(bool enable);
|
||||
void tex(float u, float v);
|
||||
void tex2(int tex2); // 4J - change brought forward from 1.8.2
|
||||
void color(float r, float g, float b);
|
||||
@@ -145,4 +143,4 @@ public:
|
||||
bool setMipmapEnable(bool enable); // 4J added
|
||||
|
||||
bool hasMaxVertices(); // 4J Added
|
||||
};
|
||||
};
|
||||
@@ -9,12 +9,13 @@
|
||||
#include <cmath>
|
||||
#include <numbers>
|
||||
|
||||
#include "platform/sdl2/Render.h"
|
||||
#include "EntityTileRenderer.h"
|
||||
#include "GameRenderer.h"
|
||||
#include "Tesselator.h"
|
||||
#include "app/common/App_enums.h"
|
||||
#include "app/common/src/Colours/ColourTable.h"
|
||||
#include "app/include/FrameProfiler.h"
|
||||
#include "Tesselator.h"
|
||||
#include "minecraft/Direction.h"
|
||||
#include "minecraft/Facing.h"
|
||||
#include "minecraft/SharedConstants.h"
|
||||
@@ -64,7 +65,6 @@
|
||||
#include "minecraft/world/level/tile/piston/PistonBaseTile.h"
|
||||
#include "minecraft/world/level/tile/piston/PistonExtensionTile.h"
|
||||
#include "minecraft/world/phys/Vec3.h"
|
||||
#include "platform/sdl2/Render.h"
|
||||
|
||||
bool TileRenderer::fancy = true;
|
||||
|
||||
@@ -75,7 +75,6 @@ void TileRenderer::_init() {
|
||||
xFlipTexture = false;
|
||||
noCulling = false;
|
||||
applyAmbienceOcclusion = false;
|
||||
waterTopSkipMask = nullptr;
|
||||
setColor = true;
|
||||
northFlip = FLIP_NONE;
|
||||
southFlip = FLIP_NONE;
|
||||
@@ -237,40 +236,6 @@ void TileRenderer::clearFixedTexture() { this->fixedTexture = nullptr; }
|
||||
|
||||
bool TileRenderer::hasFixedTexture() { return fixedTexture != nullptr; }
|
||||
|
||||
void TileRenderer::setApplyAmbienceOcclusion(bool enabled) {
|
||||
applyAmbienceOcclusion = enabled;
|
||||
}
|
||||
|
||||
void TileRenderer::setWaterTopSkipMask(const uint8_t* mask) {
|
||||
waterTopSkipMask = mask;
|
||||
}
|
||||
|
||||
void TileRenderer::setGreedyAO(float baseR, float baseG, float baseB, float ao1,
|
||||
float ao2, float ao3, float ao4, int tex2) {
|
||||
applyAmbienceOcclusion = true;
|
||||
|
||||
c1r = baseR * ao1;
|
||||
c1g = baseG * ao1;
|
||||
c1b = baseB * ao1;
|
||||
|
||||
c2r = baseR * ao2;
|
||||
c2g = baseG * ao2;
|
||||
c2b = baseB * ao2;
|
||||
|
||||
c3r = baseR * ao3;
|
||||
c3g = baseG * ao3;
|
||||
c3b = baseB * ao3;
|
||||
|
||||
c4r = baseR * ao4;
|
||||
c4g = baseG * ao4;
|
||||
c4b = baseB * ao4;
|
||||
|
||||
tc1 = tex2;
|
||||
tc2 = tex2;
|
||||
tc3 = tex2;
|
||||
tc4 = tex2;
|
||||
}
|
||||
|
||||
void TileRenderer::setShape(float x0, float y0, float z0, float x1, float y1,
|
||||
float z1) {
|
||||
if (!fixedShape) {
|
||||
@@ -4604,17 +4569,6 @@ bool TileRenderer::tesselateWaterInWorld(Tile* tt, int x, int y, int z) {
|
||||
float g = (col >> 8 & 0xff) / 255.0f;
|
||||
float b = (col & 0xff) / 255.0f;
|
||||
bool up = tt->shouldRenderFace(level, x, y + 1, z, 1);
|
||||
if (waterTopSkipMask) {
|
||||
int lx = x - xMin;
|
||||
int ly = y - yMin;
|
||||
int lz = z - zMin;
|
||||
if ((unsigned)lx < 16 && (unsigned)ly < 16 && (unsigned)lz < 16) {
|
||||
int idx = (ly << 8) | (lz << 4) | lx;
|
||||
if (waterTopSkipMask[idx]) {
|
||||
up = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool down = tt->shouldRenderFace(level, x, y - 1, z, 0);
|
||||
bool dirs[4];
|
||||
dirs[0] = tt->shouldRenderFace(level, x, y, z - 1, 2);
|
||||
@@ -4822,10 +4776,6 @@ bool TileRenderer::tesselateWaterInWorld(Tile* tt, int x, int y, int z) {
|
||||
return changed;
|
||||
}
|
||||
|
||||
float TileRenderer::getWaterHeightAt(int x, int y, int z, Material* m) {
|
||||
return getWaterHeight(x, y, z, m);
|
||||
}
|
||||
|
||||
float TileRenderer::getWaterHeight(int x, int y, int z, Material* m) {
|
||||
int count = 0;
|
||||
float h = 0;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -40,7 +39,6 @@ private:
|
||||
Icon* fixedTexture;
|
||||
bool xFlipTexture;
|
||||
bool noCulling;
|
||||
const uint8_t* waterTopSkipMask;
|
||||
|
||||
public:
|
||||
static bool fancy;
|
||||
@@ -83,10 +81,6 @@ public:
|
||||
void setFixedTexture(Icon* fixedTexture);
|
||||
void clearFixedTexture();
|
||||
bool hasFixedTexture();
|
||||
void setApplyAmbienceOcclusion(bool enabled);
|
||||
void setWaterTopSkipMask(const uint8_t* mask);
|
||||
void setGreedyAO(float baseR, float baseG, float baseB, float ao1,
|
||||
float ao2, float ao3, float ao4, int tex2);
|
||||
void setShape(float x0, float y0, float z0, float x1, float y1, float z1);
|
||||
void setShape(Tile* tt);
|
||||
void setFixedShape(float x0, float y0, float z0, float x1, float y1,
|
||||
@@ -194,7 +188,6 @@ public:
|
||||
|
||||
void tesselateRowTexture(Tile* tt, int data, float x, float y, float z);
|
||||
bool tesselateWaterInWorld(Tile* tt, int x, int y, int z);
|
||||
float getWaterHeightAt(int x, int y, int z, Material* m);
|
||||
|
||||
private:
|
||||
float getWaterHeight(int x, int y, int z, Material* m);
|
||||
|
||||
@@ -99,7 +99,7 @@ void PendingConnection::sendPreLoginResponse() {
|
||||
std::uint8_t ugcXuidCount = 0;
|
||||
std::uint8_t hostIndex = 0;
|
||||
std::uint8_t ugcFriendsOnlyBits = 0;
|
||||
char szUniqueMapName[14];
|
||||
char szUniqueMapName[256]{};
|
||||
|
||||
StorageManager.GetSaveUniqueFilename(szUniqueMapName);
|
||||
|
||||
@@ -241,4 +241,4 @@ std::wstring PendingConnection::getName() {
|
||||
|
||||
bool PendingConnection::isServerPacketListener() { return true; }
|
||||
|
||||
bool PendingConnection::isDisconnected() { return done; }
|
||||
bool PendingConnection::isDisconnected() { return done; }
|
||||
|
||||
@@ -216,11 +216,13 @@ void ConsoleSaveFileSplit::RegionFileReference::Decompress() {
|
||||
unsigned char* dataIn = dataCompressed + 4;
|
||||
unsigned char* dataInLast = dataCompressed + dataCompressedSize;
|
||||
|
||||
while (dataIn != dataInLast) {
|
||||
while (dataIn < dataInLast) {
|
||||
unsigned char thisByte = *dataIn++;
|
||||
if (thisByte == 0) {
|
||||
if (dataIn >= dataInLast) break;
|
||||
thisByte = *dataIn++;
|
||||
if (thisByte == 0) {
|
||||
if (dataIn + 1 >= dataInLast) break;
|
||||
unsigned int runLength = (*dataIn++) << 8;
|
||||
runLength |= (*dataIn++);
|
||||
runLength += 256;
|
||||
@@ -237,7 +239,6 @@ void ConsoleSaveFileSplit::RegionFileReference::Decompress() {
|
||||
if (fileEntry->data.length != uncompressedSize) {
|
||||
// Treat as if it was an empty region file
|
||||
fileEntry->data.length = 0;
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -246,21 +247,24 @@ void ConsoleSaveFileSplit::RegionFileReference::Decompress() {
|
||||
unsigned char* dataIn = dataCompressed + 4;
|
||||
unsigned char* dataInLast = dataCompressed + dataCompressedSize;
|
||||
unsigned char* dataOut = data;
|
||||
unsigned char* dataOutLast = data + fileEntry->data.length;
|
||||
|
||||
while (dataIn != dataInLast) {
|
||||
while (dataIn < dataInLast && dataOut < dataOutLast) {
|
||||
unsigned char thisByte = *dataIn++;
|
||||
if (thisByte == 0) {
|
||||
if (dataIn >= dataInLast) break;
|
||||
thisByte = *dataIn++;
|
||||
if (thisByte == 0) {
|
||||
if (dataIn + 1 >= dataInLast) break;
|
||||
unsigned int runLength = (*dataIn++) << 8;
|
||||
runLength |= (*dataIn++);
|
||||
runLength += 256;
|
||||
for (unsigned int i = 0; i < runLength; i++) {
|
||||
for (unsigned int i = 0; i < runLength && dataOut < dataOutLast; i++) {
|
||||
*dataOut++ = 0;
|
||||
}
|
||||
} else {
|
||||
unsigned int runLength = thisByte;
|
||||
for (unsigned int i = 0; i < runLength; i++) {
|
||||
for (unsigned int i = 0; i < runLength && dataOut < dataOutLast; i++) {
|
||||
*dataOut++ = 0;
|
||||
}
|
||||
}
|
||||
@@ -274,7 +278,6 @@ void ConsoleSaveFileSplit::RegionFileReference::Decompress() {
|
||||
free(data);
|
||||
fileEntry->data.length = 0;
|
||||
data = nullptr;
|
||||
assert(0);
|
||||
}
|
||||
// std::int64_t endTime = System::currentTimeMillis();
|
||||
// app.DebugPrintf("Decompressing region file from 0x%.8x %d to %d bytes -
|
||||
@@ -437,6 +440,7 @@ void ConsoleSaveFileSplit::_init(const std::wstring& fileName, void* pvSaveData,
|
||||
// Get details of region files. From this point on we are responsible for
|
||||
// the memory that the storage manager initially allocated for them
|
||||
unsigned int regionCount = PlatformStorage.GetSubfileCount();
|
||||
|
||||
for (unsigned int i = 0; i < regionCount; i++) {
|
||||
unsigned int regionIndex;
|
||||
unsigned char* regionDataCompressed;
|
||||
@@ -446,8 +450,14 @@ void ConsoleSaveFileSplit::_init(const std::wstring& fileName, void* pvSaveData,
|
||||
(void**)®ionDataCompressed,
|
||||
®ionSizeCompressed);
|
||||
|
||||
unsigned char* copiedData = nullptr;
|
||||
if (regionSizeCompressed > 0 && regionDataCompressed) {
|
||||
copiedData = (unsigned char*)malloc(regionSizeCompressed);
|
||||
memcpy(copiedData, regionDataCompressed, regionSizeCompressed);
|
||||
}
|
||||
|
||||
RegionFileReference* regionFileRef = new RegionFileReference(
|
||||
i, regionIndex, regionSizeCompressed, regionDataCompressed);
|
||||
regionIndex, regionIndex, regionSizeCompressed, copiedData);
|
||||
if (regionSizeCompressed > 0) {
|
||||
regionFileRef->Decompress();
|
||||
} else {
|
||||
@@ -493,10 +503,12 @@ void ConsoleSaveFileSplit::_init(const std::wstring& fileName, void* pvSaveData,
|
||||
PlatformStorage.GetSaveData(pvSaveMem, &storageLength);
|
||||
app.DebugPrintf("Filesize - %d, Adjusted size - %d\n", fileSize,
|
||||
storageLength);
|
||||
|
||||
fileSize = storageLength;
|
||||
}
|
||||
|
||||
int compressed = *(int*)pvSaveMem;
|
||||
|
||||
if (compressed == 0) {
|
||||
unsigned int decompSize = *((int*)pvSaveMem + 1);
|
||||
|
||||
@@ -1288,6 +1300,7 @@ void ConsoleSaveFileSplit::Flush(bool autosave, bool updateThumbnail) {
|
||||
|
||||
unsigned int fileSize = header.GetFileSize();
|
||||
|
||||
|
||||
// Assume that the compression will make it smaller so initially attempt to
|
||||
// allocate the current file size We add 4 bytes to the start so that we can
|
||||
// signal compressed data And another 4 bytes to store the decompressed data
|
||||
|
||||
@@ -203,6 +203,7 @@ void FileHeader::ReadHeader(
|
||||
// based PlayerUID
|
||||
// : Bumped it to 8 for Durango v1 when to save the chunks in a
|
||||
// different compressed format
|
||||
case SAVE_FILE_VERSION_CHUNK_INHABITED_TIME:
|
||||
case SAVE_FILE_VERSION_COMPRESSED_CHUNK_STORAGE:
|
||||
case SAVE_FILE_VERSION_DURANGO_CHANGE_MAP_DATA_MAPPING_SIZE:
|
||||
case SAVE_FILE_VERSION_CHANGE_MAP_DATA_MAPPING_SIZE:
|
||||
|
||||
@@ -11,7 +11,6 @@ public:
|
||||
VERTEX_TYPE_COMPRESSED,
|
||||
VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_LIT,
|
||||
VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_TEXGEN,
|
||||
VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_TILEUV,
|
||||
VERTEX_TYPE_COUNT
|
||||
};
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
platform_inc = include_directories('.')
|
||||
_threads = dependency('threads')
|
||||
|
||||
lib_platform_core = static_library('platform_core',
|
||||
files('C4JThread.cpp', 'ShutdownManager.cpp'),
|
||||
include_directories: [platform_inc, include_directories('..')],
|
||||
dependencies: [_threads],
|
||||
cpp_args: global_cpp_args + global_cpp_defs,
|
||||
lib_platform_core = static_library(
|
||||
'platform_core',
|
||||
files('C4JThread.cpp', 'ShutdownManager.cpp'),
|
||||
include_directories: [platform_inc, include_directories('..')],
|
||||
dependencies: [_threads],
|
||||
cpp_args: global_cpp_args + global_cpp_defs,
|
||||
)
|
||||
|
||||
platform_dep = declare_dependency(
|
||||
link_with: lib_platform_core,
|
||||
include_directories: platform_inc,
|
||||
link_with: lib_platform_core,
|
||||
include_directories: platform_inc,
|
||||
)
|
||||
|
||||
# SDL2-based platform implementations (formerly 4J.* modules)
|
||||
@@ -18,34 +19,35 @@ _sdl2 = dependency('sdl2')
|
||||
_defs = []
|
||||
|
||||
if get_option('renderer') == 'gles'
|
||||
_gl = dependency('glesv2', required: true)
|
||||
_defs += ['-DGLES']
|
||||
_gl = dependency('glesv2', required: true)
|
||||
_defs += ['-DGLES']
|
||||
else
|
||||
_gl = dependency('gl', required: true)
|
||||
_gl = dependency('gl', required: true)
|
||||
endif
|
||||
|
||||
sdl2_sources = files(
|
||||
'sdl2/Input.cpp',
|
||||
'sdl2/Profile.cpp',
|
||||
'sdl2/Render.cpp',
|
||||
'sdl2/render_stubs.cpp',
|
||||
'sdl2/Storage.cpp',
|
||||
'sdl2/Input.cpp',
|
||||
'sdl2/Profile.cpp',
|
||||
'sdl2/Render.cpp',
|
||||
'sdl2/Storage.cpp',
|
||||
'sdl2/render_stubs.cpp',
|
||||
)
|
||||
|
||||
lib_platform_sdl2 = static_library('platform_sdl2',
|
||||
sdl2_sources,
|
||||
include_directories: [platform_inc, include_directories('sdl2')],
|
||||
dependencies: [_sdl2, _gl, _threads, glm_dep, stb_dep],
|
||||
cpp_args: _defs + global_cpp_args + global_cpp_defs,
|
||||
lib_platform_sdl2 = static_library(
|
||||
'platform_sdl2',
|
||||
sdl2_sources,
|
||||
include_directories: [platform_inc, include_directories('sdl2')],
|
||||
dependencies: [_sdl2, _gl, _threads, glm_dep, stb_dep, java_dep],
|
||||
cpp_args: _defs + global_cpp_args + global_cpp_defs,
|
||||
)
|
||||
|
||||
# Combined dependency: interfaces + SDL2 implementations
|
||||
# Replaces the old render_dep, input_dep, profile_dep, storage_dep
|
||||
render_dep = declare_dependency(
|
||||
link_with: lib_platform_sdl2,
|
||||
include_directories: [platform_inc, include_directories('sdl2')],
|
||||
dependencies: [_sdl2, _gl, _threads, glm_dep],
|
||||
link_with: lib_platform_sdl2,
|
||||
include_directories: [platform_inc, include_directories('sdl2')],
|
||||
dependencies: [_sdl2, _gl, _threads, glm_dep],
|
||||
)
|
||||
input_dep = render_dep
|
||||
profile_dep = render_dep
|
||||
storage_dep = render_dep
|
||||
storage_dep = render_dep
|
||||
@@ -196,7 +196,8 @@ struct ShaderUniforms {
|
||||
GLint uFogDensity = -1, uFogColor = -1, uFogEnable = -1;
|
||||
GLint uLMTransform = -1, uUseLightmap = -1, uAlphaRef = -1;
|
||||
GLint uTex0 = -1, uTex1 = -1, uGlobalLM = -1;
|
||||
GLint uUseTexture = -1, uUseTileUV = -1, uInvGamma = -1;
|
||||
GLint uUseTexture = -1;
|
||||
GLint uInvGamma = -1;
|
||||
GLint uChunkOffset = -1;
|
||||
|
||||
void build(const char* vs, const char* fs) {
|
||||
@@ -232,7 +233,6 @@ struct ShaderUniforms {
|
||||
L(uTex1);
|
||||
L(uGlobalLM);
|
||||
L(uUseTexture);
|
||||
L(uUseTileUV);
|
||||
L(uInvGamma);
|
||||
L(uChunkOffset);
|
||||
#undef L
|
||||
@@ -380,8 +380,8 @@ static void glShadowSetDepthTest(bool e) {
|
||||
}
|
||||
|
||||
static void glShadowSetBlendFunc(GLint s, GLint d) {
|
||||
if (!(s_gl_shadow_mask & SHADOW_BLEND_FUNC) || s_gl_state.blendSrc != s ||
|
||||
s_gl_state.blendDst != d) {
|
||||
if (!(s_gl_shadow_mask & SHADOW_BLEND_FUNC) ||
|
||||
s_gl_state.blendSrc != s || s_gl_state.blendDst != d) {
|
||||
::glBlendFunc(s, d);
|
||||
s_gl_state.blendSrc = s;
|
||||
s_gl_state.blendDst = d;
|
||||
@@ -390,7 +390,8 @@ static void glShadowSetBlendFunc(GLint s, GLint d) {
|
||||
}
|
||||
|
||||
static void glShadowSetDepthMask(GLboolean e) {
|
||||
if (!(s_gl_shadow_mask & SHADOW_DEPTH_MASK) || s_gl_state.depthMask != e) {
|
||||
if (!(s_gl_shadow_mask & SHADOW_DEPTH_MASK) ||
|
||||
s_gl_state.depthMask != e) {
|
||||
::glDepthMask(e);
|
||||
s_gl_state.depthMask = e;
|
||||
s_gl_shadow_mask |= SHADOW_DEPTH_MASK;
|
||||
@@ -501,7 +502,8 @@ static void pushRenderState() {
|
||||
glUniform1f(s_shader.uFogStart, s_rs.fogStart);
|
||||
glUniform1f(s_shader.uFogEnd, s_rs.fogEnd);
|
||||
glUniform1f(s_shader.uFogDensity, s_rs.fogDensity);
|
||||
glUniform4fv(s_shader.uFogColor, 1, glm::value_ptr(s_rs.fogColor));
|
||||
glUniform4fv(s_shader.uFogColor, 1,
|
||||
glm::value_ptr(s_rs.fogColor));
|
||||
glUniform1i(s_shader.uFogEnable, s_rs.fogEnable ? 1 : 0);
|
||||
}
|
||||
if (s_rs_dirty_mask & DIRTY_TEXTURE) {
|
||||
@@ -513,9 +515,11 @@ static void pushRenderState() {
|
||||
if (s_rs_dirty_mask & DIRTY_GAMMA)
|
||||
glUniform1f(s_shader.uInvGamma, 1.0f / s_rs.gamma);
|
||||
if (s_rs_dirty_mask & DIRTY_LMT)
|
||||
glUniform4fv(s_shader.uLMTransform, 1, glm::value_ptr(s_rs.lmt));
|
||||
glUniform4fv(s_shader.uLMTransform, 1,
|
||||
glm::value_ptr(s_rs.lmt));
|
||||
if (s_rs_dirty_mask & DIRTY_GLOBAL_LM)
|
||||
glUniform2fv(s_shader.uGlobalLM, 1, glm::value_ptr(s_rs.globalLM));
|
||||
glUniform2fv(s_shader.uGlobalLM, 1,
|
||||
glm::value_ptr(s_rs.globalLM));
|
||||
s_rs_dirty_mask = 0;
|
||||
}
|
||||
flushMatrices();
|
||||
@@ -552,7 +556,6 @@ struct ChunkDrawCall {
|
||||
GLenum prim;
|
||||
GLint first;
|
||||
GLsizei count;
|
||||
bool useTileUV;
|
||||
};
|
||||
|
||||
struct ChunkBuffer {
|
||||
@@ -890,17 +893,13 @@ void C4JRender::DrawVertices(ePrimitiveType ptype, int count, void* dataIn,
|
||||
int first = (int)(s_recVerts.size() / stride);
|
||||
s_recVerts.insert(s_recVerts.end(), (const uint8_t*)dataIn,
|
||||
(const uint8_t*)dataIn + bytes);
|
||||
bool useTileUV = (vType == VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_TILEUV);
|
||||
s_recDraws.push_back({glMode, first, (GLsizei)count, useTileUV});
|
||||
s_recDraws.push_back({glMode, first, (GLsizei)count});
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&s_glCallMtx);
|
||||
pushRenderState();
|
||||
|
||||
glUniform1i(s_shader.uUseTileUV,
|
||||
(vType == VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_TILEUV) ? 1 : 0);
|
||||
|
||||
glBindVertexArray(s_sVAO_std);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_sVBO_std);
|
||||
|
||||
@@ -1020,10 +1019,7 @@ bool C4JRender::CBuffCall(int index, bool) {
|
||||
pushRenderState();
|
||||
|
||||
glBindVertexArray(cb.vao);
|
||||
for (const auto& dc : cb.draws) {
|
||||
glUniform1i(s_shader.uUseTileUV, dc.useTileUV ? 1 : 0);
|
||||
glDrawArrays(dc.prim, dc.first, dc.count);
|
||||
}
|
||||
for (const auto& dc : cb.draws) glDrawArrays(dc.prim, dc.first, dc.count);
|
||||
glBindVertexArray(0);
|
||||
|
||||
pthread_mutex_unlock(&s_glCallMtx);
|
||||
@@ -1099,7 +1095,7 @@ void C4JRender::Set_matrixDirty() {
|
||||
s_boundProgram = 0;
|
||||
s_rs_dirty_mask = 0xFFFFFFFF;
|
||||
s_gl_shadow_mask = 0;
|
||||
s_normalMatDirty = true; // normal matrix dirt after iggy reset
|
||||
s_normalMatDirty = true; // normal matrix dirt after iggy reset
|
||||
s_matDirty = true;
|
||||
s_chunkOffsetValid = false;
|
||||
if (s_shader.prog) {
|
||||
@@ -1136,7 +1132,9 @@ void C4JRender::StateSetDepthMask(bool e) {
|
||||
glShadowSetDepthMask(e ? GL_TRUE : GL_FALSE);
|
||||
}
|
||||
void C4JRender::StateSetBlendEnable(bool e) { glShadowSetBlend(e); }
|
||||
void C4JRender::StateSetBlendFunc(int s, int d) { glShadowSetBlendFunc(s, d); }
|
||||
void C4JRender::StateSetBlendFunc(int s, int d) {
|
||||
glShadowSetBlendFunc(s, d);
|
||||
}
|
||||
void C4JRender::StateSetDepthFunc(int f) { ::glDepthFunc(f); }
|
||||
void C4JRender::StateSetFaceCull(bool e) { glShadowSetCull(e); }
|
||||
void C4JRender::StateSetFaceCullCW(bool e) {
|
||||
@@ -1183,10 +1181,7 @@ void C4JRender::StateSetFogEnable(bool e) {
|
||||
}
|
||||
}
|
||||
void C4JRender::StateSetFogMode(int mode) {
|
||||
int v = (mode == GL_LINEAR) ? 1
|
||||
: (mode == GL_EXP) ? 2
|
||||
: (mode == 0x0801) ? 3
|
||||
: 0;
|
||||
int v = (mode == GL_LINEAR) ? 1 : (mode == GL_EXP) ? 2 : (mode == 0x0801) ? 3 : 0;
|
||||
if (s_rs.fogMode != v) {
|
||||
s_rs.fogMode = v;
|
||||
markDirty(DIRTY_FOG);
|
||||
@@ -1308,9 +1303,9 @@ void C4JRender::TextureBindVertex(int idx, bool scaleLight) {
|
||||
s_rs.useLightmap = true;
|
||||
markDirty(DIRTY_TEXTURE);
|
||||
}
|
||||
glm::vec4 newLmt = scaleLight
|
||||
? glm::vec4{1.f, 1.f, 8.f / 256.f, 8.f / 256.f}
|
||||
: glm::vec4{1.f, 1.f, 0.f, 0.f};
|
||||
glm::vec4 newLmt =
|
||||
scaleLight ? glm::vec4{1.f, 1.f, 8.f / 256.f, 8.f / 256.f}
|
||||
: glm::vec4{1.f, 1.f, 0.f, 0.f};
|
||||
if (s_rs.lmt != newLmt) {
|
||||
s_rs.lmt = newLmt;
|
||||
markDirty(DIRTY_LMT);
|
||||
|
||||
@@ -1,16 +1,59 @@
|
||||
#include "Storage.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "StdFileIO.h"
|
||||
|
||||
C4JStorage StorageManager;
|
||||
|
||||
static XMARKETPLACE_CONTENTOFFER_INFO s_dummyOffer = {};
|
||||
static XCONTENT_DATA s_dummyContentData = {};
|
||||
|
||||
// def save state
|
||||
// TODO: find a better way
|
||||
static SAVE_DETAILS* s_SavesInfo = nullptr;
|
||||
static std::wstring s_CurrentSaveTitle = L"New World";
|
||||
static std::string s_CurrentSaveFilename = "";
|
||||
static bool s_SaveDisabled = false;
|
||||
|
||||
// Console VFS Memory Blob
|
||||
static std::uint8_t* s_SaveBuffer = nullptr;
|
||||
static unsigned int s_SaveBufferSize = 0;
|
||||
|
||||
struct SubfileData {
|
||||
std::vector<std::uint8_t> data;
|
||||
};
|
||||
|
||||
#include <mutex>
|
||||
static std::map<int, SubfileData> s_Subfiles;
|
||||
static int s_SubfileCounter = 0;
|
||||
static std::mutex s_SubfileMutex;
|
||||
|
||||
// helper functions
|
||||
static StdFileIO s_FileIO;
|
||||
|
||||
static std::filesystem::path GetSavesRoot() {
|
||||
return s_FileIO.getUserDataPath() / "Saves";
|
||||
}
|
||||
|
||||
static std::filesystem::path GetSaveDir(const std::string& saveFilename) {
|
||||
return GetSavesRoot() / saveFilename;
|
||||
}
|
||||
|
||||
static std::filesystem::path GetSaveFile(const std::string& saveFilename,
|
||||
const std::string& filename) {
|
||||
return GetSaveDir(saveFilename) / filename;
|
||||
}
|
||||
C4JStorage::C4JStorage() : m_pStringTable(nullptr) {}
|
||||
|
||||
void C4JStorage::Tick(void) {}
|
||||
@@ -21,6 +64,7 @@ C4JStorage::EMessageResult C4JStorage::RequestMessageBox(
|
||||
std::function<int(int, const C4JStorage::EMessageResult)> callback,
|
||||
C4JStringTable* pStringTable, wchar_t* pwchFormatString,
|
||||
unsigned int focusButton) {
|
||||
if (callback) callback(pad, EMessage_ResultAccept);
|
||||
return EMessage_ResultAccept;
|
||||
}
|
||||
|
||||
@@ -30,6 +74,7 @@ C4JStorage::EMessageResult C4JStorage::GetMessageBoxResult() {
|
||||
|
||||
bool C4JStorage::SetSaveDevice(std::function<int(const bool)> callback,
|
||||
bool bForceResetOfSaveDevice) {
|
||||
if (callback) callback(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -37,48 +82,130 @@ void C4JStorage::Init(unsigned int uiSaveVersion,
|
||||
const wchar_t* pwchDefaultSaveName, char* pszSavePackName,
|
||||
int iMinimumSaveSize,
|
||||
std::function<int(const ESavingMessage, int)> callback,
|
||||
const char* szGroupID) {}
|
||||
void C4JStorage::ResetSaveData() {}
|
||||
const char* szGroupID) {
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(GetSavesRoot(), ec);
|
||||
}
|
||||
|
||||
void C4JStorage::ResetSaveData() {
|
||||
s_CurrentSaveTitle = L"New World";
|
||||
s_CurrentSaveFilename = "";
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_SubfileMutex);
|
||||
s_Subfiles.clear();
|
||||
s_SubfileCounter = 0;
|
||||
}
|
||||
if (s_SaveBuffer) {
|
||||
free(s_SaveBuffer);
|
||||
s_SaveBuffer = nullptr;
|
||||
}
|
||||
s_SaveBufferSize = 0;
|
||||
}
|
||||
|
||||
void C4JStorage::SetDefaultSaveNameForKeyboardDisplay(
|
||||
const wchar_t* pwchDefaultSaveName) {}
|
||||
void C4JStorage::SetSaveTitle(const wchar_t* pwchDefaultSaveName) {}
|
||||
const wchar_t* pwchDefaultSaveName) {
|
||||
if (pwchDefaultSaveName) s_CurrentSaveTitle = pwchDefaultSaveName;
|
||||
}
|
||||
|
||||
void C4JStorage::SetSaveTitle(const wchar_t* pwchDefaultSaveName) {
|
||||
if (pwchDefaultSaveName) s_CurrentSaveTitle = pwchDefaultSaveName;
|
||||
|
||||
if (s_CurrentSaveFilename.empty()) {
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "sv%06X",
|
||||
(unsigned int)(time(NULL) & 0xFFFFFF));
|
||||
s_CurrentSaveFilename = buf;
|
||||
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(GetSaveDir(s_CurrentSaveFilename),
|
||||
ec);
|
||||
}
|
||||
}
|
||||
|
||||
bool C4JStorage::GetSaveUniqueNumber(int* piVal) {
|
||||
if (piVal) *piVal = 0;
|
||||
if (piVal) *piVal = 1; // she turned a 0 to a 1 now the world explodes
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C4JStorage::GetSaveUniqueFilename(char* pszName) {
|
||||
if (pszName) pszName[0] = '\0';
|
||||
if (pszName) {
|
||||
strncpy(pszName, s_CurrentSaveFilename.c_str(),
|
||||
MAX_SAVEFILENAME_LENGTH - 1);
|
||||
pszName[MAX_SAVEFILENAME_LENGTH - 1] = '\0';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void C4JStorage::SetSaveUniqueFilename(char* szFilename) {}
|
||||
void C4JStorage::SetSaveUniqueFilename(char* szFilename) {
|
||||
if (szFilename) s_CurrentSaveFilename = szFilename;
|
||||
}
|
||||
void C4JStorage::SetState(ESaveGameControlState eControlState,
|
||||
std::function<int(const bool)> callback) {}
|
||||
void C4JStorage::SetSaveDisabled(bool bDisable) {}
|
||||
bool C4JStorage::GetSaveDisabled(void) { return false; }
|
||||
unsigned int C4JStorage::GetSaveSize() { return 0; }
|
||||
void C4JStorage::GetSaveData(void* pvData, unsigned int* puiBytes) {
|
||||
if (puiBytes) *puiBytes = 0;
|
||||
std::function<int(const bool)> callback) {
|
||||
if (callback) callback(true);
|
||||
}
|
||||
void C4JStorage::SetSaveDisabled(bool bDisable) { s_SaveDisabled = bDisable; }
|
||||
bool C4JStorage::GetSaveDisabled(void) { return s_SaveDisabled; }
|
||||
void* C4JStorage::AllocateSaveData(unsigned int uiBytes) {
|
||||
return malloc(uiBytes);
|
||||
if (s_SaveBuffer) free(s_SaveBuffer);
|
||||
s_SaveBuffer = (std::uint8_t*)malloc(uiBytes);
|
||||
s_SaveBufferSize = uiBytes;
|
||||
return s_SaveBuffer;
|
||||
}
|
||||
void C4JStorage::GetSaveData(void* pvData, unsigned int* puiBytes) {
|
||||
if (puiBytes) *puiBytes = s_SaveBufferSize;
|
||||
if (pvData && s_SaveBuffer) memcpy(pvData, s_SaveBuffer, s_SaveBufferSize);
|
||||
}
|
||||
unsigned int C4JStorage::GetSaveSize() { return s_SaveBufferSize; }
|
||||
void C4JStorage::SetSaveImages(std::uint8_t* pbThumbnail,
|
||||
unsigned int thumbnailBytes,
|
||||
std::uint8_t* pbImage, unsigned int imageBytes,
|
||||
std::uint8_t* pbTextData,
|
||||
unsigned int textDataBytes) {}
|
||||
unsigned int textDataBytes) {
|
||||
if (pbThumbnail && thumbnailBytes > 0 && !s_CurrentSaveFilename.empty()) {
|
||||
auto dir = GetSaveDir(s_CurrentSaveFilename);
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(dir, ec);
|
||||
s_FileIO.writeFile(dir / "thumbnail.png", pbThumbnail, thumbnailBytes);
|
||||
}
|
||||
}
|
||||
|
||||
C4JStorage::ESaveGameState C4JStorage::SaveSaveData(
|
||||
std::function<int(const bool)> callback) {
|
||||
return ESaveGame_Idle;
|
||||
if (s_CurrentSaveFilename.empty()) {
|
||||
if (callback) callback(false);
|
||||
return ESaveGame_Idle;
|
||||
}
|
||||
|
||||
auto dir = GetSaveDir(s_CurrentSaveFilename);
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(dir, ec);
|
||||
|
||||
// vfs blob -> disk
|
||||
if (s_SaveBuffer && s_SaveBufferSize > 0)
|
||||
s_FileIO.writeFile(dir / "savegame.dat", s_SaveBuffer,
|
||||
s_SaveBufferSize);
|
||||
|
||||
// save... title.. in txt... they do that.. honestly
|
||||
// i would wrap world info in a json.
|
||||
// but i'm not rewriting the whole
|
||||
// save -> storage system sooooooo nope!
|
||||
std::string titleStr(s_CurrentSaveTitle.begin(), s_CurrentSaveTitle.end());
|
||||
s_FileIO.writeFile(dir / "title.txt", titleStr.data(), titleStr.size());
|
||||
|
||||
if (callback) callback(true);
|
||||
return ESaveGame_Save;
|
||||
}
|
||||
void C4JStorage::CopySaveDataToNewSave(std::uint8_t* pbThumbnail,
|
||||
unsigned int cbThumbnail,
|
||||
wchar_t* wchNewName,
|
||||
std::function<int(bool)> callback) {}
|
||||
std::function<int(bool)> callback) {
|
||||
if (callback) callback(false);
|
||||
}
|
||||
|
||||
void C4JStorage::SetSaveDeviceSelected(unsigned int uiPad, bool bSelected) {}
|
||||
bool C4JStorage::GetSaveDeviceSelected(unsigned int iPad) { return true; }
|
||||
C4JStorage::ESaveGameState C4JStorage::DoesSaveExist(bool* pbExists) {
|
||||
if (pbExists) *pbExists = false;
|
||||
if (pbExists)
|
||||
*pbExists = s_FileIO.exists(GetSaveDir(s_CurrentSaveFilename));
|
||||
return ESaveGame_Idle;
|
||||
}
|
||||
bool C4JStorage::EnoughSpaceForAMinSaveGame() { return true; }
|
||||
@@ -87,16 +214,87 @@ C4JStorage::ESaveGameState C4JStorage::GetSavesInfo(
|
||||
int iPad,
|
||||
std::function<int(SAVE_DETAILS* pSaveDetails, const bool)> callback,
|
||||
char* pszSavePackName) {
|
||||
ClearSavesInfo();
|
||||
|
||||
auto savesRoot = GetSavesRoot();
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(savesRoot, ec);
|
||||
|
||||
std::vector<std::string> saveDirs;
|
||||
|
||||
for (const auto& entry :
|
||||
std::filesystem::directory_iterator(savesRoot, ec)) {
|
||||
if (!entry.is_directory()) continue;
|
||||
|
||||
std::string name = entry.path().filename().string();
|
||||
bool hasSave = s_FileIO.exists(entry.path() / "savegame.dat") ||
|
||||
s_FileIO.exists(entry.path() / "subfile_0.dat") ||
|
||||
s_FileIO.exists(entry.path() / "title.txt");
|
||||
|
||||
if (hasSave) saveDirs.push_back(name);
|
||||
}
|
||||
|
||||
s_SavesInfo = new SAVE_DETAILS();
|
||||
s_SavesInfo->iSaveC = (int)saveDirs.size();
|
||||
|
||||
if (s_SavesInfo->iSaveC > 0) {
|
||||
s_SavesInfo->SaveInfoA = new SAVE_INFO[s_SavesInfo->iSaveC];
|
||||
for (size_t i = 0; i < saveDirs.size(); ++i) {
|
||||
SAVE_INFO& info = s_SavesInfo->SaveInfoA[i];
|
||||
memset(&info, 0, sizeof(SAVE_INFO));
|
||||
|
||||
strncpy(info.UTF8SaveFilename, saveDirs[i].c_str(),
|
||||
MAX_SAVEFILENAME_LENGTH - 1);
|
||||
|
||||
auto titleData =
|
||||
s_FileIO.readFileToVec(GetSaveFile(saveDirs[i], "title.txt"));
|
||||
if (!titleData.empty()) {
|
||||
std::string title(titleData.begin(), titleData.end());
|
||||
strncpy(info.UTF8SaveTitle, title.c_str(),
|
||||
MAX_DISPLAYNAME_LENGTH - 1);
|
||||
} else {
|
||||
strncpy(info.UTF8SaveTitle, saveDirs[i].c_str(),
|
||||
MAX_DISPLAYNAME_LENGTH - 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
s_SavesInfo->SaveInfoA = nullptr;
|
||||
}
|
||||
|
||||
if (callback) callback(s_SavesInfo, true);
|
||||
return ESaveGame_Idle;
|
||||
}
|
||||
PSAVE_DETAILS C4JStorage::ReturnSavesInfo() { return nullptr; }
|
||||
void C4JStorage::ClearSavesInfo() {}
|
||||
|
||||
PSAVE_DETAILS C4JStorage::ReturnSavesInfo() { return s_SavesInfo; }
|
||||
|
||||
void C4JStorage::ClearSavesInfo() {
|
||||
if (s_SavesInfo) {
|
||||
if (s_SavesInfo->SaveInfoA) {
|
||||
for (int i = 0; i < s_SavesInfo->iSaveC; ++i) {
|
||||
if (s_SavesInfo->SaveInfoA[i].thumbnailData)
|
||||
delete[] s_SavesInfo->SaveInfoA[i].thumbnailData;
|
||||
}
|
||||
delete[] s_SavesInfo->SaveInfoA;
|
||||
}
|
||||
delete s_SavesInfo;
|
||||
s_SavesInfo = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
C4JStorage::ESaveGameState C4JStorage::LoadSaveDataThumbnail(
|
||||
PSAVE_INFO pSaveInfo,
|
||||
std::function<int(std::uint8_t* thumbnailData,
|
||||
unsigned int thumbnailBytes)>
|
||||
std::function<int(std::uint8_t* thumbnailData, unsigned int thumbnailBytes)>
|
||||
callback) {
|
||||
return ESaveGame_Idle;
|
||||
if (pSaveInfo) {
|
||||
auto data = s_FileIO.readFileToVec(
|
||||
GetSaveFile(pSaveInfo->UTF8SaveFilename, "thumbnail.png"));
|
||||
if (!data.empty()) {
|
||||
if (callback) callback(data.data(), (unsigned int)data.size());
|
||||
return (C4JStorage::ESaveGameState)4;
|
||||
}
|
||||
}
|
||||
if (callback) callback(nullptr, 0);
|
||||
return (C4JStorage::ESaveGameState)4;
|
||||
}
|
||||
void C4JStorage::GetSaveCacheFileInfo(unsigned int fileIndex,
|
||||
XCONTENT_DATA& xContentData) {
|
||||
@@ -109,14 +307,63 @@ void C4JStorage::GetSaveCacheFileInfo(unsigned int fileIndex,
|
||||
if (pImageBytes) *pImageBytes = 0;
|
||||
}
|
||||
C4JStorage::ESaveGameState C4JStorage::LoadSaveData(
|
||||
PSAVE_INFO pSaveInfo,
|
||||
std::function<int(const bool, const bool)> callback) {
|
||||
return ESaveGame_Idle;
|
||||
PSAVE_INFO pSaveInfo, std::function<int(const bool, const bool)> callback) {
|
||||
if (pSaveInfo) {
|
||||
s_CurrentSaveFilename = pSaveInfo->UTF8SaveFilename;
|
||||
std::string title(pSaveInfo->UTF8SaveTitle);
|
||||
s_CurrentSaveTitle = std::wstring(title.begin(), title.end());
|
||||
|
||||
auto blobData = s_FileIO.readFileToVec(
|
||||
GetSaveFile(s_CurrentSaveFilename, "savegame.dat"));
|
||||
if (!blobData.empty()) {
|
||||
if (s_SaveBuffer) free(s_SaveBuffer);
|
||||
s_SaveBufferSize = (unsigned int)blobData.size();
|
||||
s_SaveBuffer = (std::uint8_t*)malloc(s_SaveBufferSize);
|
||||
memcpy(s_SaveBuffer, blobData.data(), s_SaveBufferSize);
|
||||
|
||||
}
|
||||
|
||||
// put in mem
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_SubfileMutex);
|
||||
s_Subfiles.clear();
|
||||
int maxIndex = -1;
|
||||
auto dir = GetSaveDir(s_CurrentSaveFilename);
|
||||
std::error_code ec;
|
||||
for (const auto& entry : std::filesystem::directory_iterator(dir, ec)) {
|
||||
if (!entry.is_regular_file()) continue;
|
||||
std::string filename = entry.path().filename().string();
|
||||
if (filename.find("subfile_") == 0 && filename.find(".dat") == filename.size() - 4) {
|
||||
try {
|
||||
int i = std::stoi(filename.substr(8, filename.size() - 12));
|
||||
auto subData = s_FileIO.readFileToVec(entry.path());
|
||||
if (!subData.empty()) {
|
||||
SubfileData sd;
|
||||
sd.data = std::move(subData);
|
||||
s_Subfiles[i] = std::move(sd);
|
||||
if (i > maxIndex) maxIndex = i;
|
||||
}
|
||||
} catch (...) {}
|
||||
}
|
||||
}
|
||||
s_SubfileCounter = maxIndex + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (callback) callback(false, true);
|
||||
return (C4JStorage::ESaveGameState)1;
|
||||
}
|
||||
C4JStorage::ESaveGameState C4JStorage::DeleteSaveData(
|
||||
PSAVE_INFO pSaveInfo,
|
||||
std::function<int(const bool)> callback) {
|
||||
return ESaveGame_Idle;
|
||||
PSAVE_INFO pSaveInfo, std::function<int(const bool)> callback) {
|
||||
bool success = false;
|
||||
if (pSaveInfo) {
|
||||
std::error_code ec;
|
||||
std::filesystem::remove_all(GetSaveDir(pSaveInfo->UTF8SaveFilename),
|
||||
ec);
|
||||
success = !ec;
|
||||
}
|
||||
if (callback) callback(success);
|
||||
return (C4JStorage::ESaveGameState)3;
|
||||
}
|
||||
void C4JStorage::RegisterMarketplaceCountsCallback(
|
||||
std::function<int(C4JStorage::DLC_TMS_DETAILS*, int)> callback) {}
|
||||
@@ -124,6 +371,7 @@ void C4JStorage::SetDLCPackageRoot(char* pszDLCRoot) {}
|
||||
C4JStorage::EDLCStatus C4JStorage::GetDLCOffers(
|
||||
int iPad, std::function<int(int, std::uint32_t, int)> callback,
|
||||
std::uint32_t dwOfferTypesBitmask) {
|
||||
if (callback) callback(0, dwOfferTypesBitmask, iPad);
|
||||
return EDLC_NoOffers;
|
||||
}
|
||||
unsigned int C4JStorage::CancelGetDLCOffers() { return 0; }
|
||||
@@ -190,32 +438,71 @@ unsigned int C4JStorage::CRC(unsigned char* buf, int len) {
|
||||
unsigned int crc = 0xFFFFFFFF;
|
||||
for (int i = 0; i < len; i++) {
|
||||
crc ^= buf[i];
|
||||
for (int j = 0; j < 8; j++) {
|
||||
for (int j = 0; j < 8; j++)
|
||||
crc = (crc >> 1) ^ (0xEDB88320 & (-(crc & 1)));
|
||||
}
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
// that fucking bird that i hate
|
||||
int C4JStorage::AddSubfile(int regionIndex) {
|
||||
(void)regionIndex;
|
||||
return 0;
|
||||
std::lock_guard<std::mutex> lock(s_SubfileMutex);
|
||||
s_Subfiles[regionIndex] = SubfileData();
|
||||
if (regionIndex >= s_SubfileCounter) {
|
||||
s_SubfileCounter = regionIndex + 1;
|
||||
}
|
||||
return regionIndex;
|
||||
}
|
||||
unsigned int C4JStorage::GetSubfileCount() { return 0; }
|
||||
|
||||
unsigned int C4JStorage::GetSubfileCount() {
|
||||
std::lock_guard<std::mutex> lock(s_SubfileMutex);
|
||||
return s_Subfiles.size();
|
||||
}
|
||||
|
||||
void C4JStorage::GetSubfileDetails(unsigned int i, int* regionIndex,
|
||||
void** data, unsigned int* size) {
|
||||
(void)i;
|
||||
if (regionIndex) *regionIndex = 0;
|
||||
if (data) *data = 0;
|
||||
if (size) *size = 0;
|
||||
std::lock_guard<std::mutex> lock(s_SubfileMutex);
|
||||
auto it = s_Subfiles.begin();
|
||||
unsigned int index = 0;
|
||||
while (it != s_Subfiles.end() && index < i) {
|
||||
++it;
|
||||
++index;
|
||||
}
|
||||
if (it != s_Subfiles.end()) {
|
||||
if (regionIndex) *regionIndex = it->first;
|
||||
if (data) *data = it->second.data.data();
|
||||
if (size) *size = (unsigned int)it->second.data.size();
|
||||
} else {
|
||||
if (regionIndex) *regionIndex = 0;
|
||||
if (data) *data = nullptr;
|
||||
if (size) *size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void C4JStorage::ResetSubfiles() {
|
||||
std::lock_guard<std::mutex> lock(s_SubfileMutex);
|
||||
s_Subfiles.clear();
|
||||
s_SubfileCounter = 0;
|
||||
}
|
||||
void C4JStorage::ResetSubfiles() {}
|
||||
void C4JStorage::UpdateSubfile(int index, void* data, unsigned int size) {
|
||||
(void)index;
|
||||
(void)data;
|
||||
(void)size;
|
||||
std::lock_guard<std::mutex> lock(s_SubfileMutex);
|
||||
SubfileData& sd = s_Subfiles[index]; // inserts if missing
|
||||
sd.data.resize(size);
|
||||
memcpy(sd.data.data(), data, size);
|
||||
}
|
||||
void C4JStorage::SaveSubfiles(std::function<int(const bool)> callback) {
|
||||
std::lock_guard<std::mutex> lock(s_SubfileMutex);
|
||||
if (!s_CurrentSaveFilename.empty() && !s_Subfiles.empty()) {
|
||||
auto dir = GetSaveDir(s_CurrentSaveFilename);
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(dir, ec);
|
||||
|
||||
for (const auto& pair : s_Subfiles) {
|
||||
s_FileIO.writeFile(
|
||||
dir / ("subfile_" + std::to_string(pair.first) + ".dat"),
|
||||
pair.second.data.data(), pair.second.data.size());
|
||||
}
|
||||
}
|
||||
if (callback) callback(true);
|
||||
}
|
||||
C4JStorage::ESaveGameState C4JStorage::GetSaveState() { return ESaveGame_Idle; }
|
||||
|
||||
@@ -1,113 +1,22 @@
|
||||
R "GLSL(
|
||||
R"GLSL(
|
||||
#version 330 core
|
||||
uniform sampler2D uTex0;
|
||||
uniform sampler2D uTex1;
|
||||
uniform int uUseTexture;
|
||||
uniform int uUseTileUV;
|
||||
uniform int uUseLightmap;
|
||||
uniform int uUseTexture;
|
||||
uniform int uUseLightmap;
|
||||
uniform float uAlphaRef;
|
||||
uniform vec4 uFogColor;
|
||||
uniform int uFogEnable;
|
||||
uniform vec4 uFogColor;
|
||||
uniform int uFogEnable;
|
||||
uniform float uInvGamma;
|
||||
|
||||
in vec2 vUV0;
|
||||
in vec2 vUV1;
|
||||
in vec4 vColor;
|
||||
in vec3 vWorldPos;
|
||||
in float vFogFactor;
|
||||
out vec4 oColor;
|
||||
in vec2 vUV0;
|
||||
in vec2 vUV1;
|
||||
in vec4 vColor;
|
||||
in float vFogFactor;
|
||||
out vec4 oColor;
|
||||
|
||||
void main() {
|
||||
vec2 uv = vUV0;
|
||||
vec2 dUVdx = vec2(0.0);
|
||||
vec2 dUVdy = vec2(0.0);
|
||||
bool useGrad = false;
|
||||
bool disableMipmap = false;
|
||||
|
||||
if (uUseTileUV != 0) {
|
||||
vec2 baseUV = vUV0;
|
||||
if (baseUV.x > 1.0) {
|
||||
baseUV.x -= 1.0;
|
||||
disableMipmap = true;
|
||||
}
|
||||
if (baseUV.y > 1.0) {
|
||||
baseUV.y -= 1.0;
|
||||
disableMipmap = true;
|
||||
}
|
||||
|
||||
vec2 atlasSize = vec2(textureSize(uTex0, 0));
|
||||
float tileSize = 16.0;
|
||||
vec2 cell = floor(baseUV * atlasSize / tileSize);
|
||||
vec2 uv0 = cell * tileSize / atlasSize;
|
||||
vec2 cellSize = vec2(tileSize) / atlasSize;
|
||||
|
||||
vec3 dpdx = dFdx(vWorldPos);
|
||||
vec3 dpdy = dFdy(vWorldPos);
|
||||
vec3 n = normalize(cross(dpdx, dpdy));
|
||||
|
||||
vec3 uAxis;
|
||||
vec3 vAxis;
|
||||
if (abs(n.y) > abs(n.x) && abs(n.y) > abs(n.z)) {
|
||||
uAxis = vec3(1.0, 0.0, 0.0);
|
||||
vAxis = vec3(0.0, 0.0, 1.0);
|
||||
} else if (abs(n.z) > abs(n.x)) {
|
||||
uAxis = vec3(1.0, 0.0, 0.0);
|
||||
vAxis = vec3(0.0, 1.0, 0.0);
|
||||
} else {
|
||||
uAxis = vec3(0.0, 0.0, 1.0);
|
||||
vAxis = vec3(0.0, 1.0, 0.0);
|
||||
}
|
||||
|
||||
float du = dot(vWorldPos, uAxis);
|
||||
float dv = dot(vWorldPos, vAxis);
|
||||
|
||||
vec2 gradU = vec2(dot(dpdx, uAxis), dot(dpdy, uAxis));
|
||||
vec2 gradV = vec2(dot(dpdx, vAxis), dot(dpdy, vAxis));
|
||||
vec2 gradUx = vec2(dFdx(baseUV.x), dFdy(baseUV.x));
|
||||
vec2 gradUy = vec2(dFdx(baseUV.y), dFdy(baseUV.y));
|
||||
|
||||
float corrUx = dot(gradUx, gradU);
|
||||
float corrVx = dot(gradUx, gradV);
|
||||
bool swap = abs(corrVx) > abs(corrUx);
|
||||
|
||||
float signU = swap ? corrVx : corrUx;
|
||||
float corrUy = dot(gradUy, gradU);
|
||||
float corrVy = dot(gradUy, gradV);
|
||||
float signV = swap ? corrUy : corrVy;
|
||||
|
||||
float tu = swap ? dv : du;
|
||||
float tv = swap ? du : dv;
|
||||
|
||||
float dtu_dx = swap ? dot(dpdx, vAxis) : dot(dpdx, uAxis);
|
||||
float dtu_dy = swap ? dot(dpdy, vAxis) : dot(dpdy, uAxis);
|
||||
float dtv_dx = swap ? dot(dpdx, uAxis) : dot(dpdx, vAxis);
|
||||
float dtv_dy = swap ? dot(dpdy, uAxis) : dot(dpdy, vAxis);
|
||||
|
||||
if (signU < 0.0) {
|
||||
tu = -tu;
|
||||
dtu_dx = -dtu_dx;
|
||||
dtu_dy = -dtu_dy;
|
||||
}
|
||||
if (signV < 0.0) {
|
||||
tv = -tv;
|
||||
dtv_dx = -dtv_dx;
|
||||
dtv_dy = -dtv_dy;
|
||||
}
|
||||
|
||||
uv = uv0 + fract(vec2(tu, tv)) * cellSize;
|
||||
dUVdx = vec2(dtu_dx, dtv_dx) * cellSize;
|
||||
dUVdy = vec2(dtu_dy, dtv_dy) * cellSize;
|
||||
useGrad = true;
|
||||
}
|
||||
|
||||
vec4 texColor = vec4(1.0);
|
||||
if (uUseTexture != 0) {
|
||||
if (useGrad) {
|
||||
texColor = disableMipmap ? textureLod(uTex0, uv, 0.0) : textureGrad(uTex0, uv, dUVdx, dUVdy);
|
||||
} else {
|
||||
texColor = texture(uTex0, uv);
|
||||
}
|
||||
}
|
||||
vec4 texColor = (uUseTexture != 0) ? texture(uTex0, vUV0) : vec4(1.0);
|
||||
vec4 c = texColor * vColor;
|
||||
if (c.a < uAlphaRef) discard;
|
||||
if (uUseLightmap != 0) c.rgb *= texture(uTex1, vUV1).rgb;
|
||||
@@ -117,5 +26,4 @@ void main() {
|
||||
|
||||
oColor = c;
|
||||
}
|
||||
) GLSL ";
|
||||
|
||||
)GLSL";
|
||||
|
||||
@@ -1,116 +1,25 @@
|
||||
R "GLSL(
|
||||
R"GLSL(
|
||||
#version 300 es
|
||||
precision mediump float;
|
||||
precision mediump int;
|
||||
|
||||
uniform sampler2D uTex0;
|
||||
uniform sampler2D uTex1;
|
||||
uniform int uUseTexture;
|
||||
uniform int uUseTileUV;
|
||||
uniform int uUseLightmap;
|
||||
uniform int uUseTexture;
|
||||
uniform int uUseLightmap;
|
||||
uniform float uAlphaRef;
|
||||
uniform vec4 uFogColor;
|
||||
uniform int uFogEnable;
|
||||
uniform vec4 uFogColor;
|
||||
uniform int uFogEnable;
|
||||
uniform float uInvGamma;
|
||||
|
||||
in vec2 vUV0;
|
||||
in vec2 vUV1;
|
||||
in vec4 vColor;
|
||||
in vec3 vWorldPos;
|
||||
in float vFogFactor;
|
||||
out vec4 oColor;
|
||||
in vec2 vUV0;
|
||||
in vec2 vUV1;
|
||||
in vec4 vColor;
|
||||
in float vFogFactor;
|
||||
out vec4 oColor;
|
||||
|
||||
void main() {
|
||||
vec2 uv = vUV0;
|
||||
vec2 dUVdx = vec2(0.0);
|
||||
vec2 dUVdy = vec2(0.0);
|
||||
bool useGrad = false;
|
||||
bool disableMipmap = false;
|
||||
|
||||
if (uUseTileUV != 0) {
|
||||
vec2 baseUV = vUV0;
|
||||
if (baseUV.x > 1.0) {
|
||||
baseUV.x -= 1.0;
|
||||
disableMipmap = true;
|
||||
}
|
||||
if (baseUV.y > 1.0) {
|
||||
baseUV.y -= 1.0;
|
||||
disableMipmap = true;
|
||||
}
|
||||
|
||||
vec2 atlasSize = vec2(textureSize(uTex0, 0));
|
||||
float tileSize = 16.0;
|
||||
vec2 cell = floor(baseUV * atlasSize / tileSize);
|
||||
vec2 uv0 = cell * tileSize / atlasSize;
|
||||
vec2 cellSize = vec2(tileSize) / atlasSize;
|
||||
|
||||
vec3 dpdx = dFdx(vWorldPos);
|
||||
vec3 dpdy = dFdy(vWorldPos);
|
||||
vec3 n = normalize(cross(dpdx, dpdy));
|
||||
|
||||
vec3 uAxis;
|
||||
vec3 vAxis;
|
||||
if (abs(n.y) > abs(n.x) && abs(n.y) > abs(n.z)) {
|
||||
uAxis = vec3(1.0, 0.0, 0.0);
|
||||
vAxis = vec3(0.0, 0.0, 1.0);
|
||||
} else if (abs(n.z) > abs(n.x)) {
|
||||
uAxis = vec3(1.0, 0.0, 0.0);
|
||||
vAxis = vec3(0.0, 1.0, 0.0);
|
||||
} else {
|
||||
uAxis = vec3(0.0, 0.0, 1.0);
|
||||
vAxis = vec3(0.0, 1.0, 0.0);
|
||||
}
|
||||
|
||||
float du = dot(vWorldPos, uAxis);
|
||||
float dv = dot(vWorldPos, vAxis);
|
||||
|
||||
vec2 gradU = vec2(dot(dpdx, uAxis), dot(dpdy, uAxis));
|
||||
vec2 gradV = vec2(dot(dpdx, vAxis), dot(dpdy, vAxis));
|
||||
vec2 gradUx = vec2(dFdx(baseUV.x), dFdy(baseUV.x));
|
||||
vec2 gradUy = vec2(dFdx(baseUV.y), dFdy(baseUV.y));
|
||||
|
||||
float corrUx = dot(gradUx, gradU);
|
||||
float corrVx = dot(gradUx, gradV);
|
||||
bool swap = abs(corrVx) > abs(corrUx);
|
||||
|
||||
float signU = swap ? corrVx : corrUx;
|
||||
float corrUy = dot(gradUy, gradU);
|
||||
float corrVy = dot(gradUy, gradV);
|
||||
float signV = swap ? corrUy : corrVy;
|
||||
|
||||
float tu = swap ? dv : du;
|
||||
float tv = swap ? du : dv;
|
||||
|
||||
float dtu_dx = swap ? dot(dpdx, vAxis) : dot(dpdx, uAxis);
|
||||
float dtu_dy = swap ? dot(dpdy, vAxis) : dot(dpdy, uAxis);
|
||||
float dtv_dx = swap ? dot(dpdx, uAxis) : dot(dpdx, vAxis);
|
||||
float dtv_dy = swap ? dot(dpdy, uAxis) : dot(dpdy, vAxis);
|
||||
|
||||
if (signU < 0.0) {
|
||||
tu = -tu;
|
||||
dtu_dx = -dtu_dx;
|
||||
dtu_dy = -dtu_dy;
|
||||
}
|
||||
if (signV < 0.0) {
|
||||
tv = -tv;
|
||||
dtv_dx = -dtv_dx;
|
||||
dtv_dy = -dtv_dy;
|
||||
}
|
||||
|
||||
uv = uv0 + fract(vec2(tu, tv)) * cellSize;
|
||||
dUVdx = vec2(dtu_dx, dtv_dx) * cellSize;
|
||||
dUVdy = vec2(dtu_dy, dtv_dy) * cellSize;
|
||||
useGrad = true;
|
||||
}
|
||||
|
||||
vec4 texColor = vec4(1.0);
|
||||
if (uUseTexture != 0) {
|
||||
if (useGrad) {
|
||||
texColor = disableMipmap ? textureLod(uTex0, uv, 0.0) : textureGrad(uTex0, uv, dUVdx, dUVdy);
|
||||
} else {
|
||||
texColor = texture(uTex0, uv);
|
||||
}
|
||||
}
|
||||
vec4 texColor = (uUseTexture != 0) ? texture(uTex0, vUV0) : vec4(1.0);
|
||||
vec4 c = texColor * vColor;
|
||||
if (c.a < uAlphaRef) discard;
|
||||
if (uUseLightmap != 0) c.rgb *= texture(uTex1, vUV1).rgb;
|
||||
@@ -120,5 +29,4 @@ void main() {
|
||||
|
||||
oColor = c;
|
||||
}
|
||||
) GLSL ";
|
||||
|
||||
)GLSL";
|
||||
|
||||
@@ -1,43 +1,40 @@
|
||||
R "GLSL(
|
||||
R"GLSL(
|
||||
#version 330 core
|
||||
layout(location = 0) in vec3 aPos;
|
||||
layout(location = 1) in vec2 aUV0;
|
||||
layout(location = 2) in vec4 aColor;
|
||||
layout(location = 3) in vec3 aNormal;
|
||||
layout(location = 4) in ivec2 aLMraw;
|
||||
layout(location=0) in vec3 aPos;
|
||||
layout(location=1) in vec2 aUV0;
|
||||
layout(location=2) in vec4 aColor;
|
||||
layout(location=3) in vec3 aNormal;
|
||||
layout(location=4) in ivec2 aLMraw;
|
||||
|
||||
uniform mat4 uMVP;
|
||||
uniform mat4 uMV;
|
||||
uniform mat3 uNormalMatrix;
|
||||
uniform mat4 uMVP;
|
||||
uniform mat4 uMV;
|
||||
uniform mat3 uNormalMatrix;
|
||||
uniform float uNormalSign;
|
||||
uniform mat4 uTexMat0;
|
||||
uniform vec4 uBaseColor;
|
||||
uniform int uLighting;
|
||||
uniform vec3 uLight0Dir;
|
||||
uniform vec3 uLight1Dir;
|
||||
uniform vec3 uLightDiffuse;
|
||||
uniform vec3 uLightAmbient;
|
||||
uniform vec3 uChunkOffset;
|
||||
uniform int uFogMode;
|
||||
uniform mat4 uTexMat0;
|
||||
uniform vec4 uBaseColor;
|
||||
uniform int uLighting;
|
||||
uniform vec3 uLight0Dir;
|
||||
uniform vec3 uLight1Dir;
|
||||
uniform vec3 uLightDiffuse;
|
||||
uniform vec3 uLightAmbient;
|
||||
uniform vec3 uChunkOffset;
|
||||
uniform int uFogMode;
|
||||
uniform float uFogStart;
|
||||
uniform float uFogEnd;
|
||||
uniform float uFogDensity;
|
||||
uniform vec4 uLMTransform;
|
||||
uniform vec2 uGlobalLM;
|
||||
uniform vec4 uLMTransform;
|
||||
uniform vec2 uGlobalLM;
|
||||
|
||||
out vec2 vUV0;
|
||||
out vec2 vUV1;
|
||||
out vec4 vColor;
|
||||
out vec3 vWorldPos;
|
||||
out vec2 vUV0;
|
||||
out vec2 vUV1;
|
||||
out vec4 vColor;
|
||||
out float vFogFactor;
|
||||
|
||||
void main() {
|
||||
vec3 worldPos = aPos + uChunkOffset;
|
||||
vec4 aPos4 = vec4(worldPos, 1.0);
|
||||
vec4 eyePos = uMV * aPos4;
|
||||
gl_Position = uMVP * aPos4;
|
||||
vUV0 = (uTexMat0 * vec4(aUV0, 0.0, 1.0)).xy;
|
||||
vWorldPos = worldPos;
|
||||
vec4 aPos4 = vec4(aPos + uChunkOffset, 1.0);
|
||||
vec4 eyePos = uMV * aPos4;
|
||||
gl_Position = uMVP * aPos4;
|
||||
vUV0 = (uTexMat0 * vec4(aUV0, 0.0, 1.0)).xy;
|
||||
|
||||
vec2 lm = (aLMraw.x <= -500) ? uGlobalLM : vec2(aLMraw);
|
||||
vUV1 = (lm / 256.0) * uLMTransform.xy + uLMTransform.zw;
|
||||
@@ -55,13 +52,9 @@ void main() {
|
||||
}
|
||||
|
||||
float eDist = length(eyePos.xyz);
|
||||
if (uFogMode == 1) vFogFactor = clamp((uFogEnd - eDist) / max(uFogEnd - uFogStart, 1e-4), 0.0, 1.0);
|
||||
if (uFogMode == 1) vFogFactor = clamp((uFogEnd - eDist) / max(uFogEnd - uFogStart, 1e-4), 0.0, 1.0);
|
||||
else if (uFogMode == 2) vFogFactor = clamp(exp(-uFogDensity * eDist), 0.0, 1.0);
|
||||
else if (uFogMode == 3) {
|
||||
float d = uFogDensity * eDist;
|
||||
vFogFactor = clamp(exp(-d * d), 0.0, 1.0);
|
||||
}
|
||||
else vFogFactor = 1.0;
|
||||
else if (uFogMode == 3) { float d = uFogDensity * eDist; vFogFactor = clamp(exp(-d*d), 0.0, 1.0); }
|
||||
else vFogFactor = 1.0;
|
||||
}
|
||||
) GLSL ";
|
||||
|
||||
)GLSL";
|
||||
@@ -1,46 +1,43 @@
|
||||
R "GLSL(
|
||||
R"GLSL(
|
||||
#version 300 es
|
||||
precision highp float;
|
||||
precision highp int;
|
||||
|
||||
layout(location = 0) in vec3 aPos;
|
||||
layout(location = 1) in vec2 aUV0;
|
||||
layout(location = 2) in vec4 aColor;
|
||||
layout(location = 3) in vec3 aNormal;
|
||||
layout(location = 4) in ivec2 aLMraw;
|
||||
layout(location=0) in vec3 aPos;
|
||||
layout(location=1) in vec2 aUV0;
|
||||
layout(location=2) in vec4 aColor;
|
||||
layout(location=3) in vec3 aNormal;
|
||||
layout(location=4) in ivec2 aLMraw;
|
||||
|
||||
uniform mat4 uMVP;
|
||||
uniform mat4 uMV;
|
||||
uniform mat3 uNormalMatrix;
|
||||
uniform mat4 uMVP;
|
||||
uniform mat4 uMV;
|
||||
uniform mat3 uNormalMatrix;
|
||||
uniform float uNormalSign;
|
||||
uniform mat4 uTexMat0;
|
||||
uniform vec4 uBaseColor;
|
||||
uniform int uLighting;
|
||||
uniform vec3 uLight0Dir;
|
||||
uniform vec3 uLight1Dir;
|
||||
uniform vec3 uLightDiffuse;
|
||||
uniform vec3 uLightAmbient;
|
||||
uniform vec3 uChunkOffset;
|
||||
uniform int uFogMode;
|
||||
uniform mat4 uTexMat0;
|
||||
uniform vec4 uBaseColor;
|
||||
uniform int uLighting;
|
||||
uniform vec3 uLight0Dir;
|
||||
uniform vec3 uLight1Dir;
|
||||
uniform vec3 uLightDiffuse;
|
||||
uniform vec3 uLightAmbient;
|
||||
uniform vec3 uChunkOffset;
|
||||
uniform int uFogMode;
|
||||
uniform float uFogStart;
|
||||
uniform float uFogEnd;
|
||||
uniform float uFogDensity;
|
||||
uniform vec4 uLMTransform;
|
||||
uniform vec2 uGlobalLM;
|
||||
uniform vec4 uLMTransform;
|
||||
uniform vec2 uGlobalLM;
|
||||
|
||||
out vec2 vUV0;
|
||||
out vec2 vUV1;
|
||||
out vec4 vColor;
|
||||
out vec3 vWorldPos;
|
||||
out vec2 vUV0;
|
||||
out vec2 vUV1;
|
||||
out vec4 vColor;
|
||||
out float vFogFactor;
|
||||
|
||||
void main() {
|
||||
vec3 worldPos = aPos + uChunkOffset;
|
||||
vec4 aPos4 = vec4(worldPos, 1.0);
|
||||
vec4 eyePos = uMV * aPos4;
|
||||
gl_Position = uMVP * aPos4;
|
||||
vUV0 = (uTexMat0 * vec4(aUV0, 0.0, 1.0)).xy;
|
||||
vWorldPos = worldPos;
|
||||
vec4 aPos4 = vec4(aPos + uChunkOffset, 1.0);
|
||||
vec4 eyePos = uMV * aPos4;
|
||||
gl_Position = uMVP * aPos4;
|
||||
vUV0 = (uTexMat0 * vec4(aUV0, 0.0, 1.0)).xy;
|
||||
|
||||
vec2 lm = (aLMraw.x <= -500) ? uGlobalLM : vec2(aLMraw);
|
||||
vUV1 = (lm / 256.0) * uLMTransform.xy + uLMTransform.zw;
|
||||
@@ -58,13 +55,9 @@ void main() {
|
||||
}
|
||||
|
||||
float eDist = length(eyePos.xyz);
|
||||
if (uFogMode == 1) vFogFactor = clamp((uFogEnd - eDist) / max(uFogEnd - uFogStart, 1e-4), 0.0, 1.0);
|
||||
if (uFogMode == 1) vFogFactor = clamp((uFogEnd - eDist) / max(uFogEnd - uFogStart, 1e-4), 0.0, 1.0);
|
||||
else if (uFogMode == 2) vFogFactor = clamp(exp(-uFogDensity * eDist), 0.0, 1.0);
|
||||
else if (uFogMode == 3) {
|
||||
float d = uFogDensity * eDist;
|
||||
vFogFactor = clamp(exp(-d * d), 0.0, 1.0);
|
||||
}
|
||||
else vFogFactor = 1.0;
|
||||
else if (uFogMode == 3) { float d = uFogDensity * eDist; vFogFactor = clamp(exp(-d*d), 0.0, 1.0); }
|
||||
else vFogFactor = 1.0;
|
||||
}
|
||||
) GLSL ";
|
||||
|
||||
)GLSL";
|
||||
Reference in New Issue
Block a user