Clean up TextureAtlas, fix swaying and offsetting, add pillar blockmodel.

master
Auri 2021-09-02 23:48:09 -07:00
parent 60051a7d41
commit 838680f0fc
53 changed files with 548 additions and 501 deletions

View File

@ -14,6 +14,7 @@
<file path="$PROJECT_DIR$/.vscode" />
<file path="$PROJECT_DIR$/.github" />
<file path="$PROJECT_DIR$/worlds" />
<file path="$PROJECT_DIR$/src/CMakeFiles" />
<file path="$PROJECT_DIR$/cmake-build-debug" />
<file path="$PROJECT_DIR$/cmake-build-install" />
<file path="$PROJECT_DIR$/cmake-build-release" />
@ -27,4 +28,4 @@
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>
</project>

View File

@ -1,142 +0,0 @@
cmake_minimum_required (VERSION 3.12 FATAL_ERROR)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_BUILD_RPATH_USE_ORIGIN ON)
# Set warnings
if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang"))
add_compile_options(
-Werror -Wall -Wextra -pedantic -pedantic-errors
-Wnon-virtual-dtor -Wmisleading-indentation -Wlogical-op -Wnull-dereference
-Wno-unused-parameter -Wno-reorder -Wno-sign-compare)
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
add_compile_options(/permissive /W4 /w14640)
endif()
set(PROJECT_NAME "Zepha")
set(MAIN_EXEC_NAME "Zepha")
# set(TEST_EXEC_NAME "ZephaTest")
project(${PROJECT_NAME})
find_path(GLEW_HEADERS GL/glew.h)
find_path(GLFW_HEADERS GLFW/glfw3.h)
find_path(LUA_HEADERS lua.hpp
/usr/include/lua5.3
/usr/local/include/lua5.3)
find_path(ASSIMP_HEADERS assimp/Importer.hpp)
find_path(ENET_HEADERS enet/enet.h)
find_path(NOISE_HEADERS NAMES libnoise/noise.h libnoise/module/modulebase.h)
find_path(GLM_HEADERS glm/glm.hpp)
find_path(PTHREAD_HEADERS pthread.h)
find_library(ENET_LIB enet)
find_library(NOISE_LIB NAMES libnoise noise)
if (WIN32)
find_library(PTHREAD_LIB pthreadVC3)
else()
find_library(PTHREAD_LIB pthread)
endif()
include_directories(
${GLM_HEADERS}
${GLEW_HEADERS}
${LUA_HEADERS}
${ASSIMP_HEADERS}
${ENET_HEADERS}
${NOISE_HEADERS}
${PTHREAD_HEADERS}
lib/fastnoise2/include
lib/catch2/include
lib/gzip/include
lib/cute_files/include
lib/stb_image/include
lib/json/include
lib/sol/include
)
add_subdirectory(src)
add_executable(${MAIN_EXEC_NAME} src/Main.cpp)
target_link_libraries(${MAIN_EXEC_NAME} Zepha_Core)
target_include_directories(${MAIN_EXEC_NAME} PRIVATE ${GLFW_HEADERS})
# Enet
target_link_libraries(${MAIN_EXEC_NAME} ${ENET_LIB})
# Find and Link OpenGL
find_package(OpenGL REQUIRED)
find_package(GLUT REQUIRED)
target_link_libraries(${MAIN_EXEC_NAME} ${OPENGL_LIBRARIES} ${GLUT_LIBRARY})
# Build GLFW
if (WIN32)
find_library(GLFW_LIB glfw3dll)
else()
find_library(GLFW_LIB NAMES GLFW glfw glfw3)
endif()
target_link_libraries(${MAIN_EXEC_NAME} ${GLFW_LIB})
# Link GLEW
if (WIN32)
find_library(GLEW_LIB glew32)
else()
find_library(GLEW_LIB NAMES GLEW glew3)
endif()
target_link_libraries(${MAIN_EXEC_NAME} ${GLEW_LIB})
# Build and Link Assimp
if (WIN32)
find_library(ASSIMP_LIB assimp-vc142-mt)
else()
set(BUILD_SHARED_LIBS OFF)
set(ASSIMP_NO_EXPORT ON)
set(ASSIMP_BUILD_TESTS OFF)
set(ASSIMP_BUILD_ASSIMP_TOOLS OFF)
set(ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT OFF)
set(ASSIMP_BUILD_B3D_IMPORTER ON)
set(ASSIMP_BUILD_X3D_IMPORTER ON) # Doesn't compile if not defined
add_subdirectory(lib/assimp)
target_compile_options(assimp PRIVATE -w)
target_link_libraries(${MAIN_EXEC_NAME} assimp)
endif()
# Build and Link FastNoise2
add_subdirectory(lib/fastnoise2)
target_link_libraries(${MAIN_EXEC_NAME} FastNoise)
# Link Lua 5.3.5
find_library(LUA_LIB NAMES lua lua5.3)
target_link_libraries(${MAIN_EXEC_NAME} ${LUA_LIB})
# Link Noise
target_link_libraries(${MAIN_EXEC_NAME} ${NOISE_LIB})
# Link PThread Dynamically
target_link_libraries (${MAIN_EXEC_NAME} ${PTHREAD_LIB})
# Link Z Dynamically
target_link_libraries (${MAIN_EXEC_NAME} z)
# Fix Win32 networking
if(WIN32)
target_link_libraries(${MAIN_EXEC_NAME} winmm ws2_32)
endif()
# Test Build
# add_subdirectory(test)
# add_executable(${TEST_EXEC_NAME} test/Main.cpp)
# target_link_libraries(${TEST_EXEC_NAME} Zepha_Core)
# target_link_libraries(${TEST_EXEC_NAME} Zepha_Test)
# target_include_directories(${TEST_EXEC_NAME} PRIVATE ${GLFW_HEADERS})
# target_link_libraries(${TEST_EXEC_NAME} ${LUA_LIB})
# target_link_libraries (${TEST_EXEC_NAME} z)
# target_link_libraries(${TEST_EXEC_NAME} ${ENET_LIB})

View File

@ -5,4 +5,5 @@ require(_PATH .. "cross_large")
require(_PATH .. "block_slab")
require(_PATH .. "block_slab_foliage")
require(_PATH .. "leaf_like")
require(_PATH .. "cross_plant")
require(_PATH .. "cross_plant")
require(_PATH .. "pillar")

View File

@ -0,0 +1,104 @@
--
-- Basic 'pillar' model, represents an 8-sided pillar.
-- Texture order is: top, bottom, side
--
zepha.register_blockmodel("base:pillar", {
parts = {
{
face = "left",
tex = 3,
points = {
0, 0, 4/16, 0, 1,
0, 0, 12/16, 8/16, 1,
0, 1, 12/16, 8/16, 0,
0, 1, 4/16, 0, 0
}
}, {
face = "right",
tex = 3,
points = {
1, 1, 12/16, 0, 0,
1, 0, 12/16, 0, 1,
1, 0, 4/16, 8/16, 1,
1, 1, 4/16, 8/16, 0
}
-- }, {
-- face = "top",
-- tex = 1,
-- points = {
-- 0, 1, 0, 0, 0,
-- 0, 1, 1, 0, 1,
-- 1, 1, 1, 1, 1,
-- 1, 1, 0, 1, 0
-- }
-- }, {
-- face = "bottom",
-- tex = 2,
-- points = {
-- 0, 0, 0, 0, 0,
-- 1, 0, 0, 1, 0,
-- 1, 0, 1, 1, 1,
-- 0, 0, 1, 0, 1
-- }
}, {
face = "front",
tex = 3,
points = {
4/16, 0, 1, 0, 1,
12/16, 0, 1, 8/16, 1,
12/16, 1, 1, 8/16, 0,
4/16, 1, 1, 0, 0
}
}, {
face = "back",
tex = 3,
points = {
4/16, 0, 0, 8/16, 1,
4/16, 1, 0, 8/16, 0,
12/16, 1, 0, 0, 0,
12/16, 0, 0, 0, 1
}
},
{
face = "nocull",
tex = 3,
points = {
0, 0, 4/16, 10/16, 0,
0, 1, 4/16, 10/16, 1,
4/16, 1, 0, 1, 1,
4/16, 0, 0, 1, 0
}
},
{
face = "nocull",
tex = 3,
points = {
12/16, 0, 0, 1, 0,
12/16, 1, 0, 1, 1,
1, 1, 4/16, 10/16, 1,
1, 0, 4/16, 10/16, 0
}
},
{
face = "nocull",
tex = 3,
points = {
4/16, 0, 1, 1, 0,
4/16, 1, 1, 1, 1,
0, 1, 12/16, 10/16, 1,
0, 0, 12/16, 10/16, 0
}
},
{
face = "nocull",
tex = 3,
points = {
1, 0, 12/16, 10/16, 0,
1, 1, 12/16, 10/16, 1,
12/16, 1, 1, 1, 1,
12/16, 0, 1, 1, 0
}
}
}
})

View File

@ -82,7 +82,7 @@ void main() {
vec4 origin = vec4(round(unpackFloat(gs_in[i].modValues.x) * 8 + 8), 1);
vec3 bsp = vec3(pos - origin);
vec3 worldPos = (model * pos).xyz;
if (bsp.x*bsp.y*bsp.z != 0 && bsp.x*bsp.y*bsp.z != 1) {
if (bsp.x * bsp.y * bsp.z != 0 && bsp.x * bsp.y * bsp.z != 1) {
vec3 sway = (texture(swayTex, worldPos.xz * (worldPos.y / 16.f) / 16.f).xyz - .5f) * vec3(gs_in[i].modValues.y, gs_in[i].modValues.y / 2, gs_in[i].modValues.y);
pos += vec4(sway, 0);
}

View File

@ -12,7 +12,7 @@ layout (location = 2) in ivec3 aBlend;
layout (location = 5) in ivec4 aLight;
layout (location = 6) in int aShaderMod;
layout (location = 7) in ivec3 aModValues;
layout (location = 7) in vec3 aModValues;
out VS_OUT {
vec3 pos;

View File

@ -28,7 +28,7 @@ f64 Client::getDelta() {
}
void Client::startLocalServer(const string& subgame) {
//TODO: Implement Local Server
// TODO: Implement Local Server
// localServer = std::make_shared<LocalServerInstance>(executablePath, addr.port, state.subgame);
// localServer->start();

View File

@ -1,10 +1,10 @@
#include "util/GL.h"
#include <util/Util.h>
#include <GLFW/glfw3.h>
#include "Input.h"
#include "Window.h"
#include "util/Util.h"
#include "client/Window.h"
void Input::init(GLFWwindow* window) {
this->window = window;

View File

@ -7,6 +7,8 @@
#include "util/Types.h"
#include "client/Callback.h"
class GLFWwindow;
/**
* Manages callbacks for key and mouse input, allows toggling mouse locking.
*/

View File

@ -2,11 +2,12 @@
// Created by aurailus on 2019-10-31.
//
#include "LocalServerInstance.h"
#include "util/Log.h"
#include "server/Server.h"
#include <iostream>
#include <thread>
#include <iostream>
#include "LocalServerInstance.h"
#include "server/Server.h"
LocalServerInstance::LocalServerInstance(const std::string& path, unsigned short port, const std::string& subgame) :
port(port),

View File

@ -6,7 +6,6 @@
#include <stdexcept>
#include "util/Log.h"
#include "util/GL.h"
Window::Window() : Window({ 800, 600 }) {};

View File

@ -32,7 +32,7 @@ void ClientNetworkInterpreter::update() {
default: break;
case ENET_EVENT_TYPE_CONNECT: {
std::cout << Log::info << "Connected to server "
<< NetHandler::intToIPString(*reinterpret_cast<unsigned int*>(&event.peer->address.host))
<< NetHandler::intToIPString(*reinterpret_cast<u32*>(&event.peer->address.host))
<< ":" << event.peer->address.port << "." << Log::endl;
break;
}
@ -42,7 +42,9 @@ void ClientNetworkInterpreter::update() {
break;
}
case ENET_EVENT_TYPE_DISCONNECT: {
//std::cout << Log::info << "Disconnected from server " << event.peer->address.host << ":" << event.peer->address.port << "." << Log::endl;
std::cout << Log::info << "Disconnected from server "
<< NetHandler::intToIPString(*reinterpret_cast<u32*>(&event.peer->address.host))
<< ":" << event.peer->address.port << "." << Log::endl;
break;
}
}

View File

@ -56,7 +56,7 @@ void ServerConnection::processConnecting() {
if (elapsedMs < timeout) {
if (enet_host_service(host, &event, 0) > 0 && event.type == ENET_EVENT_TYPE_CONNECT) {
std::cout << Log::info << "Connected to "
<< NetHandler::intToIPString(*reinterpret_cast<unsigned int*>(&event.peer->address.host))
<< NetHandler::intToIPString(*reinterpret_cast<u32*>(&event.peer->address.host))
<< ":" << event.peer->address.port << "." << Log::endl;
state = State::CONNECTED;

View File

@ -11,7 +11,7 @@
Font::Font(TextureAtlas& atlas, std::shared_ptr<AtlasRef> tex) :
fontTex(std::move(tex)),
atlasSize(atlas.pixelSize) {
atlasSize(atlas.canvasSize) {
getCharWidths(atlas);
}
@ -30,8 +30,8 @@ void Font::getCharWidths(TextureAtlas& atlas) {
for (u16 i = 1; i < C_COUNT + 1; i++) {
glm::vec2 charPos = { i % 18 * C_WIDTH, std::floor(i / 18) * C_HEIGHT };
u32 xBase = static_cast<u32>(fontTex->pos.x) + static_cast<u32>(charPos.x);
u32 yBase = static_cast<u32>(fontTex->pos.y) + static_cast<u32>(charPos.y);
u32 xBase = static_cast<u32>(fontTex->rawPos.x) + static_cast<u32>(charPos.x);
u32 yBase = static_cast<u32>(fontTex->rawPos.y) + static_cast<u32>(charPos.y);
u16 width = 0;

View File

@ -58,7 +58,7 @@ void Renderer::update(double delta) {
elapsedTime += delta;
window.update();
//world.updateSwayMap(delta);
world.updateSwayMap(delta);
}
void Renderer::beginChunkDeferredCalls() {

View File

@ -2,8 +2,8 @@
// Created by aurailus on 29/11/18.
//
#include <stb_image.h>
#include <stdexcept>
#include <stb_image.h>
#include "Texture.h"

View File

@ -57,15 +57,15 @@ ChunkMeshGenerator::ChunkMeshGenerator(MeshChunkDetails* meshDetails, LocalDefin
default: break;
case MeshMod::OFFSET_X:
// vis.x += blockOffsets[0][vec3(off) / 16.f] * mod.second;
vis.x += blockOffsets[0][off] * mod.second;
break;
case MeshMod::OFFSET_Y:
// vis.y += blockOffsets[1][vec3(off) / 16.f] * mod.second;
vis.y += blockOffsets[1][off] * mod.second;
break;
case MeshMod::OFFSET_Z:
// vis.z += blockOffsets[2][vec3(off) / 16.f] * mod.second;
vis.z += blockOffsets[2][off] * mod.second;
break;
}
}

View File

@ -32,5 +32,5 @@ MeshChunk::Mesh::Mesh(const vec<Vertex>& vertices, const vec<u32>& indices) {
createVertexAttrib(idx++, 1, GL_FLOAT, false, STRIDE_OFFSET(Vertex, normal));
createVertexAttrib(idx++, 4, GL_UNSIGNED_BYTE, true, STRIDE_OFFSET(Vertex, light));
createVertexAttrib(idx++, 1, GL_UNSIGNED_BYTE, true, STRIDE_OFFSET(Vertex, shaderMod));
createVertexAttrib(idx, 3, GL_UNSIGNED_BYTE, true, STRIDE_OFFSET(Vertex, modValues));
createVertexAttrib(idx++, 3, GL_FLOAT , false, STRIDE_OFFSET(Vertex, modValues));
}

View File

@ -26,7 +26,7 @@ public:
u8vec4 light;
u8 shaderMod;
u8vec3 modValues;
vec3 modValues;
};
/** Represents a MeshChunk's underlying mesh. */

View File

@ -4,9 +4,8 @@
#pragma once
#include <glm/mat4x4.hpp>
#include "util/GL.h"
#include <glm/mat4x4.hpp>
struct GuiUniforms {
glm::mat4 matrix;

View File

@ -2,7 +2,7 @@
// Created by aurailus on 25/09/19.
//
#include <glm/vec2.hpp>
#include <iostream>
#include "WorldGeometryShader.h"
@ -11,7 +11,11 @@ WorldGeometryShader::WorldGeometryShader(glm::ivec2 windowSize, float bufferScal
bufferScale(bufferScale),
swayData(16 * 4 * 16) {
swayNoise = FastNoise::New<FastNoise::Constant>();
let simplex = FastNoise::New<FastNoise::Simplex>();
let generator = FastNoise::New<FastNoise::DomainScale>();
generator->SetSource(simplex);
generator->SetScale(500.f);
swayGenerator = generator;
}
void WorldGeometryShader::postCreate() {
@ -33,15 +37,14 @@ void WorldGeometryShader::windowResized(glm::ivec2 windowSize) {
}
void WorldGeometryShader::updateSwayMap(double delta) {
swayOffset += delta * 2.8;
for (int i = 0; i < 16 * 16; i++) {
swayData[i * 4] = static_cast<unsigned char>(
(fmax(-1, fmin(1, swayNoise->GenSingle3D((i / 16) / 3.f, (i % 16) / 3.f, swayOffset, 0))) + 1) / 2.f * 255.f);
swayData[i * 4 + 1] = static_cast<unsigned char>(
(fmax(-1, fmin(1, swayNoise->GenSingle3D((i / 16) / 3.f, (i % 16) / 3.f, swayOffset + 50, 0))) + 1) / 2.f * 255.f);
swayData[i * 4 + 2] = static_cast<unsigned char>(
(fmax(-1, fmin(1, swayNoise->GenSingle3D((i / 16) / 3.f, (i % 16) / 3.f, swayOffset + 100, 0))) + 1) / 2.f *
255.f);
swayOffset += delta * 0.001;
for (u16 i = 0; i < 16 * 16; i++) {
swayData[i * 4] = static_cast<u8>((fmax(-1, fmin(1,
swayGenerator->GenSingle3D((i / 16) / 3.f, (i % 16) / 3.f, swayOffset, 0))) + 1) / 2.f * 255.f);
swayData[i * 4 + 1] = static_cast<u8>((fmax(-1, fmin(1,
swayGenerator->GenSingle3D((i / 16) / 3.f, (i % 16) / 3.f, swayOffset + 50, 0))) + 1) / 2.f * 255.f);
swayData[i * 4 + 2] = static_cast<u8>((fmax(-1, fmin(1,
swayGenerator->GenSingle3D((i / 16) / 3.f, (i % 16) / 3.f, swayOffset + 100, 0))) + 1) / 2.f * 255.f);
}
swayTex.updateTexture(0, 0, 16, 16, &swayData[0]);
}

View File

@ -4,12 +4,12 @@
#pragma once
#include <vector>
#include <FastNoise/FastNoise.h>
#include "Shader.h"
#include "../Texture.h"
#include "util/Types.h"
#include "client/graph/Texture.h"
class WorldGeometryShader : public Shader {
public:
@ -34,9 +34,9 @@ public:
Uniforms uniforms{};
Texture swayTex;
double swayOffset = 0;
FastNoise::SmartNode<> swayNoise;
std::vector<unsigned char> swayData{};
vec<u8> swayData{};
f64 swayOffset = 0;
FastNoise::SmartNode<> swayGenerator;
glm::ivec2 windowSize{};
float bufferScale = 1;

View File

@ -130,6 +130,7 @@ bool Gui::Element::handleMouseClick(ivec2 mousePos, u32 button, bool down) {
}
void Gui::Element::draw(Renderer& renderer) {
if (!getStyle<bool>(Gui::Prop::VISIBLE, true)) return;
entity.draw(renderer);
for (let& child : children) child->draw(renderer);
}

View File

@ -8,9 +8,7 @@
#include "Gui.h"
#include "util/Util.h"
#ifndef M_PI
# define M_PI 3.14159265358979323846 /* pi */
#endif
#define M_PI 3.14159265358979323846
Gui::Expression::Expression(const string& exp) {
setExpression(exp);

View File

@ -8,6 +8,7 @@ namespace Gui {
enum class Prop {
ID,
CLASS,
VISIBLE,
POS,
SIZE,

View File

@ -138,8 +138,8 @@ void ConnectScene::update() {
string uncompressed = gzip::decompress(data.data(), data.length());
client.game->textures.addImage(
reinterpret_cast<unsigned char*>(const_cast<char*>(uncompressed.data())),
assetName, true, width, height);
assetName, true, u16vec2(width, height),
reinterpret_cast<u8*>(const_cast<char*>(uncompressed.data())));
}
else if (t == AssetType::MODEL) {
string format = p.d.read<string>();
@ -213,7 +213,7 @@ void ConnectScene::draw() {
renderer.beginChunkDeferredCalls();
renderer.endDeferredCalls();
renderer.beginGUIDrawCalls();
renderer.enableTexture(&client.game->textures.atlasTexture);
renderer.enableTexture(&client.game->textures.texture);
root.draw(renderer);
}

View File

@ -47,18 +47,18 @@ void GameScene::draw() {
perf.start("draw:world");
renderer.beginChunkDeferredCalls();
renderer.enableTexture(&client.game->textures.atlasTexture);
renderer.enableTexture(&client.game->textures.texture);
world.l()->drawChunks();
perf.start("draw:entities");
renderer.beginEntityDeferredCalls();
renderer.enableTexture(&client.game->textures.atlasTexture);
renderer.enableTexture(&client.game->textures.texture);
world.l()->drawEntities();
renderer.endDeferredCalls();
perf.start("draw:interface");
renderer.beginGUIDrawCalls();
renderer.enableTexture(&client.game->textures.atlasTexture);
renderer.enableTexture(&client.game->textures.texture);
world.l()->drawInterface();
perf.start("idle");

View File

@ -37,7 +37,7 @@ void LuaErrorScene::draw() {
renderer.beginChunkDeferredCalls();
renderer.endDeferredCalls();
renderer.beginGUIDrawCalls();
renderer.enableTexture(&client.game->textures.atlasTexture);
renderer.enableTexture(&client.game->textures.texture);
root.draw(renderer);
}

View File

@ -1,7 +1,7 @@
#include <fstream>
#include <iostream>
#include <nlohmann/json.hpp>
#include <cute_files.h>
#include <nlohmann/json.hpp>
#include "MainMenuScene.h"
@ -211,6 +211,6 @@ void MainMenuScene::draw() {
renderer.endDeferredCalls();
renderer.beginGUIDrawCalls();
renderer.enableTexture(&client.game->textures.atlasTexture);
renderer.enableTexture(&client.game->textures.texture);
root.draw(renderer);
}

View File

@ -12,22 +12,16 @@
#include "world/dim/LocalDimension.h"
MeshGenStream::MeshGenStream(SubgamePtr game, LocalDimension& dimension): dimension(dimension),
noiseSampler({ NoiseSample(u16vec3(16), 4), NoiseSample(u16vec3(16), 4), NoiseSample(u16vec3(16), 4) }) {
/*noise::module::Perlin offsetBaseNoise;
offsetBaseNoise.SetFrequency(8);
offsetBaseNoise.SetOctaveCount(3);
noise::module::Turbulence offsetTurbulence;
offsetTurbulence.SetSourceModule(0, offsetBaseNoise);
offsetTurbulence.SetFrequency(4.0);
offsetTurbulence.SetPower(0.125);*/
generator = FastNoise::New<FastNoise::Constant>();
noiseSampler({ NoiseSample(u16vec3(16), 1), NoiseSample(u16vec3(16), 1), NoiseSample(u16vec3(16), 1) }) {
let simplex = FastNoise::New<FastNoise::Simplex>();
let generator = FastNoise::New<FastNoise::DomainScale>();
generator->SetSource(simplex);
generator->SetScale(1000.f);
// 8 is just a random value to offset results
// noiseSampler[0].generate(u16vec3(8, 0, 0), generator);
// noiseSampler[1].generate(u16vec3(0, 8, 0), generator);
// noiseSampler[2].generate(u16vec3(0, 0, 8), generator);
noiseSampler[0].generate(u16vec3(8, 0, 0), generator);
noiseSampler[1].generate(u16vec3(0, 8, 0), generator);
noiseSampler[2].generate(u16vec3(0, 0, 8), generator);
threads.reserve(THREADS);
for (int i = 0; i < THREADS; i++) threads.emplace_back(*game.l(), noiseSampler);

View File

@ -70,7 +70,5 @@ private:
std::unordered_set<glm::vec3, Vec::vec3> queuedMap;
constexpr const static u8 HIGH_DETAIL_RANGE = 4;
FastNoise::SmartNode<> generator;
};

View File

@ -12,7 +12,7 @@
*/
LocalSubgame::LocalSubgame(const std::string& baseAssets) :
textures(2048),
textures(u16vec2(2048)),
lua(std::make_unique<LocalLuaParser>(*this)),
biomes(std::make_unique<LocalBiomeAtlas>()),

View File

@ -1,26 +1,21 @@
//
// Created by aurailus on 16/04/19.
//
#include <cmath>
#include <iostream>
#include <algorithm>
#include <stb_image.h>
#include <cute_files.h>
#include <util/Types.h>
#include <util/Util.h>
#include "TextureAtlas.h"
#include "util/Log.h"
#include "util/Util.h"
#include "game/atlas/asset/AtlasRef.h"
TextureAtlas::TextureAtlas(unsigned int width, unsigned int height) :
pixelSize(width, (height == 0 ? width : height)),
tileSize(pixelSize.x / 16, pixelSize.y / 16),
atlasData(pixelSize.x * 4 * pixelSize.y) {
maxTextureSlots = tileSize.x * tileSize.y;
TextureAtlas::TextureAtlas(uvec2 size) :
canvasSize(size),
canvasTileSize(size / 16u),
atlasData(size.x * 4 * size.y),
maxTextureSlots(canvasTileSize.x * canvasTileSize.y),
empty(canvasTileSize.x * canvasTileSize.y, true) {
// int maxTexSize, texUnits;
//
@ -30,14 +25,13 @@ TextureAtlas::TextureAtlas(unsigned int width, unsigned int height) :
// glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &texUnits);
// std::cout << Log::info << "This GPU supports " << texUnits << " texture units." << Log::endl;
empty = std::vector<bool>(tileSize.x * tileSize.y, true);
atlasTexture.loadFromBytes(&atlasData[0], pixelSize.x, pixelSize.y);
texture.loadFromBytes(&atlasData[0], size.x, size.y);
createMissingImage();
createMissingTexture();
}
std::vector<std::shared_ptr<AtlasRef>> TextureAtlas::loadDirectory(const std::string& path, bool base, bool recursive) {
std::vector<std::shared_ptr<AtlasRef>> refs{};
vec<sptr<AtlasRef>> TextureAtlas::loadDirectory(const string& path, bool base, bool recurse) {
vec<sptr<AtlasRef>> refs {};
cf_dir_t dir;
cf_dir_open(&dir, (path).c_str());
@ -45,17 +39,15 @@ std::vector<std::shared_ptr<AtlasRef>> TextureAtlas::loadDirectory(const std::st
while (dir.has_next) {
cf_file_t file;
cf_read_file(&dir, &file);
std::string_view name = file.name;
if (!file.is_dir && strcmp(file.ext, ".png") == 0) {
refs.push_back(
loadImage(file.path, std::string(file.name).substr(0, std::string(file.name).size() - 4), base));
}
if (!file.is_dir && strcmp(file.ext, ".png") == 0)
refs.push_back(loadImage(file.path, string(name.substr(0, name.size() - 4)), base));
if (recursive && file.is_dir && strncmp(file.name, ".", 1) != 0) {
auto vec = loadDirectory(file.path, base, recursive);
if (recurse && file.is_dir && name.data()[0] != '.') {
let vec = loadDirectory(file.path, base, true);
refs.insert(refs.end(), vec.begin(), vec.end());
}
cf_dir_next(&dir);
}
cf_dir_close(&dir);
@ -63,95 +55,75 @@ std::vector<std::shared_ptr<AtlasRef>> TextureAtlas::loadDirectory(const std::st
return refs;
}
std::shared_ptr<AtlasRef> TextureAtlas::loadImage(const std::string& path, const std::string& name, bool base) {
int width, height;
unsigned char* data = stbi_load(path.data(), &width, &height, nullptr, 4);
auto ref = addImage(data, name, base, width, height);
sptr<AtlasRef> TextureAtlas::loadImage(const string& path, const string& name, bool base) {
i32 width, height;
u8* data = stbi_load(path.data(), &width, &height, nullptr, 4);
let ref = addImage(name, base, u16vec2(width, height), data);
free(data);
return ref;
}
void TextureAtlas::update() {
auto it = textures.cbegin();
while (it != textures.cend()) {
auto curr = it++;
if (!curr->second->base && curr->second.unique()) {
deleteImage(curr->second);
textures.erase(curr);
for (let it = textures.begin(); it != textures.end();) {
if (!it->second->base && it->second.unique()) {
deleteImage(it->second);
it = textures.erase(it);
}
else it++;
}
}
glm::vec4 TextureAtlas::sampleTexturePixel(const std::shared_ptr<AtlasRef>& atlasRef, glm::vec2 pixel) {
glm::vec2 absPos = { atlasRef->pos.x + pixel.x, atlasRef->pos.y + pixel.y };
unsigned int index = (static_cast<unsigned int>(absPos.y) * pixelSize.x + static_cast<unsigned int>(absPos.x)) * 4;
vec4 TextureAtlas::getPixel(const sptr<AtlasRef>& ref, ivec2 pos) {
uvec2 absPos = { ref->rawPos.x + pos.x, ref->rawPos.y + pos.y };
u32 index = (static_cast<u32>(absPos.y) * canvasSize.x + static_cast<u32>(absPos.x)) * 4;
return {
static_cast<float>(atlasData[index]) / 255.f,
static_cast<float>(atlasData[index + 1]) / 255.f,
static_cast<float>(atlasData[index + 2]) / 255.f,
static_cast<float>(atlasData[index + 3]) / 255.f,
};
return { atlasData[index] / 255.f, atlasData[index + 1] / 255.f,
atlasData[index + 2] / 255.f, atlasData[index + 3] / 255.f };
}
std::shared_ptr<AtlasRef>
TextureAtlas::addImage(unsigned char* data, const std::string& name, bool base, int texWidth, int texHeight) {
std::shared_ptr<AtlasRef> ref;
sptr<AtlasRef> TextureAtlas::addImage(const string& name, bool base, u16vec2 size, u8* data) {
sptr<AtlasRef> ref;
u16vec2 tileSize = u16vec2(glm::ceil(vec2(size) / 16.f));
if (textures.count(name) != 0) ref = textures[name];
else ref = std::make_shared<AtlasRef>();
let posOpt = findImageSpace(tileSize);
if (!posOpt) throw std::runtime_error("Failed to find space in the dynamic definition atlas.");
u16vec2 pos = *posOpt;
ref->name = name;
ref->base = base;
ref->width = texWidth;
ref->height = texHeight;
textureSlotsUsed += tileSize.x * tileSize.y;
auto tileWidth = static_cast<int>(std::ceil(texWidth / 16.0f));
auto tileHeight = static_cast<int>(std::ceil(texHeight / 16.0f));
textures.erase(name);
ref = make_shared<AtlasRef>(AtlasRef {
pos,
tileSize,
uvec2(pos) * 16u,
size,
vec4(pos.x * 16 / static_cast<f32>(canvasSize.x), pos.y * 16 / static_cast<f32>(canvasSize.y),
(pos.x * 16 + size.x) / static_cast<f32>(canvasSize.x), (pos.y * 16 + size.y) / static_cast<f32>(canvasSize.y)),
name,
base
});
if (tileWidth != ref->tileWidth || tileHeight != ref->tileHeight) {
ref->tileWidth = tileWidth;
ref->tileHeight = tileHeight;
auto space = findImageSpace(tileWidth, tileHeight);
if (space.x < 0) throw std::runtime_error("Failed to find space in the dynamic definition atlas.");
textureSlotsUsed += tileWidth * tileHeight;
ref->tileX = static_cast<int>(space.x);
ref->tileY = static_cast<int>(space.y);
ref->pos = { space.x * 16, space.y * 16, space.x * 16 + texWidth, space.y * 16 + texHeight };
ref->uv = { (space.x * 16) / pixelSize.x, (space.y * 16) / pixelSize.y,
(space.x * 16 + texWidth) / pixelSize.x, (space.y * 16 + texHeight) / pixelSize.y };
textures.insert({ name, ref });
}
textures.insert({ name, ref });
updateAtlas(ref->tileX, ref->tileY, texWidth, texHeight, data);
updateAtlas(ref->rawPos, ref->rawSize, data);
return ref;
}
std::shared_ptr<AtlasRef> TextureAtlas::generateCrackImage(const std::string& name, unsigned short crackLevel) {
sptr<AtlasRef> TextureAtlas::generateCrackImage(const string& name, u8 crackLevel) {
RawTexData base = getBytesOfTex(name);
std::string crackStr("zeus:default:crack_" + std::to_string(crackLevel));
RawTexData crack = getBytesOfTex(crackStr);
for (int i = 0; i < base.width * base.height; i++) {
for (int i = 0; i < base.size.x * base.size.y; i++) {
float alpha = crack.data[i * 4 + 3] / 255.f;
base.data[i * 4 + 0] = static_cast<unsigned char>(base.data[i * 4 + 0] * (1 - alpha) +
crack.data[i * 4 + 0] * alpha);
base.data[i * 4 + 1] = static_cast<unsigned char>(base.data[i * 4 + 1] * (1 - alpha) +
crack.data[i * 4 + 1] * alpha);
base.data[i * 4 + 2] = static_cast<unsigned char>(base.data[i * 4 + 2] * (1 - alpha) +
crack.data[i * 4 + 2] * alpha);
base.data[i * 4 + 0] = static_cast<u8>(base.data[i * 4 + 0] * (1 - alpha) + crack.data[i * 4 + 0] * alpha);
base.data[i * 4 + 1] = static_cast<u8>(base.data[i * 4 + 1] * (1 - alpha) + crack.data[i * 4 + 1] * alpha);
base.data[i * 4 + 2] = static_cast<u8>(base.data[i * 4 + 2] * (1 - alpha) + crack.data[i * 4 + 2] * alpha);
}
auto ref = addImage(base.data, name + "_crack_" + std::to_string(crackLevel), false, base.width, base.height);
auto ref = addImage(name + "_crack_" + std::to_string(crackLevel), false, base.size, base.data);
delete[] base.data;
delete[] crack.data;
@ -159,16 +131,16 @@ std::shared_ptr<AtlasRef> TextureAtlas::generateCrackImage(const std::string& na
return ref;
}
std::shared_ptr<AtlasRef> TextureAtlas::operator[](const std::string& name) {
sptr<AtlasRef> TextureAtlas::operator[](const string& name) {
if (textures.count(name)) return textures[name];
std::shared_ptr<AtlasRef> gen = generateTexture(name);
sptr<AtlasRef> gen = generateTexture(name);
if (gen) return gen;
throw std::runtime_error("Invalid texture: '" + name + "'");
}
std::shared_ptr<AtlasRef> TextureAtlas::generateTexture(std::string req) {
sptr<AtlasRef> TextureAtlas::generateTexture(string req) {
req.erase(std::remove(req.begin(), req.end(), ' '), req.end());
if (req.find_first_of('(') != std::string::npos) {
@ -176,15 +148,15 @@ std::shared_ptr<AtlasRef> TextureAtlas::generateTexture(std::string req) {
throw std::runtime_error("Mismatched braces.");
}
std::string::size_type paramsBegin = req.find_first_of('(');
std::string::size_type paramsEnd = req.find_last_of(')');
string::size_type paramsBegin = req.find_first_of('(');
string::size_type paramsEnd = req.find_last_of(')');
std::string paramName = req.substr(0, paramsBegin);
std::string paramsString = req.substr(paramsBegin + 1, paramsEnd - paramsBegin - 1);
string paramName = req.substr(0, paramsBegin);
string paramsString = req.substr(paramsBegin + 1, paramsEnd - paramsBegin - 1);
std::vector<std::string> params;
std::string::size_type pos;
while ((pos = paramsString.find(',')) != std::string::npos) {
vec<string> params;
string::size_type pos;
while ((pos = paramsString.find(',')) != string::npos) {
params.push_back(paramsString.substr(0, pos));
paramsString.erase(0, pos + 1);
}
@ -192,26 +164,26 @@ std::shared_ptr<AtlasRef> TextureAtlas::generateTexture(std::string req) {
if (paramName == "crop") {
if (params.size() != 5) throw std::runtime_error("crop() requires 5 parameters.");
glm::ivec4 loc = { atof(params[0].data()), atof(params[1].data()), atof(params[2].data()),
atof(params[3].data()) };
std::shared_ptr<AtlasRef> src = operator[](params[4]);
uvec2 pos = { atoi(params[0].data()), atoi(params[1].data()) };
uvec2 size = { atoi(params[2].data()), atoi(params[3].data()) };
sptr<AtlasRef> src = operator[](params[4]);
auto data = getBytesAtPos({ src->pos.x + loc.x, src->pos.y + loc.y }, { loc.z, loc.w }).data;
return addImage(data, req, false, loc.z, loc.w);
let data = getBytesAtPos(src->rawPos + pos, size).data;
return addImage(req, false, size, data);
}
else if (paramName == "multiply") {
if (params.size() != 2) throw std::runtime_error("multiply() requires 2 parameters.");
vec4 multiple = Util::hexToColorVec(params[1]);
auto tex = getBytesOfTex(params[0]);
for (int i = 0; i < tex.width * tex.height; i++) {
for (int i = 0; i < tex.size.x * tex.size.y; i++) {
tex.data[i * 4 + 0] *= multiple.x;
tex.data[i * 4 + 1] *= multiple.y;
tex.data[i * 4 + 2] *= multiple.z;
tex.data[i * 4 + 3] *= multiple.w;
}
return addImage(tex.data, req, false, tex.width, tex.height);
return addImage(req, false, tex.size, tex.data);
}
else {
throw std::runtime_error("Invalid parameter.");
@ -221,48 +193,44 @@ std::shared_ptr<AtlasRef> TextureAtlas::generateTexture(std::string req) {
return nullptr;
}
TextureAtlas::RawTexData TextureAtlas::getBytesOfTex(const std::string& name) {
glm::vec4 pos;
TextureAtlas::RawTexData TextureAtlas::getBytesOfTex(const string& name) {
let it = textures.find(name);
if (it != textures.end()) return getBytesAtPos(it->second->rawPos, it->second->rawSize);
if (textures.count(name)) pos = textures[name]->pos;
else {
std::cout << Log::err << "Invalid base texture \"" << name << "\"." << Log::endl;
pos = textures["_missing"]->pos;
}
return getBytesAtPos({ pos.x, pos.y }, { pos.z - pos.x, pos.w - pos.y });
std::cout << Log::err << "Invalid base texture '" << name << "'." << Log::endl;
let& missing = textures["_missing"];
return getBytesAtPos(missing->rawPos, missing->rawSize);
}
TextureAtlas::RawTexData TextureAtlas::getBytesAtPos(glm::ivec2 pos, glm::ivec2 dims) {
RawTexData data{};
data.width = dims.x;
data.height = dims.y;
TextureAtlas::RawTexData TextureAtlas::getBytesAtPos(uvec2 pos, uvec2 size) {
RawTexData data {};
data.size = size;
auto pixels = new unsigned char[data.width * data.height * 4];
let pixels = new u8[size.x * size.y * 4];
for (int i = 0; i < data.width * data.height; i++) {
int xx = pos.x + (i % data.width);
int yy = pos.y + (i / data.width);
for (u32 i = 0; i < size.x * size.y; i++) {
u32 x = pos.x + (i % size.x);
u32 y = pos.y + (i / size.y);
pixels[i * 4 + 0] = atlasData[xx * 4 + yy * (pixelSize.x * 4)];
pixels[i * 4 + 1] = atlasData[xx * 4 + 1 + yy * (pixelSize.x * 4)];
pixels[i * 4 + 2] = atlasData[xx * 4 + 2 + yy * (pixelSize.x * 4)];
pixels[i * 4 + 3] = atlasData[xx * 4 + 3 + yy * (pixelSize.x * 4)];
pixels[i * 4 + 0] = atlasData[x * 4 + y * (canvasSize.x * 4)];
pixels[i * 4 + 1] = atlasData[x * 4 + 1 + y * (canvasSize.x * 4)];
pixels[i * 4 + 2] = atlasData[x * 4 + 2 + y * (canvasSize.x * 4)];
pixels[i * 4 + 3] = atlasData[x * 4 + 3 + y * (canvasSize.x * 4)];
}
data.data = pixels;
return data;
}
glm::vec2 TextureAtlas::findImageSpace(int w, int h) {
for (int j = 0; j < tileSize.y - (h - 1); j++) {
for (int i = 0; i < tileSize.x - (w - 1); i++) {
if (empty[j * tileSize.x + i]) {
optional<u16vec2> TextureAtlas::findImageSpace(u16vec2 tileSize) {
for (u16 j = 0; j < canvasTileSize.y - (tileSize.y - 1); j++) {
for (u16 i = 0; i < canvasTileSize.x - (tileSize.x - 1); i++) {
if (empty[j * canvasTileSize.x + i]) {
bool space = true;
for (int k = 0; k < h; k++) {
for (int l = 0; l < w; l++) {
if (!empty[(j + k) * tileSize.x + (i + l)]) {
for (int k = 0; k < tileSize.y; k++) {
for (int l = 0; l < tileSize.x; l++) {
if (!empty[(j + k) * canvasTileSize.x + (i + l)]) {
space = false;
break;
}
@ -272,25 +240,25 @@ glm::vec2 TextureAtlas::findImageSpace(int w, int h) {
}
if (space) {
for (int k = 0; k < h; k++) {
for (int l = 0; l < w; l++) {
empty[(j + k) * tileSize.x + (i + l)] = false;
for (int k = 0; k < tileSize.y; k++) {
for (int l = 0; l < tileSize.x; l++) {
empty[(j + k) * canvasTileSize.x + (i + l)] = false;
}
}
return glm::vec2(i, j);
return u16vec2(i, j);
}
}
}
}
return glm::vec2(-1, -1);
return {};
}
void TextureAtlas::createMissingImage() {
auto data = new unsigned char[16 * 4 * 16];
for (int i = 0; i < 16 * 16; i++) {
void TextureAtlas::createMissingTexture() {
auto data = new u8[16 * 4 * 16];
for (u16 i = 0; i < 16 * 16; i++) {
unsigned char m = 0;
u8 m = 0;
if ((i % 16 < 8) ^ ((i / 16) < 8)) m = 255;
data[i * 4 + 0] = m;
@ -299,26 +267,23 @@ void TextureAtlas::createMissingImage() {
data[i * 4 + 3] = 255;
}
addImage(data, "_missing", true, 16, 16);
addImage("_missing", true, u16vec2(16), data);
delete[] data;
}
void TextureAtlas::updateAtlas(int tileX, int tileY, int texWidth, int texHeight, unsigned char* data) {
int baseX = tileX * 16;
int baseY = tileY * 16;
void TextureAtlas::updateAtlas(u16vec2 pos, u16vec2 size, u8* data) {
texture.updateTexture(pos.x, pos.y, size.x, size.y, data);
atlasTexture.updateTexture(baseX, baseY, texWidth, texHeight, data);
for (int i = 0; i < texWidth * texHeight * 4; i++) {
int xx = (i / 4) % texWidth;
int yy = (i / 4) / texWidth;
int of = i % 4;
for (u32 i = 0; i < size.x * size.y * 4; i++) {
u32 x = (i / 4) % size.x;
u32 y = (i / 4) / size.x;
u32 of = i % 4;
atlasData[(baseX + xx + (baseY + yy) * pixelSize.x) * 4 + of] = data[(xx + yy * texWidth) * 4 + of];
atlasData[(pos.x + x + (pos.y + y) * canvasSize.x) * 4 + of] = data[(x + y * size.x) * 4 + of];
}
}
void TextureAtlas::deleteImage(std::shared_ptr<AtlasRef> ref) {
void TextureAtlas::deleteImage(sptr<AtlasRef> ref) {
// Actually delete the image from the texture (for debugging)
//auto data = new unsigned char[ref->width * ref->height * 4];
@ -330,11 +295,11 @@ void TextureAtlas::deleteImage(std::shared_ptr<AtlasRef> ref) {
//updateAtlas(ref->tileX, ref->tileY, ref->width, ref->height, data);
//delete[] data;
textureSlotsUsed -= ref->tileWidth * ref->tileHeight;
textureSlotsUsed -= ref->size.x * ref->size.y;
for (float i = ref->tileX; i < ref->tileX + ref->tileWidth; i++) {
for (float j = ref->tileY; j < ref->tileY + ref->tileHeight; j++) {
empty[j * tileSize.x + i] = true;
for (u32 x = ref->pos.x; x < ref->pos.x + ref->size.x; x++) {
for (u32 y = ref->pos.y; y < ref->pos.y + ref->size.y; y++) {
empty[y * canvasTileSize.x + x] = true;
}
}
}

View File

@ -1,71 +1,59 @@
//
// Created by aurailus on 16/04/19.
//
#pragma once
#include <map>
#include <memory>
#include <vector>
#include <glm/vec2.hpp>
#include <glm/vec4.hpp>
#include <unordered_map>
#include "util/Types.h"
#include "client/graph/Texture.h"
class AtlasRef;
class TextureAtlas {
public:
struct RawTexData {
unsigned char* data;
int width;
int height;
};
public:
struct RawTexData { u8* data; uvec2 size; };
TextureAtlas() = default;
explicit TextureAtlas(unsigned int width, unsigned int height = 0);
explicit TextureAtlas(uvec2 size);
void update();
std::vector<std::shared_ptr<AtlasRef>>
loadDirectory(const std::string& path, bool base = true, bool recursive = true);
vec<sptr<AtlasRef>> loadDirectory(const string& path, bool base = true, bool recurse = true);
std::shared_ptr<AtlasRef> loadImage(const std::string& path, const std::string& name, bool base = false);
sptr<AtlasRef> loadImage(const string& path, const string& name, bool base = false);
glm::vec4 sampleTexturePixel(const std::shared_ptr<AtlasRef>& atlasRef, glm::vec2 pixel);
sptr<AtlasRef> addImage(const string& name, bool base, u16vec2 size, u8* data);
std::shared_ptr<AtlasRef> operator[](const std::string& name);
sptr<AtlasRef> operator[](const string& name);
std::shared_ptr<AtlasRef>
addImage(unsigned char* data, const std::string& name, bool base, int texWidth, int texHeight);
vec4 getPixel(const sptr<AtlasRef>& ref, ivec2 pos);
std::shared_ptr<AtlasRef> generateCrackImage(const std::string& name, unsigned short crackLevel);
sptr<AtlasRef> generateCrackImage(const string& name, u8 crackLevel);
glm::ivec2 pixelSize{};
glm::ivec2 tileSize{};
ivec2 canvasSize;
ivec2 canvasTileSize;
Texture atlasTexture{};
std::vector<unsigned char> atlasData;
Texture texture {};
vec<u8> atlasData;
unsigned int textureSlotsUsed = 0;
unsigned int maxTextureSlots = 0;
private:
std::shared_ptr<AtlasRef> generateTexture(std::string req);
u32 textureSlotsUsed = 0;
u32 maxTextureSlots = 0;
private:
sptr<AtlasRef> generateTexture(string req);
RawTexData getBytesOfTex(const std::string& name);
RawTexData getBytesOfTex(const string& name);
RawTexData getBytesAtPos(glm::ivec2 pos, glm::ivec2 dims);
RawTexData getBytesAtPos(uvec2 pos, uvec2 size);
glm::vec2 findImageSpace(int w, int h);
optional<u16vec2> findImageSpace(u16vec2 tileSize);
void createMissingImage();
void createMissingTexture();
void updateAtlas(int tileX, int tileY, int texWidth, int texHeight, unsigned char* data);
void updateAtlas(u16vec2 pos, u16vec2 size, u8* data);
void deleteImage(std::shared_ptr<AtlasRef> ref);
void deleteImage(sptr<AtlasRef> ref);
std::map<std::string, std::shared_ptr<AtlasRef>> textures;
std::vector<bool> empty;
vec<bool> empty;
std::unordered_map<string, sptr<AtlasRef>> textures;
};

View File

@ -4,22 +4,16 @@
#pragma once
#include <string>
#include <glm/glm.hpp>
#include "util/Util.h"
struct AtlasRef {
int tileX = 0;
int tileY = 0;
int tileWidth = 0;
int tileHeight = 0;
u16vec2 pos {};
u16vec2 size {};
uvec2 rawPos {};
uvec2 rawSize {};
vec4 uv {};
string name = "";
bool base = false;
glm::vec4 pos{};
glm::vec4 uv{};
std::string name = "";
int width = 0;
int height = 0;
};

View File

@ -44,11 +44,11 @@ void CraftItemDef::createModel(TextureAtlas& atlas) {
for (unsigned int i = 0; i < 16 * 16; i++) {
glm::vec2 samplePos = { i % 16, i / 16 };
glm::vec2 off{ samplePos.x / 16.f, samplePos.y / 16.f };
glm::vec4 col = atlas.sampleTexturePixel(ref, samplePos);
glm::vec4 col = atlas.getPixel(ref, samplePos);
if (col.w < 0.5) continue;
if (samplePos.y == 0 || atlas.sampleTexturePixel(ref, { samplePos.x, samplePos.y - 1 }).w < 0.5) {
if (samplePos.y == 0 || atlas.getPixel(ref, { samplePos.x, samplePos.y - 1 }).w < 0.5) {
std::vector<EntityVertex> myVerts = {
{{ -xo, 0.5 - off.y, -0.5 + off.x }, col, { 1, 1, 1 }, false, { 0, 1, 0 }, {}, {}},
{{ -xo, 0.5 - off.y, -0.5 + off.x + 0.0625 }, col, { 1, 1, 1 }, false, { 0, 1, 0 }, {}, {}},
@ -61,7 +61,7 @@ void CraftItemDef::createModel(TextureAtlas& atlas) {
indOffset += 4;
}
if (samplePos.y == 15 || atlas.sampleTexturePixel(ref, { samplePos.x, samplePos.y + 1 }).w < 0.5) {
if (samplePos.y == 15 || atlas.getPixel(ref, { samplePos.x, samplePos.y + 1 }).w < 0.5) {
std::vector<EntityVertex> myVerts = {
{{ -xo, 0.5 - off.y - 0.0625, -0.5 + off.x }, col, { 1, 1, 1 }, false, { 0, -1, 0 }, {}, {}},
{{ -xo, 0.5 - off.y - 0.0625, -0.5 + off.x + 0.0625 }, col, { 1, 1, 1 }, false, { 0, -1, 0 }, {}, {}},
@ -74,7 +74,7 @@ void CraftItemDef::createModel(TextureAtlas& atlas) {
indOffset += 4;
}
if (samplePos.x == 0 || atlas.sampleTexturePixel(ref, { samplePos.x - 1, samplePos.y }).w < 0.5) {
if (samplePos.x == 0 || atlas.getPixel(ref, { samplePos.x - 1, samplePos.y }).w < 0.5) {
std::vector<EntityVertex> myVerts = {
{{ -xo, 0.5 - off.y - 0.0625, -0.5 + off.x }, col, { 1, 1, 1 }, false, { 0, 0, 1 }, {}, {}},
{{ -xo, 0.5 - off.y, -0.5 + off.x }, col, { 1, 1, 1 }, false, { 0, 0, 1 }, {}, {}},
@ -87,7 +87,7 @@ void CraftItemDef::createModel(TextureAtlas& atlas) {
indOffset += 4;
}
if (samplePos.x == 15 || atlas.sampleTexturePixel(ref, { samplePos.x + 1, samplePos.y }).w < 0.5) {
if (samplePos.x == 15 || atlas.getPixel(ref, { samplePos.x + 1, samplePos.y }).w < 0.5) {
std::vector<EntityVertex> myVerts = {
{{ -xo, 0.5 - off.y - 0.0625, -0.5 + off.x + 0.0625 }, col, { 1, 1, 1 }, false, { 0, 0, -1 }, {}, {}},
{{ -xo, 0.5 - off.y, -0.5 + off.x + 0.0625 }, col, { 1, 1, 1 }, false, { 0, 0, -1 }, {}, {}},

View File

@ -5,30 +5,30 @@
#include "LocalLuaParser.h"
#include "client/Client.h"
#include "ErrorFormatter.h"
#include "lua/ModException.h"
#include "register/RegisterItem.h"
#include "register/RegisterBlock.h"
#include "register/RegisterBiome.h"
#include "register/RegisterKeybind.h"
#include "lua/ErrorFormatter.h"
#include "lua/register/RegisterItem.h"
#include "lua/register/RegisterBlock.h"
#include "lua/register/RegisterBiome.h"
#include "lua/register/RegisterKeybind.h"
// Usertypes
#include "usertype/Target.h"
#include "usertype/Player.h"
#include "usertype/Entity.h"
#include "usertype/Inventory.h"
#include "usertype/Dimension.h"
#include "usertype/ItemStack.h"
#include "usertype/InventoryList.h"
#include "usertype/AnimationManager.h"
#include "usertype/GuiElement.h"
#include "lua/usertype/Target.h"
#include "lua/usertype/Player.h"
#include "lua/usertype/Entity.h"
#include "lua/usertype/Inventory.h"
#include "lua/usertype/Dimension.h"
#include "lua/usertype/ItemStack.h"
#include "lua/usertype/GuiElement.h"
#include "lua/usertype/KeyObserver.h"
#include "lua/usertype/InventoryList.h"
#include "lua/usertype/AnimationManager.h"
// Modules
#include "modules/Time.h"
#include "modules/Message.h"
#include "modules/Dimension.h"
#include "modules/Structure.h"
#include "lua/modules/Time.h"
#include "lua/modules/Message.h"
#include "lua/modules/Dimension.h"
#include "lua/modules/Structure.h"
// Util
#include "lua/register/CreateRegister.h"
@ -37,9 +37,10 @@ LocalLuaParser::LocalLuaParser(LocalSubgame& game) : LuaParser(game) {}
void LocalLuaParser::init(WorldPtr world, PlayerPtr player, Client& client) {
this->client = &client;
this->player = player;
lua.open_libraries(sol::lib::base, sol::lib::string, sol::lib::math, sol::lib::table, sol::lib::debug);
loadApi(world, player);
loadApi(world);
try {
runFileSandboxed("base/init");
@ -87,8 +88,6 @@ void LocalLuaParser::init(WorldPtr world, PlayerPtr player, Client& client) {
throw ModException(err);
}
// client.renderer.window.input.setCallback(Util::bind_this(&keybinds, &LuaKeybindHandler::keybindHandler));
}
void LocalLuaParser::update(double delta) {
@ -108,7 +107,17 @@ void LocalLuaParser::setModLoadOrder(const vec<string> order) {
modLoadOrder = order;
}
void LocalLuaParser::loadApi(WorldPtr world, PlayerPtr player) {
void LocalLuaParser::addKBObserver(usize id) {
kbObservers.emplace(id);
player.l()->setKBIndicatorVisible(true);
}
void LocalLuaParser::removeKBObserver(usize id) {
kbObservers.erase(id);
player.l()->setKBIndicatorVisible(kbObservers.size());
}
void LocalLuaParser::loadApi(WorldPtr world) {
//Create Zepha Table
core = lua.create_table();
lua["zepha"] = core;
@ -124,6 +133,7 @@ void LocalLuaParser::loadApi(WorldPtr world, PlayerPtr player) {
Api::Usertype::GuiElement::bind(lua, core, player.l()->getRoot());
Api::Usertype::InventoryList::bind(Api::State::CLIENT, lua, core);
Api::Usertype::LocalAnimationManager::bind(Api::State::CLIENT, lua, core);
Api::Usertype::KeyObserver::bind(lua, core, client->renderer.window.input, *this);
core["client"] = true;
core["player"] = Api::Usertype::LocalPlayer(player);
@ -191,4 +201,4 @@ sol::protected_function_result LocalLuaParser::runFileSandboxed(const std::strin
return res;
}
throw std::runtime_error("Error opening \"" + file + "\", file not found.");
}
}

View File

@ -4,6 +4,7 @@
#pragma once
#include <unordered_set>
#include <unordered_map>
#include "lua/LuaParser.h"
@ -30,15 +31,21 @@ public:
void setModLoadOrder(const vec<string> order);
void addKBObserver(usize id);
void removeKBObserver(usize id);
private:
void loadApi(WorldPtr world, PlayerPtr player);
void loadApi(WorldPtr world);
sol::protected_function_result runFileSandboxed(const std::string& file);
Client* client;
PlayerPtr player;
double accumulatedDelta = 0;
vec<CallbackRef> refs;
vec<string> modLoadOrder {};
std::unordered_set<usize> kbObservers {};
std::unordered_map<string, LuaMod> mods {};
};

View File

@ -4,10 +4,10 @@
#include <sstream>
#include <fstream>
#include <nlohmann/json.hpp>
#include <gzip/compress.hpp>
#include <stb_image.h>
#include <cute_files.h>
#include <gzip/compress.hpp>
#include <nlohmann/json.hpp>
#include "ServerModHandler.h"

View File

@ -1,7 +1,6 @@
#pragma once
#include "lua/Lua.h"
#include "util/Types.h"
namespace Gui {

View File

@ -0,0 +1,41 @@
#include <GLFW/glfw3.h>
#include "KeyObserver.h"
#include "client/Input.h"
#include "lua/LocalLuaParser.h"
usize Api::Usertype::KeyObserver::ID_NEXT = 0;
void Api::Usertype::KeyObserver::start() {
if (nativeCBs.size()) return;
parser.addKBObserver(id);
nativeCBs.emplace_back(input.events.bind(Input::CBType::KEY, [&](i32 key, u32 state) {
if (state == GLFW_PRESS && on_press) on_press(key);
else if (state == GLFW_RELEASE && on_release) on_release(key);
}));
}
void Api::Usertype::KeyObserver::stop() {
parser.removeKBObserver(id);
nativeCBs.clear();
}
Api::Usertype::KeyObserver::~KeyObserver() {
stop();
}
void Api::Usertype::KeyObserver::bind(sol::state& lua, sol::table& core, Input& input, LocalLuaParser& parser) {
lua.new_usertype<KeyObserver>("KeyObserver",
sol::meta_function::construct, sol::factories([&]() {
return make_shared<KeyObserver>(input, parser);
}),
"start", &KeyObserver::start,
"stop", &KeyObserver::stop,
"on_press", &KeyObserver::on_press,
"on_release", &KeyObserver::on_release,
"on_change", &KeyObserver::on_change
);
}

View File

@ -0,0 +1,39 @@
#pragma once
#include "lua/Lua.h"
#include "util/Types.h"
#include "client/Callback.h"
class Input;
class LocalLuaParser;
namespace Api::Usertype {
class KeyObserver {
public:
KeyObserver(Input& input, LocalLuaParser& parser): input(input), parser(parser), id(ID_NEXT++) {}
~KeyObserver();
void start();
void stop();
static void bind(sol::state& lua, sol::table& core, Input& input, LocalLuaParser& parser);
private:
sol::protected_function on_press = sol::nil;
sol::protected_function on_release = sol::nil;
sol::protected_function on_change = sol::nil;
vec<CallbackRef> nativeCBs {};
usize id = 0;
bool active = false;
Input& input;
LocalLuaParser& parser;
static usize ID_NEXT;
};
}

View File

@ -9,7 +9,7 @@
/** Checks if boxes or points are within the camera's frustum cone. */
class Frustum {
private:
enum class Direction : uint8_t {
enum class Direction : u8 {
TOP = 0,
BOTTOM,
LEFT,

View File

@ -79,7 +79,7 @@ void NetHandler::initClient(Address hostAddress, int attempts, int timeout) {
ENetEvent event;
if (enet_host_service(host, &event, (enet_uint32) timeout) > 0 && event.type == ENET_EVENT_TYPE_CONNECT) {
std::cout << Log::info << "Connected to "
<< NetHandler::intToIPString(*reinterpret_cast<unsigned int*>(&event.peer->address.host))
<< NetHandler::intToIPString(*reinterpret_cast<u32*>(&event.peer->address.host))
<< ":" << event.peer->address.port << "." << Log::endl;
state = NetState::CLIENT;
break;

View File

@ -18,8 +18,8 @@ std::tuple<glm::vec3, glm::vec3> Collision::applyVel(SubgamePtr game, DimensionP
const SelectionBox& collisionBox, glm::vec3 pos, glm::vec3 vel, float delta) {
constexpr static double INC = 0.05;
for (unsigned char i = 0; i < 3; i++) {
for (int j = 0; j < std::abs(vel[i] * delta) / INC; j++) {
for (u8 i = 0; i < 3; i++) {
for (u32 j = 0; j < std::abs(vel[i] * delta) / INC; j++) {
double moveAmount = std::max(std::min(INC, std::abs(vel[i] * delta) - (j * INC)), 0.);
glm::vec3 newPos = pos;

View File

@ -14,9 +14,7 @@
#include "world/dim/chunk/Chunk.h"
#include "game/atlas/DefinitionAtlas.h"
#ifndef M_PI
# define M_PI 3.14159265358979323846 /* pi */
#endif
#define M_PI 3.14159265358979323846
MapGen::MapGen(Subgame& game, World& world, u32 seed, std::unordered_set<string> biomes) :
game(game), world(world), props(seed) {

View File

@ -1,10 +1,6 @@
//
// Created by aurailus on 2020-04-05.
//
#include "MapGenProps.h"
MapGenProps::MapGenProps(unsigned int seed) : seed(seed) {
MapGenProps::MapGenProps(u32 seed) : seed(seed) {
/*temperatureBase.SetSeed(seed);
temperatureBase.SetFrequency(0.02);
temperatureBase.SetOctaveCount(4);

View File

@ -1,26 +1,10 @@
//
// Created by aurailus on 2020-04-05.
//
#pragma once
//#include <libnoise/noise.h>
#include "util/Util.h"
class MapGenProps {
public:
MapGenProps(unsigned int seed);
public:
MapGenProps(u32 seed);
unsigned int seed;
/*noise::module::Perlin temperatureBase;
noise::module::Turbulence temperatureTurbulence;
noise::module::ScaleBias temperature;
noise::module::Perlin humidityBase;
noise::module::Turbulence humidityTurbulence;
noise::module::ScaleBias humidity;
noise::module::Perlin roughnessBase;
noise::module::Turbulence roughnessTurbulence;
noise::module::ScaleBias roughness;*/
u32 seed;
};

View File

@ -20,6 +20,13 @@ LocalPlayer::LocalPlayer(SubgamePtr game, LocalWorld& world, DimensionPtr dim, R
hud(root.body->append<Gui::BoxElement>({{ { Gui::Prop::CLASS, vec<string> { "_GUI_ROOT" } } }})),
menu(root.body->append<Gui::BoxElement>({{ { Gui::Prop::CLASS, vec<string> { "_GUI_ROOT" } } }})),
debug(root.body->append<Gui::BoxElement>({{ { Gui::Prop::CLASS, vec<string> { "_GUI_ROOT" } } }})),
indicators(root.body->append<Gui::BoxElement>({{ { Gui::Prop::CLASS, vec<string> { "_GUI_ROOT" } } }})),
kbIndicator(indicators->append<Gui::BoxElement>({{
{ Gui::Prop::VISIBLE, false },
{ Gui::Prop::BACKGROUND, string("key_observing") },
{ Gui::Prop::POS, array<Gui::Expression, 2> { Gui::Expression("100cw - 100sw - 2dp"), Gui::Expression("100ch - 100sh - 2dp") } },
{ Gui::Prop::SIZE, array<Gui::Expression, 2> { Gui::Expression("20px * 2"), Gui::Expression("16px * 2") } }
}})),
wireframe(game, dim, { 1, 1, 1 }),
renderer(renderer) {
handItemModel.parent = &handModel;
@ -30,6 +37,10 @@ LocalPlayer::LocalPlayer(SubgamePtr game, LocalWorld& world, DimensionPtr dim, R
{ Gui::Prop::SIZE, array<Gui::Expression, 2> { Gui::Expression("100cw"), Gui::Expression("100ch") }}
}}}
});
debug->setProp(Gui::Prop::VISIBLE, false);
indicators->append<Gui::BoxElement>();
}
void LocalPlayer::update(f64 delta, vec2 mouseDelta) {
@ -48,8 +59,7 @@ void LocalPlayer::update(f64 delta, vec2 mouseDelta) {
findTarget();
updateWireframe();
// if (!gameGui.isInMenu())
updateInteract(delta);
if (!isInMenu()) updateInteract(delta);
}
string LocalPlayer::getUsername() {
@ -139,6 +149,11 @@ void LocalPlayer::setHudVisible(bool visible) {
// gameGui.setVisible(hudVisible);
}
void LocalPlayer::setKBIndicatorVisible(bool visible) {
kbIndicator->setProp(Gui::Prop::VISIBLE, visible);
kbIndicator->updateElement();
}
void LocalPlayer::draw(Renderer&) {
wireframe.draw(renderer);
handItemModel.draw(renderer);
@ -151,6 +166,7 @@ void LocalPlayer::drawHud(Renderer&) {
void LocalPlayer::drawMenu(Renderer&) {
menu->draw(renderer);
indicators->draw(renderer);
}
void LocalPlayer::assertField(Packet packet) {
@ -222,6 +238,7 @@ void LocalPlayer::handleAssertion(Deserializer& d) {
}
bool LocalPlayer::getKey(LocalPlayer::PlayerControl control) {
if (isInMenu()) return false;
return renderer.window.input.isKeyDown(
control == PlayerControl::FORWARD ? GLFW_KEY_COMMA :
control == PlayerControl::BACKWARD ? GLFW_KEY_O :

View File

@ -80,6 +80,9 @@ public:
/** Sets whether or not the hud should be visible. */
void setHudVisible(bool visible);
/** Sets whether or not the KBIndicator is visible. */
void setKBIndicatorVisible(bool visible);
/** Draws the player's target wireframe and held item. */
void draw(Renderer& renderer) override;
@ -122,7 +125,7 @@ private:
Gui::Root root;
/** Element roots for the hud and menu, respectively. */
sptr<Gui::BoxElement> hud, menu, debug;
sptr<Gui::BoxElement> hud, menu, debug, indicators, kbIndicator;
/** A reference to the renderer. */
Renderer& renderer;

View File

@ -24,13 +24,42 @@ local chat_menu = zepha.Gui.Box {
zepha.Gui.Box {
id = 'chat_input',
size = { '256dp', '10dp' },
pos = { '0dp', 3 + max_messages * 8 .. 'dp' }
pos = { '0dp', 3 + max_messages * 8 .. 'dp' },
zepha.Gui.Text {
id = 'chat_input_text',
pos = '2dp',
text_size = '2px',
content = ''
}
}
}
local chat_menu_box = chat_menu:get('chat_box')
local chat_menu_tabs = chat_menu:get('chat_tabs')
local chat_menu_input = chat_menu:get('chat_input')
local chat_menu_input_text = chat_menu:get('chat_input_text')
local chat_buffer = ''
local pipe = '`r` `c1|'
local has_pipe = false
local observer = KeyObserver.new()
observer.on_press = function(keycode)
local key = zepha.keycodes[keycode]
if key == 'enter' then return
elseif key == 'space' then chat_buffer = chat_buffer .. ' '
elseif key == 'backspace' then chat_buffer = chat_buffer:sub(1, chat_buffer:len() - 1)
else chat_buffer = chat_buffer .. key end
chat_menu_input_text.content = chat_buffer .. (has_pipe and pipe or '')
end
zepha.after(function()
if not chat.open then return true end
has_pipe = not has_pipe
chat_menu_input_text.content = chat_buffer .. (has_pipe and pipe or '')
return true
end, 0.5)
-- Rerenders the chat gui.
chat._refresh = function()
@ -104,6 +133,13 @@ chat.set_open = function(open)
if open == nil then chat.open = not chat.open
else chat.open = open end
if chat.open then
observer:start()
else
observer:stop()
chat_buffer = ''
end
zepha.player.menu = chat.open and chat_menu or nil
chat._refresh()
@ -113,5 +149,19 @@ end
zepha.register_keybind(":open_chat", {
description = "Open Chat",
default = zepha.keys.p,
on_press = chat.set_open
on_press = function()
if chat.open then return end
chat.set_open()
end
})
-- Keyboard shortcut to send the message
zepha.register_keybind(":send_message", {
description = "Send Message",
default = zepha.keys.enter,
on_press = function()
if not chat.open then return end
chat.send(chat_buffer)
chat.set_open()
end
})

View File

@ -1,12 +1,13 @@
zepha.register_block(":wood", {
name = "Log",
model = "base:block",
model = "base:pillar",
textures = {
"zeus:default:oak_log_top",
"zeus:default:oak_log_top",
"zeus:default:oak_log_side"
"zeus:default:oak_log_side_pillar"
},
culls = false,
tool_props = {
health = 30,

View File

@ -1,13 +1,6 @@
require(_PATH .. "blocks/index")
require(_PATH .. "entity/index")
local chat_down = false
zepha.register_keybind("zeus:default:open_chat", {
description = "Open Chat",
default = zepha.keys.t,
on_press = function() print "Opened chat!" end
})
-- Flying toggles
local function toggleFlying()
zepha.player.flying = not zepha.player.flying
@ -19,7 +12,7 @@ zepha.register_keybind("zeus:default:toggle_flying", {
on_press = toggleFlying
})
local last_press = -100
local last_press = -1
zepha.register_keybind("zeus:default:double_jump_fly", {
description = "Double Jump to Toggle Flying",
default = zepha.keys.space,