This commit is contained in:
2025-02-16 21:36:05 +06:00
parent dce0272653
commit 133782b185
18 changed files with 698 additions and 409 deletions

1
.gitignore vendored
View File

@@ -11,3 +11,4 @@
/cmake_install.cmake /cmake_install.cmake
/libassets.a /libassets.a
/resources.cpp /resources.cpp
/imgui.ini

View File

@@ -1,8 +1,18 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdata-sections -ffunction-sections") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdata-sections -ffunction-sections -DGLM_FORCE_DEPTH_ZERO_TO_ONE")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -UNDEBUG") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -UNDEBUG")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") # -rdynamic set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") # -rdynamic
# gprof
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg")
# set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg")
# sanitizer
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment")
project (LuaVox VERSION 0.0 DESCRIPTION "LuaVox Description") project (LuaVox VERSION 0.0 DESCRIPTION "LuaVox Description")
add_executable(${PROJECT_NAME}) add_executable(${PROJECT_NAME})
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_20) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_20)
@@ -11,20 +21,41 @@ file(GLOB_RECURSE SOURCES RELATIVE ${PROJECT_SOURCE_DIR} "Src/*.cpp")
target_sources(${PROJECT_NAME} PRIVATE ${SOURCES}) target_sources(${PROJECT_NAME} PRIVATE ${SOURCES})
target_include_directories(${PROJECT_NAME} PUBLIC "${PROJECT_SOURCE_DIR}/Src") target_include_directories(${PROJECT_NAME} PUBLIC "${PROJECT_SOURCE_DIR}/Src")
include(FetchContent)
# Boost # Boost
if(POLICY CMP0167) if(POLICY CMP0167)
cmake_policy(SET CMP0167 NEW) cmake_policy(SET CMP0167 NEW)
endif() endif()
set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON)
find_package(Boost REQUIRED COMPONENTS thread json) # find_package(Boost REQUIRED COMPONENTS thread json)
target_include_directories(${PROJECT_NAME} PUBLIC ${Boost_INCLUDE_DIR}) # target_include_directories(${PROJECT_NAME} PUBLIC ${Boost_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} PUBLIC Boost::thread Boost::json) # target_link_libraries(${PROJECT_NAME} PUBLIC Boost::thread Boost::json)
set(BOOST_INCLUDE_LIBRARIES asio thread json)
set(BOOST_ENABLE_CMAKE ON)
FetchContent_Declare(
Boost
URL https://github.com/boostorg/boost/releases/download/boost-1.87.0/boost-1.87.0-cmake.7z
USES_TERMINAL_DOWNLOAD TRUE
DOWNLOAD_NO_EXTRACT FALSE
)
FetchContent_MakeAvailable(Boost)
target_link_libraries(${PROJECT_NAME} PUBLIC Boost::asio Boost::thread Boost::json)
# glm # glm
find_package(glm REQUIRED) # find_package(glm REQUIRED)
target_include_directories(${PROJECT_NAME} PUBLIC ${GLM_INCLUDE_DIR}) # target_include_directories(${PROJECT_NAME} PUBLIC ${GLM_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} PUBLIC ${GLM_LIBRARY}) # target_link_libraries(${PROJECT_NAME} PUBLIC ${GLM_LIBRARY})
FetchContent_Declare(
glm
GIT_REPOSITORY https://github.com/g-truc/glm.git
GIT_TAG 1.0.1
)
FetchContent_MakeAvailable(glm)
target_link_libraries(${PROJECT_NAME} PUBLIC glm)
# JPEG # JPEG
find_package(JPEG REQUIRED) find_package(JPEG REQUIRED)
@@ -40,13 +71,26 @@ target_link_libraries(${PROJECT_NAME} PUBLIC PNG::PNG)
target_include_directories(${PROJECT_NAME} PUBLIC "${PROJECT_SOURCE_DIR}/Libs/png++") target_include_directories(${PROJECT_NAME} PUBLIC "${PROJECT_SOURCE_DIR}/Libs/png++")
# GLFW3 # GLFW3
find_package(glfw3 REQUIRED) # find_package(glfw3 REQUIRED)
target_include_directories(${PROJECT_NAME} PUBLIC ${GLFW_INCLUDE_DIRS}) # target_include_directories(${PROJECT_NAME} PUBLIC ${GLFW_INCLUDE_DIRS})
FetchContent_Declare(
glfw
GIT_REPOSITORY https://github.com/glfw/glfw.git
GIT_TAG 3.4
)
FetchContent_MakeAvailable(glfw)
target_link_libraries(${PROJECT_NAME} PUBLIC glfw) target_link_libraries(${PROJECT_NAME} PUBLIC glfw)
# FreeType # FreeType
find_package(Freetype REQUIRED) find_package(Freetype REQUIRED)
target_include_directories(${PROJECT_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) # FetchContent_Declare(
# freetype
# GIT_REPOSITORY https://github.com/freetype/freetype.git
# GIT_TAG freetype
# )
# FetchContent_MakeAvailable(freetype)
target_include_directories(${PROJECT_NAME} PUBLIC ${freetype_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} PUBLIC Freetype::Freetype) target_link_libraries(${PROJECT_NAME} PUBLIC Freetype::Freetype)
# ImGui # ImGui
@@ -70,5 +114,3 @@ SET_SOURCE_FILES_PROPERTIES(assets.o PROPERTIES EXTERNAL_OBJECT true GENERATED t
add_library(assets STATIC resources.cpp assets.o) add_library(assets STATIC resources.cpp assets.o)
SET_TARGET_PROPERTIES(assets PROPERTIES LINKER_LANGUAGE C) SET_TARGET_PROPERTIES(assets PROPERTIES LINKER_LANGUAGE C)
target_link_libraries(${PROJECT_NAME} PUBLIC assets uring) target_link_libraries(${PROJECT_NAME} PUBLIC assets uring)
#set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment")

View File

@@ -3,6 +3,7 @@
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <unordered_set>
#include <vector> #include <vector>
#include <Common/Abstract.hpp> #include <Common/Abstract.hpp>
@@ -81,7 +82,7 @@ public:
virtual void onDefEntityUpdates(const std::vector<DefEntityId_c> &updates) = 0; virtual void onDefEntityUpdates(const std::vector<DefEntityId_c> &updates) = 0;
// Сообщаем об изменившихся чанках // Сообщаем об изменившихся чанках
virtual void onChunksChange(WorldId_c worldId, const std::vector<Pos::GlobalChunk> &changeOrAddList, const std::vector<Pos::GlobalChunk> &remove) = 0; virtual void onChunksChange(WorldId_c worldId, const std::unordered_set<Pos::GlobalChunk> &changeOrAddList, const std::unordered_set<Pos::GlobalChunk> &remove) = 0;
// Установить позицию для камеры // Установить позицию для камеры
virtual void setCameraPos(WorldId_c worldId, Pos::Object pos, glm::quat quat) = 0; virtual void setCameraPos(WorldId_c worldId, Pos::Object pos, glm::quat quat) = 0;
@@ -90,7 +91,7 @@ public:
struct Region { struct Region {
std::unordered_map<Pos::Local4_u::Key, Chunk[4][4][4]> Subs; std::unordered_map<Pos::Local16_u, Chunk> Chunks;
}; };
@@ -147,6 +148,10 @@ public:
std::unordered_map<EntityId_c, EntityInfo> Entityes; std::unordered_map<EntityId_c, EntityInfo> Entityes;
} Registry; } Registry;
struct {
std::unordered_map<WorldId_c, World> Worlds;
} External;
virtual ~IServerSession(); virtual ~IServerSession();
virtual void atFreeDrawTime(GlobalTime gTime, float dTime) = 0; virtual void atFreeDrawTime(GlobalTime gTime, float dTime) = 0;

View File

@@ -10,6 +10,8 @@
#include <memory> #include <memory>
#include <Common/Packets.hpp> #include <Common/Packets.hpp>
#include <glm/ext.hpp> #include <glm/ext.hpp>
#include <unordered_map>
#include <unordered_set>
namespace LV::Client { namespace LV::Client {
@@ -163,6 +165,9 @@ void ServerSession::onCursorPosChange(int32_t width, int32_t height) {
} }
void ServerSession::onCursorMove(float xMove, float yMove) { void ServerSession::onCursorMove(float xMove, float yMove) {
xMove /= 10.f;
yMove /= 10.f;
glm::vec3 deltaPYR; glm::vec3 deltaPYR;
static constexpr float PI = glm::pi<float>(), PI2 = PI*2, PI_HALF = PI/2, PI_DEG = PI/180; static constexpr float PI = glm::pi<float>(), PI2 = PI*2, PI_HALF = PI/2, PI_DEG = PI/180;
@@ -186,6 +191,26 @@ void ServerSession::onCursorBtn(ISurfaceEventListener::EnumCursorBtn btn, bool s
void ServerSession::onKeyboardBtn(int btn, int state) { void ServerSession::onKeyboardBtn(int btn, int state) {
if(btn == GLFW_KEY_TAB && !state) { if(btn == GLFW_KEY_TAB && !state) {
CursorMode = CursorMode == EnumCursorMoveMode::Default ? EnumCursorMoveMode::MoveAndHidden : EnumCursorMoveMode::Default; CursorMode = CursorMode == EnumCursorMoveMode::Default ? EnumCursorMoveMode::MoveAndHidden : EnumCursorMoveMode::Default;
Keys.clear();
}
if(CursorMode == EnumCursorMoveMode::MoveAndHidden)
{
if(btn == GLFW_KEY_W)
Keys.W = state;
else if(btn == GLFW_KEY_A)
Keys.A = state;
else if(btn == GLFW_KEY_S)
Keys.S = state;
else if(btn == GLFW_KEY_D)
Keys.D = state;
else if(btn == GLFW_KEY_LEFT_SHIFT)
Keys.SHIFT = state;
else if(btn == GLFW_KEY_SPACE)
Keys.SPACE = state;
else if(btn == GLFW_KEY_LEFT_CONTROL)
Keys.CTRL = state;
} }
} }
@@ -196,17 +221,62 @@ void ServerSession::onJoystick() {
void ServerSession::atFreeDrawTime(GlobalTime gTime, float dTime) { void ServerSession::atFreeDrawTime(GlobalTime gTime, float dTime) {
GTime = gTime; GTime = gTime;
Pos += glm::vec3(Speed) * dTime;
Speed -= glm::dvec3(Speed) * double(dTime);
glm::mat4 rot(1);
float deltaTime = 1-std::min<float>(gTime-PYR_At, 1/PYR_TIME_DELTA)*PYR_TIME_DELTA;
rot = glm::rotate(rot, PYR.y-deltaTime*PYR_Offset.y, {0, 1, 0});
float mltpl = 16*dTime*Pos::Object_t::BS;
if(Keys.CTRL)
mltpl *= 16;
Speed += glm::vec3(rot*glm::vec4(0, 0, 1, 1)*float(Keys.W))*mltpl;
Speed += glm::vec3(rot*glm::vec4(-1, 0, 0, 1)*float(Keys.A))*mltpl;
Speed += glm::vec3(rot*glm::vec4(0, 0, -1, 1)*float(Keys.S))*mltpl;
Speed += glm::vec3(rot*glm::vec4(1, 0, 0, 1)*float(Keys.D))*mltpl;
Speed += glm::vec3(0, -1, 0)*float(Keys.SHIFT)*mltpl;
Speed += glm::vec3(0, 1, 0)*float(Keys.SPACE)*mltpl;
{
std::unordered_map<WorldId_c, std::tuple<std::unordered_set<Pos::GlobalChunk>, std::unordered_set<Pos::GlobalChunk>>> changeOrAddList_removeList;
// Пакеты
ParsedPacket *pack;
while(NetInputPackets.pop(pack)) {
if(pack->Level1 == ToClient::L1::Content && ToClient::L2Content(pack->Level2) == ToClient::L2Content::ChunkVoxels) {
PP_Content_ChunkVoxels &p = *dynamic_cast<PP_Content_ChunkVoxels*>(pack);
Pos::GlobalRegion rPos(p.Pos.X >> 4, p.Pos.Y >> 4, p.Pos.Z >> 4);
Pos::Local16_u cPos(p.Pos.X & 0xf, p.Pos.Y & 0xf, p.Pos.Z & 0xf);
External.Worlds[p.Id].Regions[rPos].Chunks[cPos].Voxels = std::move(p.Cubes);
auto &pair = changeOrAddList_removeList[p.Id];
std::get<0>(pair).insert(p.Pos);
}
delete pack;
}
if(RS && !changeOrAddList_removeList.empty()) {
for(auto &pair : changeOrAddList_removeList) {
RS->onChunksChange(pair.first, std::get<0>(pair.second), std::get<1>(pair.second));
}
}
}
if(!RS) if(!RS)
return; return;
// Расчёт камеры // Расчёт камеры
{ {
float deltaTime = 1-std::min<float>(gTime-PYR_At, 1/PYR_TIME_DELTA)*PYR_TIME_DELTA; float deltaTime = 1-std::min<float>(gTime-PYR_At, 1/PYR_TIME_DELTA)*PYR_TIME_DELTA;
glm::quat quat =
glm::angleAxis(PYR.x-deltaTime*PYR_Offset.x, glm::vec3(1.f, 0.f, 0.f))
* glm::angleAxis(PYR.y-deltaTime*PYR_Offset.y, glm::vec3(0.f, 1.f, 0.f));
RS->setCameraPos(0, {0, 0, 0}, quat); glm::quat quat =
glm::angleAxis(PYR.x-deltaTime*PYR_Offset.x, glm::vec3(-1.f, 0.f, 0.f))
* glm::angleAxis(PYR.y-deltaTime*PYR_Offset.y, glm::vec3(0.f, -1.f, 0.f));
RS->setCameraPos(0, Pos, quat);
} }
} }
@@ -387,6 +457,7 @@ coro<> ServerSession::rP_Content(Net::AsyncSocket &sock) {
Pos::GlobalChunk pos = *(Pos::GlobalChunk*) &posKey; Pos::GlobalChunk pos = *(Pos::GlobalChunk*) &posKey;
std::vector<VoxelCube> cubes(co_await sock.read<uint16_t>()); std::vector<VoxelCube> cubes(co_await sock.read<uint16_t>());
uint16_t debugCubesCount = cubes.size();
for(size_t iter = 0; iter < cubes.size(); iter++) { for(size_t iter = 0; iter < cubes.size(); iter++) {
VoxelCube &cube = cubes[iter]; VoxelCube &cube = cubes[iter];
@@ -409,7 +480,7 @@ coro<> ServerSession::rP_Content(Net::AsyncSocket &sock) {
while(!NetInputPackets.push(packet)); while(!NetInputPackets.push(packet));
LOG.info() << "Приняты воксели чанка " << int(wcId) << " / " << pos.X << ":" << pos.Y << ":" << pos.Z << " Вокселей " << cubes.size(); LOG.info() << "Приняты воксели чанка " << int(wcId) << " / " << pos.X << ":" << pos.Y << ":" << pos.Z << " Вокселей " << debugCubesCount;
co_return; co_return;
} }

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "Abstract.hpp" #include "Abstract.hpp"
#include "Common/Abstract.hpp"
#include "Common/Async.hpp" #include "Common/Async.hpp"
#include "Common/Lockable.hpp" #include "Common/Lockable.hpp"
#include "Common/Net.hpp" #include "Common/Net.hpp"
@@ -31,10 +32,6 @@ class ServerSession : public AsyncObject, public IServerSession, public ISurface
TOS::Logger LOG = "ServerSession"; TOS::Logger LOG = "ServerSession";
struct {
glm::quat Quat;
} Camera;
boost::lockfree::spsc_queue<ParsedPacket*> NetInputPackets; boost::lockfree::spsc_queue<ParsedPacket*> NetInputPackets;
// PYR - поворот камеры по осям xyz в радианах, PYR_Offset для сглаживание поворота // PYR - поворот камеры по осям xyz в радианах, PYR_Offset для сглаживание поворота
@@ -43,6 +40,17 @@ class ServerSession : public AsyncObject, public IServerSession, public ISurface
static constexpr float PYR_TIME_DELTA = 30; static constexpr float PYR_TIME_DELTA = 30;
GlobalTime GTime; GlobalTime GTime;
struct {
bool W = false, A = false, S = false, D = false, SHIFT = false, SPACE = false;
bool CTRL = false;
void clear()
{
std::memset(this, 0, sizeof(*this));
}
} Keys;
Pos::Object Pos = Pos::Object(0), Speed = Pos::Object(0);
public: public:
// Нужен сокет, на котором только что был согласован игровой протокол (asyncInitGameProtocol) // Нужен сокет, на котором только что был согласован игровой протокол (asyncInitGameProtocol)
ServerSession(asio::io_context &ioc, std::unique_ptr<Net::AsyncSocket> &&socket, IRenderSession *rs = nullptr) ServerSession(asio::io_context &ioc, std::unique_ptr<Net::AsyncSocket> &&socket, IRenderSession *rs = nullptr)

View File

@@ -140,7 +140,7 @@ void Vulkan::run()
while(!NeedShutdown) while(!NeedShutdown)
{ {
float dTime = glfwGetTime()-prevTime; float dTime = glfwGetTime()-prevTime;
prevTime = glfwGetTime(); prevTime += dTime;
Screen.State = DrawState::Begin; Screen.State = DrawState::Begin;
{ {
@@ -176,15 +176,15 @@ void Vulkan::run()
// Спрятать или показать курсор // Спрятать или показать курсор
{ {
int mode = glfwGetInputMode(Graphics.Window, GLFW_CURSOR); int mode = glfwGetInputMode(Graphics.Window, GLFW_CURSOR);
if(mode == GLFW_CURSOR_HIDDEN && sobj.CursorMode != ISurfaceEventListener::EnumCursorMoveMode::MoveAndHidden) if(mode == GLFW_CURSOR_DISABLED && sobj.CursorMode != ISurfaceEventListener::EnumCursorMoveMode::MoveAndHidden)
glfwSetInputMode(Graphics.Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); glfwSetInputMode(Graphics.Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
else if(mode == GLFW_CURSOR_NORMAL && sobj.CursorMode != ISurfaceEventListener::EnumCursorMoveMode::Default) { else if(mode == GLFW_CURSOR_NORMAL && sobj.CursorMode != ISurfaceEventListener::EnumCursorMoveMode::Default) {
glfwSetInputMode(Graphics.Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
glfwSetCursorPos(Graphics.Window, Screen.Width/2., Screen.Height/2.); glfwSetCursorPos(Graphics.Window, Screen.Width/2., Screen.Height/2.);
Game.MLastPosX = Screen.Width/2.;
Game.MLastPosY = Screen.Height/2.;
glfwSetInputMode(Graphics.Window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
} }
} }
} }
// if(CallBeforeDraw) // if(CallBeforeDraw)
@@ -197,7 +197,8 @@ void Vulkan::run()
glfwPollEvents(); glfwPollEvents();
VkResult err; VkResult err;
err = vkAcquireNextImageKHR(Graphics.Device, Graphics.Swapchain, UINT64_MAX, SemaphoreImageAcquired, (VkFence) 0, &Graphics.DrawBufferCurrent); err = vkAcquireNextImageKHR(Graphics.Device, Graphics.Swapchain, 1000000000ULL/20, SemaphoreImageAcquired, (VkFence) 0, &Graphics.DrawBufferCurrent);
GlobalTime gTime = glfwGetTime();
if (err == VK_ERROR_OUT_OF_DATE_KHR) if (err == VK_ERROR_OUT_OF_DATE_KHR)
{ {
@@ -207,9 +208,7 @@ void Vulkan::run()
} else if (err == VK_SUBOPTIMAL_KHR) } else if (err == VK_SUBOPTIMAL_KHR)
{ {
LOGGER.debug() << "VK_SUBOPTIMAL_KHR Pre"; LOGGER.debug() << "VK_SUBOPTIMAL_KHR Pre";
} else } else if(err == VK_SUCCESS) {
assert(!err);
Screen.State = DrawState::Drawing; Screen.State = DrawState::Drawing;
//Готовим инструкции рисовки //Готовим инструкции рисовки
@@ -277,8 +276,6 @@ void Vulkan::run()
vkCmdSetScissor(Graphics.CommandBufferRender, 0, 1, &scissor); vkCmdSetScissor(Graphics.CommandBufferRender, 0, 1, &scissor);
} }
GlobalTime gTime = glfwGetTime();
if(Game.RSession) { if(Game.RSession) {
auto &robj = *Game.RSession; auto &robj = *Game.RSession;
// Рендер мира // Рендер мира
@@ -528,6 +525,8 @@ void Vulkan::run()
else else
assert(!err); assert(!err);
} }
} else
assert(err == VK_TIMEOUT);
if(Game.Session) { if(Game.Session) {
Game.Session->atFreeDrawTime(gTime, dTime); Game.Session->atFreeDrawTime(gTime, dTime);
@@ -996,8 +995,15 @@ void Vulkan::glfwCallbackOnResize(GLFWwindow *window, int width, int height)
handler->freeSwapchains(); handler->freeSwapchains();
handler->buildSwapchains(); handler->buildSwapchains();
if(handler->Game.Session) if(handler->Game.Session) {
handler->Game.Session->onResize(width, height); handler->Game.Session->onResize(width, height);
if(handler->Game.Session->CursorMode == ISurfaceEventListener::EnumCursorMoveMode::MoveAndHidden) {
glfwSetCursorPos(window, width/2., height/2.);
handler->Game.MLastPosX = width/2.;
handler->Game.MLastPosY = height/2.;
}
}
} }
} }
@@ -1018,8 +1024,9 @@ void Vulkan::glfwCallbackOnCursorPos(GLFWwindow* window, double xpos, double ypo
if(sobj.CursorMode == ISurfaceEventListener::EnumCursorMoveMode::Default) { if(sobj.CursorMode == ISurfaceEventListener::EnumCursorMoveMode::Default) {
sobj.onCursorPosChange((int32_t) xpos, (int32_t) ypos); sobj.onCursorPosChange((int32_t) xpos, (int32_t) ypos);
} else { } else {
glfwSetCursorPos(handler->Graphics.Window, handler->Screen.Width/2., handler->Screen.Height/2.); sobj.onCursorMove(xpos-handler->Game.MLastPosX, handler->Game.MLastPosY-ypos);
sobj.onCursorMove(xpos-handler->Screen.Width/2., handler->Screen.Height/2.-ypos); handler->Game.MLastPosX = xpos;
handler->Game.MLastPosY = ypos;
} }
} }
} }

View File

@@ -16,9 +16,7 @@
#define HAS_IMGUI #define HAS_IMGUI
#define GLM_FORCE_DEPTH_ZERO_TO_ONE #include "freetype/freetype.h"
#include <freetype/freetype.h>
#include <vulkan/vulkan_core.h> #include <vulkan/vulkan_core.h>
#include <glm/ext.hpp> #include <glm/ext.hpp>
@@ -28,6 +26,8 @@
#define GLFW_INCLUDE_NONE #define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
static_assert(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO);
#define IMGUI_ENABLE_STB_TEXTEDIT_UNICODE #define IMGUI_ENABLE_STB_TEXTEDIT_UNICODE
namespace LV::Client::VK { namespace LV::Client::VK {
@@ -245,6 +245,8 @@ public:
std::list<void (Vulkan::*)()> ImGuiInterfaces; std::list<void (Vulkan::*)()> ImGuiInterfaces;
std::unique_ptr<ServerObj> Server; std::unique_ptr<ServerObj> Server;
double MLastPosX, MLastPosY;
} Game; } Game;
private: private:

View File

@@ -1,8 +1,10 @@
#include "VulkanRenderSession.hpp" #include "VulkanRenderSession.hpp"
#include "Client/Vulkan/Vulkan.hpp" #include "Client/Vulkan/Vulkan.hpp"
#include "Common/Abstract.hpp"
#include "assets.hpp" #include "assets.hpp"
#include <glm/ext/matrix_transform.hpp> #include <memory>
#include <vulkan/vulkan_core.h> #include <vulkan/vulkan_core.h>
#include <fstream>
namespace LV::Client::VK { namespace LV::Client::VK {
@@ -92,7 +94,7 @@ void VulkanRenderSession::init(Vulkan *instance) {
.binding = 1, .binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT, .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
.pImmutableSamplers = nullptr .pImmutableSamplers = nullptr
} }
}; };
@@ -136,7 +138,7 @@ void VulkanRenderSession::init(Vulkan *instance) {
.binding = 1, .binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT, .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
.pImmutableSamplers = nullptr .pImmutableSamplers = nullptr
} }
}; };
@@ -188,13 +190,28 @@ void VulkanRenderSession::init(Vulkan *instance) {
return true; return true;
}); });
int width, height;
bool hasAlpha;
ByteBuffer image = VK::loadPNG(std::ifstream("/home/mr_s/Workspace/Alpha/LuaVox/assets/grass.png"), width, height, hasAlpha);
uint16_t texId = VKCTX->MainTest.atlasAddTexture(width, height);
VKCTX->MainTest.atlasChangeTextureData(texId, (const uint32_t*) image.data());
/*
x left -1 ~ right 1
y up -1 ~ down 1
z far 1 ~ near 0
glm
*/
NodeVertexStatic *array = (NodeVertexStatic*) VKCTX->TestQuad.mapMemory(); NodeVertexStatic *array = (NodeVertexStatic*) VKCTX->TestQuad.mapMemory();
array[0] = {112, 114, 113, 0, 0, 0, 0, 0, 0}; array[0] = {112, 114, 50, 0, 0, 0, 0, 0, 0};
array[1] = {114, 114, 113, 0, 0, 0, 0, 65535, 0}; array[1] = {114, 114, 50, 0, 0, 0, 0, 65535, 0};
array[2] = {114, 112, 113, 0, 0, 0, 0, 65535, 65535}; array[2] = {114, 112, 50, 0, 0, 0, 0, 65535, 65535};
array[3] = {112, 114, 113, 0, 0, 0, 0, 0, 0}; array[3] = {112, 114, 50, 0, 0, 0, 0, 0, 0};
array[4] = {114, 112, 113, 0, 0, 0, 0, 65535, 65535}; array[4] = {114, 112, 50, 0, 0, 0, 0, 65535, 65535};
array[5] = {112, 112, 113, 0, 0, 0, 0, 0, 65535}; array[5] = {112, 112, 50, 0, 0, 0, 0, 0, 65535};
VKCTX->TestQuad.unMapMemory(); VKCTX->TestQuad.unMapMemory();
} }
@@ -576,8 +593,32 @@ void VulkanRenderSession::onDefEntityUpdates(const std::vector<DefEntityId_c> &u
} }
void VulkanRenderSession::onChunksChange(WorldId_c worldId, const std::vector<Pos::GlobalChunk> &changeOrAddList, const std::vector<Pos::GlobalChunk> &remove) { void VulkanRenderSession::onChunksChange(WorldId_c worldId, const std::unordered_set<Pos::GlobalChunk> &changeOrAddList, const std::unordered_set<Pos::GlobalChunk> &remove) {
for(Pos::GlobalChunk pos : changeOrAddList) {
Pos::GlobalRegion rPos(pos.X >> 4, pos.Y >> 4, pos.Z >> 4);
Pos::Local16_u cPos(pos.X & 0xf, pos.Y & 0xf, pos.Z & 0xf);
const auto &voxels = ServerSession->External.Worlds[worldId].Regions[rPos].Chunks[cPos].Voxels;
auto &table = External.ChunkVoxelMesh[worldId];
if(voxels.empty()) {
auto iter = table.find(pos);
if(iter != table.end())
table.erase(iter);
if(table.empty())
External.ChunkVoxelMesh.erase(External.ChunkVoxelMesh.find(worldId));
} else {
auto &buffer = table[pos] = std::make_unique<Buffer>(VkInst, voxels.size()*6*6*sizeof(NodeVertexStatic));
NodeVertexStatic *vertex = (NodeVertexStatic*) buffer->mapMemory();
for(const VoxelCube &cube : voxels) {
}
buffer->unMapMemory();
}
}
} }
void VulkanRenderSession::setCameraPos(WorldId_c worldId, Pos::Object pos, glm::quat quat) { void VulkanRenderSession::setCameraPos(WorldId_c worldId, Pos::Object pos, glm::quat quat) {
@@ -587,14 +628,19 @@ void VulkanRenderSession::setCameraPos(WorldId_c worldId, Pos::Object pos, glm::
} }
void VulkanRenderSession::beforeDraw() { void VulkanRenderSession::beforeDraw() {
if(VKCTX) {
VKCTX->MainTest.atlasUpdateDynamicData();
VKCTX->LightDummy.atlasUpdateDynamicData();
}
} }
void VulkanRenderSession::drawWorld(GlobalTime gTime, float dTime, VkCommandBuffer drawCmd) { void VulkanRenderSession::drawWorld(GlobalTime gTime, float dTime, VkCommandBuffer drawCmd) {
glm::mat4 proj = glm::perspective<float>(75, float(VkInst->Screen.Width)/float(VkInst->Screen.Height), 0.5, std::pow(2, 17)); glm::mat4 proj = glm::perspective<float>(75, float(VkInst->Screen.Width)/float(VkInst->Screen.Height), 0.5, std::pow(2, 17));
PCO.ProjView = glm::mat4(Quat); // Сместить в координаты игрока, повернуть относительно взгляда, ещё поворот на 180 и проецировать на экран
//PCO.ProjView *= proj; PCO.ProjView = glm::mat4(1);
PCO.Model = glm::mat4(1); //= glm::rotate(glm::mat4(1), float(gTime/10), glm::vec3(0, 1, 0)); PCO.ProjView = glm::translate(PCO.ProjView, -glm::vec3(Pos)/float(Pos::Object_t::BS));
PCO.ProjView = proj*glm::mat4(Quat)*glm::rotate(glm::mat4(1), glm::pi<float>(), glm::vec3(0, 1, 0))*PCO.ProjView;
PCO.Model = glm::mat4(1);
vkCmdBindPipeline(drawCmd, VK_PIPELINE_BIND_POINT_GRAPHICS, NodeStaticOpaquePipeline); vkCmdBindPipeline(drawCmd, VK_PIPELINE_BIND_POINT_GRAPHICS, NodeStaticOpaquePipeline);
vkCmdPushConstants(drawCmd, MainAtlas_LightMap_PipelineLayout, vkCmdPushConstants(drawCmd, MainAtlas_LightMap_PipelineLayout,
@@ -606,7 +652,14 @@ void VulkanRenderSession::drawWorld(GlobalTime gTime, float dTime, VkCommandBuff
VkDeviceSize vkOffsets = 0; VkDeviceSize vkOffsets = 0;
VkBuffer vkBuffer = VKCTX->TestQuad; VkBuffer vkBuffer = VKCTX->TestQuad;
vkCmdBindVertexBuffers(drawCmd, 0, 1, &vkBuffer, &vkOffsets); vkCmdBindVertexBuffers(drawCmd, 0, 1, &vkBuffer, &vkOffsets);
for(int i = 0; i < 16; i++) {
PCO.Model = glm::rotate(PCO.Model, glm::half_pi<float>()*i/4, glm::vec3(0, 1, 0));
vkCmdPushConstants(drawCmd, MainAtlas_LightMap_PipelineLayout,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT, 0, sizeof(WorldPCO), &PCO);
vkCmdDraw(drawCmd, 6, 1, 0, 0); vkCmdDraw(drawCmd, 6, 1, 0, 0);
}
} }
void VulkanRenderSession::updateDescriptor_MainAtlas() { void VulkanRenderSession::updateDescriptor_MainAtlas() {

View File

@@ -1,10 +1,13 @@
#pragma once #pragma once
#include "Client/Abstract.hpp" #include "Client/Abstract.hpp"
#include "Common/Abstract.hpp" #include "Common/Abstract.hpp"
#include <Client/Vulkan/Vulkan.hpp> #include <Client/Vulkan/Vulkan.hpp>
#include <glm/ext/matrix_transform.hpp> #include <memory>
#include <unordered_map>
#include <vulkan/vulkan_core.h> #include <vulkan/vulkan_core.h>
/* /*
У движка есть один текстурный атлас VK_IMAGE_VIEW_TYPE_2D_ARRAY(RGBA_UINT) и к нему Storage с инфой о положении текстур У движка есть один текстурный атлас VK_IMAGE_VIEW_TYPE_2D_ARRAY(RGBA_UINT) и к нему Storage с инфой о положении текстур
Это общий для всех VkDescriptorSetLayout и VkDescriptorSet Это общий для всех VkDescriptorSetLayout и VkDescriptorSet
@@ -127,6 +130,10 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent {
std::map<TextureId_c, uint16_t> ServerToAtlas; std::map<TextureId_c, uint16_t> ServerToAtlas;
struct {
std::unordered_map<WorldId_c, std::unordered_map<Pos::GlobalChunk, std::unique_ptr<Buffer>>> ChunkVoxelMesh;
} External;
virtual void free(Vulkan *instance) override; virtual void free(Vulkan *instance) override;
virtual void init(Vulkan *instance) override; virtual void init(Vulkan *instance) override;
@@ -153,7 +160,7 @@ public:
virtual void onDefPortalUpdates(const std::vector<DefPortalId_c> &updates) override; virtual void onDefPortalUpdates(const std::vector<DefPortalId_c> &updates) override;
virtual void onDefEntityUpdates(const std::vector<DefEntityId_c> &updates) override; virtual void onDefEntityUpdates(const std::vector<DefEntityId_c> &updates) override;
virtual void onChunksChange(WorldId_c worldId, const std::vector<Pos::GlobalChunk> &changeOrAddList, const std::vector<Pos::GlobalChunk> &remove) override; virtual void onChunksChange(WorldId_c worldId, const std::unordered_set<Pos::GlobalChunk> &changeOrAddList, const std::unordered_set<Pos::GlobalChunk> &remove) override;
virtual void setCameraPos(WorldId_c worldId, Pos::Object pos, glm::quat quat) override; virtual void setCameraPos(WorldId_c worldId, Pos::Object pos, glm::quat quat) override;
glm::mat4 calcViewMatrix(glm::quat quat, glm::vec3 camOffset = glm::vec3(0)) { glm::mat4 calcViewMatrix(glm::quat quat, glm::vec3 camOffset = glm::vec3(0)) {

View File

@@ -8,10 +8,12 @@
#include <chrono> #include <chrono>
#include <glm/geometric.hpp> #include <glm/geometric.hpp>
#include <memory> #include <memory>
#include <string>
#include <thread> #include <thread>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include "SaveBackends/Filesystem.hpp" #include "SaveBackends/Filesystem.hpp"
#include "Server/SaveBackend.hpp"
namespace LV::Server { namespace LV::Server {
@@ -27,9 +29,10 @@ static thread_local std::vector<ContentViewCircle> TL_Circles;
std::vector<ContentViewCircle> GameServer::WorldObj::calcCVCs(ContentViewCircle circle, int depth) std::vector<ContentViewCircle> GameServer::WorldObj::calcCVCs(ContentViewCircle circle, int depth)
{ {
TL_Circles.reserve(4096); TL_Circles.clear();
TL_Circles.reserve(256);
TL_Circles.push_back(circle); TL_Circles.push_back(circle);
_calcContentViewCircles(TL_Circles.front(), depth); _calcContentViewCircles(circle, depth);
return TL_Circles; return TL_Circles;
} }
@@ -215,6 +218,42 @@ coro<> GameServer::pushSocketGameProtocol(tcp::socket socket, const std::string
} }
} }
Region* GameServer::forceGetRegion(WorldId_t worldId, Pos::GlobalRegion pos) {
auto worldIter = Expanse.Worlds.find(worldId);
assert(worldIter != Expanse.Worlds.end());
World &world = *worldIter->second;
auto iterRegion = world.Regions.find(pos);
if(iterRegion == world.Regions.end() || !iterRegion->second->IsLoaded) {
std::unique_ptr<Region> &region = world.Regions[pos];
if(!region)
region = std::make_unique<Region>();
std::string worldName = "world_"+std::to_string(worldId);
if(SaveBackend.World->isExist(worldName, pos)) {
SB_Region data;
SaveBackend.World->load(worldName, pos, &data);
region->IsLoaded = true;
region->load(&data);
} else {
region->IsLoaded = true;
if(pos.Y == 0) {
for(int z = 0; z < 16; z++)
for(int x = 0; x < 16; x++) {
region->Voxels[x][0][z].push_back({{0, 0, 0}, {255, 255, 255}, 0});
}
}
}
std::fill(region->IsChunkChanged_Voxels, region->IsChunkChanged_Voxels+64, ~0);
return region.get();
} else {
return iterRegion->second.get();
}
}
void GameServer::init(fs::path worldPath) { void GameServer::init(fs::path worldPath) {
Expanse.Worlds[0] = std::make_unique<World>(0); Expanse.Worlds[0] = std::make_unique<World>(0);
@@ -302,16 +341,16 @@ void GameServer::run() {
// Сон или подгонка длительности такта при высоких нагрузках // Сон или подгонка длительности такта при высоких нагрузках
std::chrono::steady_clock::time_point atTickEnd = std::chrono::steady_clock::now(); std::chrono::steady_clock::time_point atTickEnd = std::chrono::steady_clock::now();
float currentWastedTime = double((atTickEnd-atTickStart).count() * std::chrono::steady_clock::duration::period::num) / std::chrono::steady_clock::duration::period::den; float currentWastedTime = double((atTickEnd-atTickStart).count() * std::chrono::steady_clock::duration::period::num) / std::chrono::steady_clock::duration::period::den;
float freeTime = CurrentTickDuration-currentWastedTime-GlobalTickLagTime; GlobalTickLagTime += CurrentTickDuration-currentWastedTime;
if(freeTime > 0) { if(GlobalTickLagTime > 0) {
CurrentTickDuration -= PerTickAdjustment; CurrentTickDuration -= PerTickAdjustment;
if(CurrentTickDuration < PerTickDuration) if(CurrentTickDuration < PerTickDuration)
CurrentTickDuration = PerTickDuration; CurrentTickDuration = PerTickDuration;
std::this_thread::sleep_for(std::chrono::milliseconds(uint32_t(1000*freeTime))); std::this_thread::sleep_for(std::chrono::milliseconds(uint32_t(1000*GlobalTickLagTime)));
GlobalTickLagTime = 0;
} else { } else {
GlobalTickLagTime = freeTime;
CurrentTickDuration += PerTickAdjustment; CurrentTickDuration += PerTickAdjustment;
} }
} }
@@ -558,7 +597,7 @@ void GameServer::stepWorlds() {
if(rPos != pRegion.first || pWorld.first != entity.WorldId) { if(rPos != pRegion.first || pWorld.first != entity.WorldId) {
Region *toRegion = Expanse.Worlds[entity.WorldId]->forceLoadOrGetRegion(rPos); Region *toRegion = forceGetRegion(entity.WorldId, rPos);
LocalEntityId_t newId = toRegion->pushEntity(entity); LocalEntityId_t newId = toRegion->pushEntity(entity);
// toRegion->Entityes[newId].WorldId = Если мир изменился // toRegion->Entityes[newId].WorldId = Если мир изменился
@@ -808,6 +847,11 @@ void GameServer::stepWorlds() {
if(needToUnload) { if(needToUnload) {
regionsToRemove.push_back(pRegion.first); regionsToRemove.push_back(pRegion.first);
} }
// Сброс информации об изменившихся данных
std::fill(region.IsChunkChanged_Voxels, region.IsChunkChanged_Voxels+64, 0);
std::fill(region.IsChunkChanged_Nodes, region.IsChunkChanged_Nodes+64, 0);
} }
for(Pos::GlobalRegion regionPos : regionsToRemove) { for(Pos::GlobalRegion regionPos : regionsToRemove) {
@@ -962,7 +1006,13 @@ void GameServer::stepSendPlayersPackets() {
} }
void GameServer::stepLoadRegions() { void GameServer::stepLoadRegions() {
for(auto &iterWorld : Expanse.Worlds) {
for(Pos::GlobalRegion pos : iterWorld.second->NeedToLoad) {
forceGetRegion(iterWorld.first, pos);
}
iterWorld.second->NeedToLoad.clear();
}
} }
void GameServer::stepGlobal() { void GameServer::stepGlobal() {

View File

@@ -134,6 +134,9 @@ public:
// Инициализация игрового протокола для сокета (onSocketAuthorized() может передать сокет в onSocketGame()) // Инициализация игрового протокола для сокета (onSocketAuthorized() может передать сокет в onSocketGame())
coro<> pushSocketGameProtocol(tcp::socket socket, const std::string username); coro<> pushSocketGameProtocol(tcp::socket socket, const std::string username);
/* Загрузит, сгенерирует или просто выдаст регион из мира, который должен существовать */
Region* forceGetRegion(WorldId_t worldId, Pos::GlobalRegion pos);
private: private:
void init(fs::path worldPath); void init(fs::path worldPath);
void prerun(); void prerun();

View File

@@ -16,6 +16,7 @@ struct SB_Region {
std::unordered_map<Pos::Local16_u, Node> Nodes; std::unordered_map<Pos::Local16_u, Node> Nodes;
std::unordered_map<DefNodeId_t, std::string> NodeMap; std::unordered_map<DefNodeId_t, std::string> NodeMap;
std::vector<Entity> Entityes; std::vector<Entity> Entityes;
std::unordered_map<DefEntityId_t, std::string> EntityMap;
}; };
class IWorldSaveBackend { class IWorldSaveBackend {

View File

@@ -46,17 +46,4 @@ void World::onCEC_RegionsLost(ContentEventController *cec, const std::vector<Pos
} }
} }
Region* World::forceLoadOrGetRegion(Pos::GlobalRegion pos) {
std::unique_ptr<Region> &region = Regions[pos];
if(!region)
region = std::make_unique<Region>();
if(!region->IsLoaded) {
region->IsLoaded = true;
}
return region.get();
}
} }

View File

@@ -3,8 +3,10 @@
#include "Common/Abstract.hpp" #include "Common/Abstract.hpp"
#include "Server/Abstract.hpp" #include "Server/Abstract.hpp"
#include "Server/ContentEventController.hpp" #include "Server/ContentEventController.hpp"
#include "Server/SaveBackend.hpp"
#include <memory> #include <memory>
#include <unordered_map> #include <unordered_map>
#include <vector>
namespace LV::Server { namespace LV::Server {
@@ -15,7 +17,7 @@ class Region {
public: public:
uint64_t IsChunkChanged_Voxels[64] = {0}; uint64_t IsChunkChanged_Voxels[64] = {0};
uint64_t IsChunkChanged_Nodes[64] = {0}; uint64_t IsChunkChanged_Nodes[64] = {0};
bool IsChanged = false; bool IsChanged = false; // Изменён ли был регион, относительно последнего сохранения
// cx cy cz // cx cy cz
std::vector<VoxelCube> Voxels[16][16][16]; std::vector<VoxelCube> Voxels[16][16][16];
// x y cx cy cz // x y cx cy cz
@@ -132,6 +134,15 @@ public:
return LocalEntityId_t(-1); return LocalEntityId_t(-1);
} }
void load(SB_Region *data) {
convertRegionVoxelsToChunks(data->Voxels, (std::vector<VoxelCube>*) Voxels);
}
void save(SB_Region *data) {
data->Voxels.clear();
convertChunkVoxelsToRegion((const std::vector<VoxelCube>*) Voxels, data->Voxels);
}
}; };
class World { class World {
@@ -154,8 +165,6 @@ public:
void onCEC_RegionsEnter(ContentEventController *cec, const std::vector<Pos::GlobalRegion> &enter); void onCEC_RegionsEnter(ContentEventController *cec, const std::vector<Pos::GlobalRegion> &enter);
void onCEC_RegionsLost(ContentEventController *cec, const std::vector<Pos::GlobalRegion> &lost); void onCEC_RegionsLost(ContentEventController *cec, const std::vector<Pos::GlobalRegion> &lost);
Region* forceLoadOrGetRegion(Pos::GlobalRegion pos);
DefWorldId_t getDefId() const { return DefId; } DefWorldId_t getDefId() const { return DefId; }
}; };

BIN
assets/grass.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -8,16 +8,67 @@ layout(location = 0) in FragmentObj {
layout(location = 0) out vec4 Frame; layout(location = 0) out vec4 Frame;
uniform layout(set = 0, binding = 0) sampler2DArray MainAtlas; struct InfoSubTexture {
uint Flags; // 1 isExist
uint PosXY, WidthHeight;
uint AnimationFrames_AnimationTimePerFrame;
};
uniform layout(set = 0, binding = 0) sampler2D MainAtlas;
layout(set = 0, binding = 1) readonly buffer MainAtlasLayoutObj { layout(set = 0, binding = 1) readonly buffer MainAtlasLayoutObj {
vec3 Color; uint SubsCount;
uint Counter;
uint WidthHeight;
InfoSubTexture SubTextures[];
} MainAtlasLayout; } MainAtlasLayout;
uniform layout(set = 1, binding = 0) sampler2DArray LightMap; uniform layout(set = 1, binding = 0) sampler2D LightMap;
layout(set = 1, binding = 1) readonly buffer LightMapLayoutObj { layout(set = 1, binding = 1) readonly buffer LightMapLayoutObj {
vec3 Color; vec3 Color;
} LightMapLayout; } LightMapLayout;
void main() { vec4 atlasColor(uint texId, vec2 uv)
Frame = vec4(1); {
uint flags = (texId & 0xffff0000) >> 16;
texId &= 0xffff;
vec4 color = vec4(uv, 0, 1);
if((flags & (2 | 4)) > 0)
{
if((flags & 2) > 0)
color = vec4(1, 1, 1, 1);
else if((flags & 4) > 0)
{
color = vec4(1);
}
}
else if(texId >= uint(MainAtlasLayout.SubsCount))
return vec4(((int(gl_FragCoord.x / 128) + int(gl_FragCoord.y / 128)) % 2 ) * vec3(0, 1, 1), 1);
else {
InfoSubTexture texInfo = MainAtlasLayout.SubTextures[texId];
if(texInfo.Flags == 0)
return vec4(((int(gl_FragCoord.x / 128) + int(gl_FragCoord.y / 128)) % 2 ) * vec3(1, 0, 1), 1);
uint posX = texInfo.PosXY & 0xffff;
uint posY = (texInfo.PosXY >> 16) & 0xffff;
uint width = texInfo.WidthHeight & 0xffff;
uint height = (texInfo.WidthHeight >> 16) & 0xffff;
uint awidth = MainAtlasLayout.WidthHeight & 0xffff;
uint aheight = (MainAtlasLayout.WidthHeight >> 16) & 0xffff;
if((flags & 1) > 0)
color = texture(MainAtlas, vec2((posX+0.5f+uv.x*(width-1))/awidth, (posY+0.5f+(1-uv.y)*(height-1))/aheight));
else
color = texture(MainAtlas, vec2((posX+uv.x*width)/awidth, (posY+(1-uv.y)*height)/aheight));
}
return color;
}
void main() {
Frame = atlasColor(Fragment.Texture, Fragment.UV);
} }

View File

@@ -1,8 +0,0 @@
[Window][Debug##Default]
Pos=0,0
Size=400,400
[Window][MainMenu]
Pos=0,0
Size=960,540