Apply new Code Styling to all files.

master
Auri 2020-11-08 22:57:34 -08:00
parent 4915a8130b
commit e49ab18617
322 changed files with 14205 additions and 13136 deletions

View File

@ -6,14 +6,12 @@
<file path="$PROJECT_DIR$/src" />
<file path="$PROJECT_DIR$/test" />
</sourceRoots>
<libraryRoots>
<file path="$PROJECT_DIR$/lib" />
</libraryRoots>
<excludeRoots>
<file path="$PROJECT_DIR$/.github" />
<file path="$PROJECT_DIR$/.idea" />
<file path="$PROJECT_DIR$/Libraries" />
<file path="$PROJECT_DIR$/cmake-build-install" />
<file path="$PROJECT_DIR$/lib" />
<file path="$PROJECT_DIR$/worlds" />
<file path="$PROJECT_DIR$/worlds/world" />
</excludeRoots>

View File

@ -1,321 +1,321 @@
add_library(Zepha_Core
client/Client.cpp
client/Client.h
client/conn/ClientNetworkInterpreter.cpp
client/conn/ClientNetworkInterpreter.h
client/conn/ServerConnection.cpp
client/conn/ServerConnection.h
client/entity/ParticleEntity.cpp
client/entity/ParticleEntity.h
client/entity/PlayerEntity.h
client/entity/WireframeEntity.cpp
client/entity/WireframeEntity.h
client/graph/Camera.cpp
client/graph/Camera.h
client/graph/Drawable.h
client/graph/DrawableGroup.cpp
client/graph/DrawableGroup.h
client/graph/Font.cpp
client/graph/Font.h
client/graph/mesh/ChunkMesh.cpp
client/graph/mesh/ChunkMesh.h
client/graph/mesh/ChunkMeshGenerator.cpp
client/graph/mesh/ChunkMeshGenerator.h
client/graph/mesh/ChunkRenderElem.h
client/graph/mesh/ChunkVertex.h
client/graph/mesh/EntityMesh.cpp
client/graph/mesh/EntityMesh.h
client/graph/mesh/EntityVertex.h
client/graph/mesh/Mesh.cpp
client/graph/mesh/Mesh.h
client/graph/mesh/MeshChunk.cpp
client/graph/mesh/MeshChunk.h
client/graph/Model.cpp
client/graph/Model.h
client/graph/ModelAnimation.cpp
client/graph/ModelAnimation.h
client/graph/ModelBone.cpp
client/graph/ModelBone.h
client/graph/Renderer.cpp
client/graph/Renderer.h
client/graph/shader/BlurShader.cpp
client/graph/shader/BlurShader.h
client/graph/shader/EntityGeometryShader.cpp
client/graph/shader/EntityGeometryShader.h
client/graph/shader/GuiUniforms.h
client/graph/shader/LightingShader.cpp
client/graph/shader/LightingShader.h
client/graph/shader/Shader.cpp
client/graph/shader/Shader.h
client/graph/shader/SSAOShader.cpp
client/graph/shader/SSAOShader.h
client/graph/shader/WorldGeometryShader.cpp
client/graph/shader/WorldGeometryShader.h
client/graph/Texture.cpp
client/graph/Texture.h
client/gui/basic/GuiContainer.cpp
client/gui/basic/GuiContainer.h
client/gui/basic/GuiGraph.cpp
client/gui/basic/GuiGraph.h
client/gui/basic/GuiInventoryItem.cpp
client/gui/basic/GuiInventoryItem.h
client/gui/basic/GuiModel.cpp
client/gui/basic/GuiModel.h
client/gui/basic/GuiRect.cpp
client/gui/basic/GuiRect.h
client/gui/basic/GuiText.cpp
client/gui/basic/GuiText.h
client/gui/compound/GuiImageButton.cpp
client/gui/compound/GuiImageButton.h
client/gui/compound/GuiInventoryList.cpp
client/gui/compound/GuiInventoryList.h
client/gui/compound/GuiLabelledGraph.cpp
client/gui/compound/GuiLabelledGraph.cpp
client/gui/DebugGui.cpp
client/gui/DebugGui.h
client/gui/GameGui.cpp
client/gui/GameGui.h
client/gui/GameGuiBuilder.cpp
client/gui/GameGuiBuilder.h
client/gui/GuiBuilder.cpp
client/gui/GuiBuilder.h
client/gui/GuiComponent.cpp
client/gui/GuiComponent.h
client/gui/SerialGui.h
client/Input.cpp
client/Input.h
client/LocalServerInstance.cpp
client/LocalServerInstance.h
client/menu/MenuSandbox.cpp
client/menu/MenuSandbox.h
client/menu/SubgameConfig.h
client/menu/SubgameDef.h
client/scene/ConnectScene.cpp
client/scene/ConnectScene.h
client/scene/GameScene.cpp
client/scene/GameScene.h
client/scene/LuaErrorScene.cpp
client/scene/LuaErrorScene.h
client/scene/MainMenuScene.cpp
client/scene/MainMenuScene.h
client/scene/Scene.h
client/scene/SceneManager.cpp
client/scene/SceneManager.h
client/stream/ChunkMeshDetails.h
client/stream/MeshGenStream.cpp
client/stream/MeshGenStream.h
client/stream/WorldInterpolationStream.cpp
client/stream/WorldInterpolationStream.h
client/Window.cpp
client/Window.h
game/atlas/asset/AssetStorage.h
game/atlas/asset/AssetType.h
game/atlas/asset/AtlasRef.h
game/atlas/asset/ModelStore.h
game/atlas/asset/SerializedModel.h
game/atlas/asset/ServerTexture.h
game/atlas/BiomeAtlas.cpp
game/atlas/BiomeAtlas.h
game/atlas/DefinitionAtlas.cpp
game/atlas/DefinitionAtlas.h
game/atlas/LocalBiomeAtlas.cpp
game/atlas/LocalBiomeAtlas.h
game/atlas/LocalDefinitionAtlas.cpp
game/atlas/LocalDefinitionAtlas.h
game/atlas/ServerBiomeAtlas.cpp
game/atlas/ServerBiomeAtlas.h
game/atlas/ServerDefinitionAtlas.cpp
game/atlas/ServerDefinitionAtlas.h
game/atlas/TextureAtlas.cpp
game/atlas/TextureAtlas.h
client/Client.cpp
client/Client.h
client/conn/ClientNetworkInterpreter.cpp
client/conn/ClientNetworkInterpreter.h
client/conn/ServerConnection.cpp
client/conn/ServerConnection.h
client/entity/ParticleEntity.cpp
client/entity/ParticleEntity.h
client/entity/PlayerEntity.h
client/entity/WireframeEntity.cpp
client/entity/WireframeEntity.h
client/graph/Camera.cpp
client/graph/Camera.h
client/graph/Drawable.h
client/graph/DrawableGroup.cpp
client/graph/DrawableGroup.h
client/graph/Font.cpp
client/graph/Font.h
client/graph/mesh/ChunkMesh.cpp
client/graph/mesh/ChunkMesh.h
client/graph/mesh/ChunkMeshGenerator.cpp
client/graph/mesh/ChunkMeshGenerator.h
client/graph/mesh/ChunkRenderElem.h
client/graph/mesh/ChunkVertex.h
client/graph/mesh/EntityMesh.cpp
client/graph/mesh/EntityMesh.h
client/graph/mesh/EntityVertex.h
client/graph/mesh/Mesh.cpp
client/graph/mesh/Mesh.h
client/graph/mesh/MeshChunk.cpp
client/graph/mesh/MeshChunk.h
client/graph/Model.cpp
client/graph/Model.h
client/graph/ModelAnimation.cpp
client/graph/ModelAnimation.h
client/graph/ModelBone.cpp
client/graph/ModelBone.h
client/graph/Renderer.cpp
client/graph/Renderer.h
client/graph/shader/BlurShader.cpp
client/graph/shader/BlurShader.h
client/graph/shader/EntityGeometryShader.cpp
client/graph/shader/EntityGeometryShader.h
client/graph/shader/GuiUniforms.h
client/graph/shader/LightingShader.cpp
client/graph/shader/LightingShader.h
client/graph/shader/Shader.cpp
client/graph/shader/Shader.h
client/graph/shader/SSAOShader.cpp
client/graph/shader/SSAOShader.h
client/graph/shader/WorldGeometryShader.cpp
client/graph/shader/WorldGeometryShader.h
client/graph/Texture.cpp
client/graph/Texture.h
client/gui/basic/GuiContainer.cpp
client/gui/basic/GuiContainer.h
client/gui/basic/GuiGraph.cpp
client/gui/basic/GuiGraph.h
client/gui/basic/GuiInventoryItem.cpp
client/gui/basic/GuiInventoryItem.h
client/gui/basic/GuiModel.cpp
client/gui/basic/GuiModel.h
client/gui/basic/GuiRect.cpp
client/gui/basic/GuiRect.h
client/gui/basic/GuiText.cpp
client/gui/basic/GuiText.h
client/gui/compound/GuiImageButton.cpp
client/gui/compound/GuiImageButton.h
client/gui/compound/GuiInventoryList.cpp
client/gui/compound/GuiInventoryList.h
client/gui/compound/GuiLabelledGraph.cpp
client/gui/compound/GuiLabelledGraph.cpp
client/gui/DebugGui.cpp
client/gui/DebugGui.h
client/gui/GameGui.cpp
client/gui/GameGui.h
client/gui/GameGuiBuilder.cpp
client/gui/GameGuiBuilder.h
client/gui/GuiBuilder.cpp
client/gui/GuiBuilder.h
client/gui/GuiComponent.cpp
client/gui/GuiComponent.h
client/gui/SerialGui.h
client/Input.cpp
client/Input.h
client/LocalServerInstance.cpp
client/LocalServerInstance.h
client/menu/MenuSandbox.cpp
client/menu/MenuSandbox.h
client/menu/SubgameConfig.h
client/menu/SubgameDef.h
client/scene/ConnectScene.cpp
client/scene/ConnectScene.h
client/scene/GameScene.cpp
client/scene/GameScene.h
client/scene/LuaErrorScene.cpp
client/scene/LuaErrorScene.h
client/scene/MainMenuScene.cpp
client/scene/MainMenuScene.h
client/scene/Scene.h
client/scene/SceneManager.cpp
client/scene/SceneManager.h
client/stream/ChunkMeshDetails.h
client/stream/MeshGenStream.cpp
client/stream/MeshGenStream.h
client/stream/WorldInterpolationStream.cpp
client/stream/WorldInterpolationStream.h
client/Window.cpp
client/Window.h
game/atlas/asset/AssetStorage.h
game/atlas/asset/AssetType.h
game/atlas/asset/AtlasRef.h
game/atlas/asset/ModelStore.h
game/atlas/asset/SerializedModel.h
game/atlas/asset/ServerTexture.h
game/atlas/BiomeAtlas.cpp
game/atlas/BiomeAtlas.h
game/atlas/DefinitionAtlas.cpp
game/atlas/DefinitionAtlas.h
game/atlas/LocalBiomeAtlas.cpp
game/atlas/LocalBiomeAtlas.h
game/atlas/LocalDefinitionAtlas.cpp
game/atlas/LocalDefinitionAtlas.h
game/atlas/ServerBiomeAtlas.cpp
game/atlas/ServerBiomeAtlas.h
game/atlas/ServerDefinitionAtlas.cpp
game/atlas/ServerDefinitionAtlas.h
game/atlas/TextureAtlas.cpp
game/atlas/TextureAtlas.h
game/def/BiomeDef.h
game/def/BlockDef.cpp
game/def/BlockDef.h
game/def/CraftItemDef.cpp
game/def/CraftItemDef.h
game/def/ItemDef.h
game/def/mesh/BlockModel.cpp
game/def/mesh/BlockModel.h
game/def/mesh/BlockModelVertex.h
game/def/mesh/MeshPart.cpp
game/def/mesh/MeshPart.h
game/def/mesh/SelectionBox.h
game/def/mesh/ShaderMod.h
game/LocalSubgame.cpp
game/LocalSubgame.h
game/ServerSubgame.cpp
game/ServerSubgame.h
game/Subgame.h
lua/Callback.h
lua/customization/vec3.hpp
lua/ErrorFormatter.cpp
lua/ErrorFormatter.h
lua/LocalLuaParser.cpp
lua/LocalLuaParser.h
lua/LocalModHandler.cpp
lua/LocalModHandler.h
lua/LuaKeybindHandler.cpp
lua/LuaKeybindHandler.h
lua/LuaMod.cpp
lua/LuaMod.h
lua/LuaParser.cpp
lua/LuaParser.h
lua/modules/BaseModule.h
lua/modules/create_structure.h
lua/modules/Dimension.cpp
lua/modules/Dimension.h
lua/modules/mSetGui.h
lua/modules/mStartGame.h
lua/modules/SubgameModule.cpp
lua/modules/SubgameModule.h
lua/modules/Time.cpp
lua/modules/Time.h
lua/register/RegisterBiome.h
game/def/BlockDef.cpp
game/def/BlockDef.h
game/def/CraftItemDef.cpp
game/def/CraftItemDef.h
game/def/ItemDef.h
game/def/mesh/BlockModel.cpp
game/def/mesh/BlockModel.h
game/def/mesh/BlockModelVertex.h
game/def/mesh/MeshPart.cpp
game/def/mesh/MeshPart.h
game/def/mesh/SelectionBox.h
game/def/mesh/ShaderMod.h
game/LocalSubgame.cpp
game/LocalSubgame.h
game/ServerSubgame.cpp
game/ServerSubgame.h
game/Subgame.h
lua/Callback.h
lua/customization/vec3.hpp
lua/ErrorFormatter.cpp
lua/ErrorFormatter.h
lua/LocalLuaParser.cpp
lua/LocalLuaParser.h
lua/LocalModHandler.cpp
lua/LocalModHandler.h
lua/LuaKeybindHandler.cpp
lua/LuaKeybindHandler.h
lua/LuaMod.cpp
lua/LuaMod.h
lua/LuaParser.cpp
lua/LuaParser.h
lua/modules/BaseModule.h
lua/modules/create_structure.h
lua/modules/Dimension.cpp
lua/modules/Dimension.h
lua/modules/mSetGui.h
lua/modules/mStartGame.h
lua/modules/SubgameModule.cpp
lua/modules/SubgameModule.h
lua/modules/Time.cpp
lua/modules/Time.h
lua/register/RegisterBiome.h
lua/register/RegisterBlock.h
lua/register/RegisterItem.h
lua/register/RegisterKeybind.h
lua/ServerLuaParser.cpp
lua/ServerLuaParser.h
lua/ServerModHandler.cpp
lua/ServerModHandler.h
lua/usertype/AnimationManager.cpp
lua/usertype/AnimationManager.h
lua/usertype/BaseUsertype.h
lua/usertype/Dimension.cpp
lua/usertype/Dimension.h
lua/usertype/Entity.cpp
lua/usertype/Entity.h
lua/usertype/Inventory.cpp
lua/usertype/Inventory.h
lua/usertype/InventoryList.cpp
lua/usertype/InventoryList.h
lua/usertype/ItemStack.cpp
lua/usertype/ItemStack.h
lua/usertype/LuaGuiElement.cpp
lua/usertype/LuaGuiElement.h
lua/usertype/Player.cpp
lua/usertype/Player.h
lua/usertype/SubgameUsertype.h
lua/usertype/Target.cpp
lua/usertype/Target.h
server/Server.cpp
server/Server.h
server/ServerClient.cpp
server/ServerClient.h
server/ServerClients.cpp
server/ServerClients.h
server/ServerConfig.cpp
server/ServerConfig.h
server/stream/ServerGenStream.cpp
server/stream/ServerGenStream.h
server/stream/ServerPacketStream.cpp
server/stream/ServerPacketStream.h
StartGame.h
util/Any.h
util/CovariantPtr.h
util/frustum/Frustum.cpp
util/frustum/Frustum.h
util/frustum/FrustumAABB.cpp
util/frustum/FrustumAABB.h
util/frustum/FrustumPlane.cpp
util/frustum/FrustumPlane.h
util/Interp.h
util/Lockable.h
util/Log.h
util/Mat4Conv.h
util/net/Address.h
util/net/Deserializer.h
util/net/NetHandler.cpp
util/net/NetHandler.h
util/net/NetState.h
util/net/Packet.cpp
util/net/Packet.h
util/net/PacketView.cpp
util/net/PacketView.h
util/net/Serializer.h
util/Ray.cpp
util/Ray.h
util/RIE.h
util/Schematic.cpp
util/Schematic.h
util/Space.h
util/Target.cpp
util/Target.h
util/Timer.cpp
util/Timer.h
util/Util.h
util/Vec.h
util/Voronoi3D.cpp
util/Voronoi3D.h
world/dim/chunk/Chunk.cpp
world/dim/chunk/Chunk.h
world/dim/chunk/MapBlock.cpp
world/dim/chunk/MapBlock.h
world/dim/chunk/Region.cpp
world/dim/chunk/Region.h
world/dim/Dimension.cpp
world/dim/Dimension.h
world/dim/DimensionBase.cpp
world/dim/DimensionBase.h
world/dim/ent/AnimationSegment.h
world/dim/ent/AnimationState.cpp
world/dim/ent/AnimationState.h
world/dim/ent/AnimChannel.cpp
world/dim/ent/AnimChannel.h
world/dim/ent/Collision.cpp
world/dim/ent/Collision.h
world/dim/ent/DrawableEntity.cpp
world/dim/ent/DrawableEntity.h
world/dim/ent/Entity.cpp
world/dim/ent/Entity.h
world/dim/ent/LocalLuaEntity.cpp
world/dim/ent/LocalLuaEntity.h
world/dim/ent/LuaEntity.cpp
world/dim/ent/LuaEntity.h
world/dim/ent/ServerLuaEntity.cpp
world/dim/ent/ServerLuaEntity.h
world/dim/file/FileManipulator.cpp
world/dim/file/FileManipulator.h
world/dim/LocalDimension.cpp
world/dim/LocalDimension.h
world/dim/ServerDimension.cpp
world/dim/ServerDimension.h
world/gen/MapGen.cpp
world/gen/MapGen.h
world/gen/MapGenProps.cpp
world/gen/MapGenProps.h
world/gen/NoiseSample.cpp
world/gen/NoiseSample.h
world/inv/Inventory.cpp
world/inv/Inventory.h
world/inv/InventoryList.cpp
world/inv/InventoryList.h
world/inv/InventoryRefs.cpp
world/inv/InventoryRefs.h
world/inv/ItemStack.cpp
world/inv/ItemStack.h
world/inv/LocalInventory.cpp
world/inv/LocalInventory.h
world/inv/LocalInventoryRefs.cpp
world/inv/LocalInventoryRefs.h
world/inv/ServerInventory.cpp
world/inv/ServerInventory.h
world/inv/ServerInventoryList.cpp
world/inv/ServerInventoryList.h
world/inv/ServerInventoryRefs.cpp
world/inv/ServerInventoryRefs.h
world/LocalWorld.cpp
world/LocalWorld.h
world/player/LocalPlayer.cpp
world/player/LocalPlayer.h
world/player/Player.cpp
world/player/Player.h
world/player/ServerPlayer.cpp
world/player/ServerPlayer.h
world/ServerWorld.cpp
world/ServerWorld.h
world/World.cpp
world/World.h
lua/register/RegisterKeybind.h
lua/ServerLuaParser.cpp
lua/ServerLuaParser.h
lua/ServerModHandler.cpp
lua/ServerModHandler.h
lua/usertype/AnimationManager.cpp
lua/usertype/AnimationManager.h
lua/usertype/BaseUsertype.h
lua/usertype/Dimension.cpp
lua/usertype/Dimension.h
lua/usertype/Entity.cpp
lua/usertype/Entity.h
lua/usertype/Inventory.cpp
lua/usertype/Inventory.h
lua/usertype/InventoryList.cpp
lua/usertype/InventoryList.h
lua/usertype/ItemStack.cpp
lua/usertype/ItemStack.h
lua/usertype/LuaGuiElement.cpp
lua/usertype/LuaGuiElement.h
lua/usertype/Player.cpp
lua/usertype/Player.h
lua/usertype/SubgameUsertype.h
lua/usertype/Target.cpp
lua/usertype/Target.h
server/Server.cpp
server/Server.h
server/ServerClient.cpp
server/ServerClient.h
server/ServerClients.cpp
server/ServerClients.h
server/ServerConfig.cpp
server/ServerConfig.h
server/stream/ServerGenStream.cpp
server/stream/ServerGenStream.h
server/stream/ServerPacketStream.cpp
server/stream/ServerPacketStream.h
StartGame.h
util/Any.h
util/CovariantPtr.h
util/frustum/Frustum.cpp
util/frustum/Frustum.h
util/frustum/FrustumAABB.cpp
util/frustum/FrustumAABB.h
util/frustum/FrustumPlane.cpp
util/frustum/FrustumPlane.h
util/Interp.h
util/Lockable.h
util/Log.h
util/Mat4Conv.h
util/net/Address.h
util/net/Deserializer.h
util/net/NetHandler.cpp
util/net/NetHandler.h
util/net/NetState.h
util/net/Packet.cpp
util/net/Packet.h
util/net/PacketView.cpp
util/net/PacketView.h
util/net/Serializer.h
util/Ray.cpp
util/Ray.h
util/RIE.h
util/Schematic.cpp
util/Schematic.h
util/Space.h
util/Target.cpp
util/Target.h
util/Timer.cpp
util/Timer.h
util/Util.h
util/Vec.h
util/Voronoi3D.cpp
util/Voronoi3D.h
world/dim/chunk/Chunk.cpp
world/dim/chunk/Chunk.h
world/dim/chunk/MapBlock.cpp
world/dim/chunk/MapBlock.h
world/dim/chunk/Region.cpp
world/dim/chunk/Region.h
world/dim/Dimension.cpp
world/dim/Dimension.h
world/dim/DimensionBase.cpp
world/dim/DimensionBase.h
world/dim/ent/AnimationSegment.h
world/dim/ent/AnimationState.cpp
world/dim/ent/AnimationState.h
world/dim/ent/AnimChannel.cpp
world/dim/ent/AnimChannel.h
world/dim/ent/Collision.cpp
world/dim/ent/Collision.h
world/dim/ent/DrawableEntity.cpp
world/dim/ent/DrawableEntity.h
world/dim/ent/Entity.cpp
world/dim/ent/Entity.h
world/dim/ent/LocalLuaEntity.cpp
world/dim/ent/LocalLuaEntity.h
world/dim/ent/LuaEntity.cpp
world/dim/ent/LuaEntity.h
world/dim/ent/ServerLuaEntity.cpp
world/dim/ent/ServerLuaEntity.h
world/dim/file/FileManipulator.cpp
world/dim/file/FileManipulator.h
world/dim/LocalDimension.cpp
world/dim/LocalDimension.h
world/dim/ServerDimension.cpp
world/dim/ServerDimension.h
world/gen/MapGen.cpp
world/gen/MapGen.h
world/gen/MapGenProps.cpp
world/gen/MapGenProps.h
world/gen/NoiseSample.cpp
world/gen/NoiseSample.h
world/inv/Inventory.cpp
world/inv/Inventory.h
world/inv/InventoryList.cpp
world/inv/InventoryList.h
world/inv/InventoryRefs.cpp
world/inv/InventoryRefs.h
world/inv/ItemStack.cpp
world/inv/ItemStack.h
world/inv/LocalInventory.cpp
world/inv/LocalInventory.h
world/inv/LocalInventoryRefs.cpp
world/inv/LocalInventoryRefs.h
world/inv/ServerInventory.cpp
world/inv/ServerInventory.h
world/inv/ServerInventoryList.cpp
world/inv/ServerInventoryList.h
world/inv/ServerInventoryRefs.cpp
world/inv/ServerInventoryRefs.h
world/LocalWorld.cpp
world/LocalWorld.h
world/player/LocalPlayer.cpp
world/player/LocalPlayer.h
world/player/Player.cpp
world/player/Player.h
world/player/ServerPlayer.cpp
world/player/ServerPlayer.h
world/ServerWorld.cpp
world/ServerWorld.h
world/World.cpp
world/World.h
util/net/Address.cpp util/Bounds.cpp util/Bounds.h lua/register/CreateRegister.h lua/register/CreateRegister.cpp)
target_include_directories(Zepha_Core PUBLIC .)

View File

@ -21,12 +21,13 @@
/**
* Main entrance point to the program. (Am I really describing what the main function is?)
* Intentionally kept minimal to allow for testing. Real startup logic is done in StartGame. *
* Intentionally kept minimal to allow for testing. Real startup logic is done in StartGame.
*
* @param argc - Argument array length
* @param argv - Argument array
* @returns - A numerical value indicating exit status.
*/
int main(int argc, char* argv[]) {
return StartGame(argc, argv);
return StartGame(argc, argv);
}

View File

@ -11,7 +11,9 @@
#include "client/Client.h"
#include "server/Server.h"
enum class Mode { CLIENT, SERVER };
enum class Mode {
CLIENT, SERVER
};
/**
@ -23,22 +25,21 @@ enum class Mode { CLIENT, SERVER };
*/
std::map<std::string, std::string> ParseArgs(int argc, char* argv[]) {
//Collect arguments into `args` map
std::map<std::string, std::string> args;
for (int i = 1; i < argc; i++) {
std::string arg(argv[i]);
size_t equals = arg.find('=');
std::string first = (equals == -1) ? arg : arg.substr(0, equals);
if (args.count(first)) throw std::invalid_argument("Duplicate argument " + first + ".");
if (equals == -1) args.emplace(first, "");
else if (equals == arg.length() - 1) throw std::invalid_argument("Empty argument " + first + ".");
else args.emplace(first, arg.substr(equals + 1, arg.length()));
}
return args;
std::map<std::string, std::string> args;
for (int i = 1; i < argc; i++) {
std::string arg(argv[i]);
size_t equals = arg.find('=');
std::string first = (equals == -1) ? arg : arg.substr(0, equals);
if (args.count(first)) throw std::invalid_argument("Duplicate argument " + first + ".");
if (equals == -1) args.emplace(first, "");
else if (equals == arg.length() - 1) throw std::invalid_argument("Empty argument " + first + ".");
else args.emplace(first, arg.substr(equals + 1, arg.length()));
}
return args;
}
@ -50,74 +51,63 @@ std::map<std::string, std::string> ParseArgs(int argc, char* argv[]) {
*/
int StartGame(int argc, char* argv[]) {
Mode mode = Mode::CLIENT;
try {
unsigned short port = Address::DEFAULT_PORT;
std::string subgame = "";
bool ascii = true;
/**
* Handle command line arguments.
* @arg mode ("client" | "server") - Whether to initialize a client instance, or a server. Defaults to "client".
* @arg port (unsigned short) - The port that the server should listen on. Defaults to Address::DEFAULT_PORT.
* @arg subgame (std::string) - The subgame that the server should load.
* @arg noascii - Switch to disable ASCII from the console output.
*/
for (auto arg : ParseArgs(argc, argv)) {
switch (Util::hash(arg.first.c_str())) {
default:
throw std::runtime_error("Invalid argument '" + arg.first + "'.");
case Util::hash("--mode"):
if (arg.second == "client") mode = Mode::CLIENT;
else if (arg.second == "server") mode = Mode::SERVER;
else throw std::runtime_error("Invalid mode specified.");
break;
Mode mode = Mode::CLIENT;
try {
unsigned short port = Address::DEFAULT_PORT;
std::string subgame = "";
bool ascii = true;
/**
* Handle command line arguments.
* @arg mode ("client" | "server") - Whether to initialize a client instance, or a server. Defaults to "client".
* @arg port (unsigned short) - The port that the server should listen on. Defaults to Address::DEFAULT_PORT.
* @arg subgame (std::string) - The subgame that the server should load.
* @arg noascii - Switch to disable ASCII from the console output.
*/
for (auto arg : ParseArgs(argc, argv)) {
switch (Util::hash(arg.first.c_str())) {
default: throw std::runtime_error("Invalid argument '" + arg.first + "'.");
case Util::hash("--mode"):
if (arg.second == "client") mode = Mode::CLIENT;
else if (arg.second == "server") mode = Mode::SERVER;
else throw std::runtime_error("Invalid mode specified.");
break;
// case Util::hash("--address"):
// addr.host = arg.second;
// break;
case Util::hash("--port"):
port = static_cast<unsigned short>(stoi(arg.second));
break;
case Util::hash("--subgame"):
subgame = arg.second;
break;
case Util::hash("--noascii"):
ascii = false;
break;
}
}
if (ascii) {
Log::clear();
std::cout <<
"\n"
"\t\t ____ ____ ____ _ _ __ \n"
"\t\t(__ )( __)( _ \\/ )( \\ / _\\ \n"
"\t\t / _/ ) _) ) __/) __ (/ \\\n"
"\t\t(____)(____)(__) \\_)(_/\\_/\\_/\n" << std::endl;
}
switch (mode) {
case Mode::CLIENT: {
Client c({1366, 768});
break; }
case Mode::SERVER: {
Server s(port, subgame);
break; }
}
return 0;
}
catch (const std::exception& e) {
std::cout << Log::err << "Zepha failed to start.\n" << e.what() << Log::endl;
return 1;
}
case Util::hash("--port"): port = static_cast<unsigned short>(stoi(arg.second));
break;
case Util::hash("--subgame"): subgame = arg.second;
break;
case Util::hash("--noascii"): ascii = false;
break;
}
}
if (ascii) {
Log::clear();
std::cout <<
"\n"
"\t\t ____ ____ ____ _ _ __ \n"
"\t\t(__ )( __)( _ \\/ )( \\ / _\\ \n"
"\t\t / _/ ) _) ) __/) __ (/ \\\n"
"\t\t(____)(____)(__) \\_)(_/\\_/\\_/\n" << std::endl;
}
if (mode == Mode::CLIENT) Client({ 1366, 768 });
else Server(port, subgame);
return 0;
}
catch (const std::exception& e) {
std::cout << Log::err << "Zepha failed to start.\n" << e.what() << Log::endl;
return 1;
}
}

View File

@ -18,12 +18,12 @@
*/
Client::Client(glm::ivec2 window) :
renderer(window) {
std::cout << Log::info << "Starting Zepha Client." << Log::endl;
scene.setScene(std::make_unique<MainMenuScene>(*this));
while (!renderer.window.shouldClose()) loop();
renderer(window) {
std::cout << Log::info << "Starting Zepha Client." << Log::endl;
scene.setScene(std::make_unique<MainMenuScene>(*this));
while (!renderer.window.shouldClose()) loop();
}
@ -33,7 +33,7 @@ Client::Client(glm::ivec2 window) :
*/
double Client::getDelta() {
return delta;
return delta;
}
@ -44,11 +44,11 @@ double Client::getDelta() {
*/
void Client::startLocalServer(const std::string& subgame) {
//TODO: Implement Local Server
//TODO: Implement Local Server
// localServer = std::make_shared<LocalServerInstance>(executablePath, addr.port, state.subgame);
// localServer->start();
scene.setScene(std::make_unique<ConnectScene>(*this, Address { "127.0.0.1", Address::DEFAULT_PORT }));
scene.setScene(std::make_unique<ConnectScene>(*this, Address{ "127.0.0.1", Address::DEFAULT_PORT }));
}
@ -58,12 +58,12 @@ void Client::startLocalServer(const std::string& subgame) {
*/
void Client::loop() {
double now = glfwGetTime();
delta = now - timeElapsed;
timeElapsed = now;
glfwPollEvents();
scene.update();
renderer.update(delta);
double now = glfwGetTime();
delta = now - timeElapsed;
timeElapsed = now;
glfwPollEvents();
scene.update();
renderer.update(delta);
}

View File

@ -16,26 +16,27 @@
class LocalServerInstance;
class Client {
public:
Client(const Client& o) = delete;
explicit Client(glm::ivec2 window);
double getDelta();
void startLocalServer(const std::string& subgame);
Renderer renderer;
SceneManager scene;
ServerConnection connection {};
std::shared_ptr<LocalSubgame> game = std::make_shared<LocalSubgame>("../assets/textures");
private:
void loop();
std::shared_ptr<LocalServerInstance> localServer = nullptr;
double delta = 0;
double timeElapsed = 0;
public:
Client(const Client& o) = delete;
explicit Client(glm::ivec2 window);
double getDelta();
void startLocalServer(const std::string& subgame);
Renderer renderer;
SceneManager scene;
ServerConnection connection{};
std::shared_ptr<LocalSubgame> game = std::make_shared<LocalSubgame>("../assets/textures");
private:
void loop();
std::shared_ptr<LocalServerInstance> localServer = nullptr;
double delta = 0;
double timeElapsed = 0;
};

View File

@ -11,161 +11,161 @@
#include "Window.h"
Input::Input() {
for (bool& key : keysDown) key = false;
for (bool& key : keysPressed) key = false;
for (bool& key : keysReleased) key = false;
for (bool& key : keysNew) key = false;
for (bool& key : keysDown) key = false;
for (bool& key : keysPressed) key = false;
for (bool& key : keysReleased) key = false;
for (bool& key : keysNew) key = false;
}
void Input::init(GLFWwindow *window, glm::ivec2* winDimensions) {
this->window = window;
this->winDimensions = winDimensions;
glfwSetKeyCallback(window, keyCallback);
glfwSetScrollCallback(window, scrollCallback);
void Input::init(GLFWwindow* window, glm::ivec2* winDimensions) {
this->window = window;
this->winDimensions = winDimensions;
glfwSetKeyCallback(window, keyCallback);
glfwSetScrollCallback(window, scrollCallback);
}
void Input::setCallback(std::function<void(bool, int)> callback) {
this->callback = callback;
this->callback = callback;
}
void Input::update() {
for (bool &key : keysPressed) key = false;
for (bool &key : keysReleased) key = false;
for (int i = 0; i < 1024; i++) {
bool key = keysNew[i];
if (key) {
if (!keysDown[i]) {
keysPressed[i] = true;
if (callback) callback(true, i);
}
keysDown[i] = true;
}
else {
if (keysDown[i]) {
keysReleased[i] = true;
if (callback) callback(false, i);
}
keysDown[i] = false;
}
}
for (auto& s : mouseState) {
s.pressed = false;
s.released = false;
}
for (int i = 0; i < 12; i++) {
keysNew[i] = false;
}
updateMouse(0);
updateMouse(1);
updateMouse(2);
if (glfwGetWindowAttrib(window, GLFW_FOCUSED) == GL_FALSE) {
mouseIsLocked = false;
delta = {};
}
else {
double mouseX, mouseY;
glfwGetCursorPos(window, &mouseX, &mouseY);
if (!mouseIsLocked) {
if (!forceMouseUnlocked && mousePressed(GLFW_MOUSE_BUTTON_LEFT)) {
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
glfwSetCursorPos(window, winDimensions->x / 2, winDimensions->y / 2);
mouseIsLocked = true;
}
}
else {
delta = {mouseX - (winDimensions->x / 2), -(mouseY - (winDimensions->y / 2))};
glfwSetCursorPos(window, winDimensions->x / 2, winDimensions->y / 2);
}
}
for (bool& key : keysPressed) key = false;
for (bool& key : keysReleased) key = false;
for (int i = 0; i < 1024; i++) {
bool key = keysNew[i];
if (key) {
if (!keysDown[i]) {
keysPressed[i] = true;
if (callback) callback(true, i);
}
keysDown[i] = true;
}
else {
if (keysDown[i]) {
keysReleased[i] = true;
if (callback) callback(false, i);
}
keysDown[i] = false;
}
}
for (auto& s : mouseState) {
s.pressed = false;
s.released = false;
}
for (int i = 0; i < 12; i++) {
keysNew[i] = false;
}
updateMouse(0);
updateMouse(1);
updateMouse(2);
if (glfwGetWindowAttrib(window, GLFW_FOCUSED) == GL_FALSE) {
mouseIsLocked = false;
delta = {};
}
else {
double mouseX, mouseY;
glfwGetCursorPos(window, &mouseX, &mouseY);
if (!mouseIsLocked) {
if (!forceMouseUnlocked && mousePressed(GLFW_MOUSE_BUTTON_LEFT)) {
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
glfwSetCursorPos(window, winDimensions->x / 2, winDimensions->y / 2);
mouseIsLocked = true;
}
}
else {
delta = { mouseX - (winDimensions->x / 2), -(mouseY - (winDimensions->y / 2)) };
glfwSetCursorPos(window, winDimensions->x / 2, winDimensions->y / 2);
}
}
}
bool Input::keyDown(int key) {
return keysDown[key];
return keysDown[key];
}
bool Input::keyPressed(int key) {
return keysPressed[key];
return keysPressed[key];
}
bool Input::keyReleased(int key) {
return keysReleased[key];
return keysReleased[key];
}
bool Input::mouseDown(int button) {
return mouseState[button].down;
return mouseState[button].down;
}
bool Input::mousePressed(int button) {
return mouseState[button].pressed;
return mouseState[button].pressed;
}
bool Input::mouseReleased(int button) {
return mouseState[button].released;
return mouseState[button].released;
}
void Input::updateMouse(int button) {
if (glfwGetMouseButton(window, button) == GLFW_PRESS) {
if (!mouseState[button].down) mouseState[button].pressed = true;
mouseState[button].down = true;
}
else {
if (mouseState[button].down) mouseState[button].released = true;
mouseState[button].down = false;
}
if (glfwGetMouseButton(window, button) == GLFW_PRESS) {
if (!mouseState[button].down) mouseState[button].pressed = true;
mouseState[button].down = true;
}
else {
if (mouseState[button].down) mouseState[button].released = true;
mouseState[button].down = false;
}
}
void Input::keyCallback(GLFWwindow* window, int key, int code, int action, int mode) {
auto w = static_cast<Window*>(glfwGetWindowUserPointer(window));
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GL_TRUE);
if (key >= 32 && key < 1024) {
if (action == GLFW_PRESS) w->input.keysNew[key] = true;
else if (action == GLFW_RELEASE) w->input.keysNew[key] = false;
}
auto w = static_cast<Window*>(glfwGetWindowUserPointer(window));
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GL_TRUE);
if (key >= 32 && key < 1024) {
if (action == GLFW_PRESS) w->input.keysNew[key] = true;
else if (action == GLFW_RELEASE) w->input.keysNew[key] = false;
}
}
void Input::scrollCallback(GLFWwindow *window, double xO, double yO) {
auto w = static_cast<Window*>(glfwGetWindowUserPointer(window));
if (xO > 0) {
//Right
w->input.keysNew[11] = true;
}
else if (xO < 0) {
// Left
w->input.keysNew[10] = true;
}
if (yO > 0) {
// Up
w->input.keysNew[8] = true;
}
else if (yO < 0) {
// Down
w->input.keysNew[9] = true;
}
void Input::scrollCallback(GLFWwindow* window, double xO, double yO) {
auto w = static_cast<Window*>(glfwGetWindowUserPointer(window));
if (xO > 0) {
//Right
w->input.keysNew[11] = true;
}
else if (xO < 0) {
// Left
w->input.keysNew[10] = true;
}
if (yO > 0) {
// Up
w->input.keysNew[8] = true;
}
else if (yO < 0) {
// Down
w->input.keysNew[9] = true;
}
}
void Input::lockMouse(bool lock) {
forceMouseUnlocked = !lock;
mouseIsLocked = lock;
glfwSetCursorPos(window, winDimensions->x / 2, winDimensions->y / 2);
glfwSetInputMode(window, GLFW_CURSOR, (mouseIsLocked ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL));
delta = {};
forceMouseUnlocked = !lock;
mouseIsLocked = lock;
glfwSetCursorPos(window, winDimensions->x / 2, winDimensions->y / 2);
glfwSetInputMode(window, GLFW_CURSOR, (mouseIsLocked ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL));
delta = {};
}
glm::ivec2 Input::mousePos() {
double xPos, yPos;
glfwGetCursorPos(window, &xPos, &yPos);
return glm::ivec2 { static_cast<int>(xPos), static_cast<int>(yPos) };
double xPos, yPos;
glfwGetCursorPos(window, &xPos, &yPos);
return glm::ivec2{ static_cast<int>(xPos), static_cast<int>(yPos) };
}
glm::vec2 Input::mouseDelta() {
return delta;
return delta;
}

View File

@ -9,43 +9,58 @@
#include <glm/vec2.hpp>
class Input {
public:
Input();
void init(GLFWwindow* window, glm::ivec2* winDimensions);
void setCallback(std::function<void(bool, int)> callback);
void update();
bool keyDown(int key);
bool keyPressed(int key);
bool keyReleased(int key);
bool mouseDown(int button);
bool mousePressed(int button);
bool mouseReleased(int button);
void lockMouse(bool lock);
glm::ivec2 mousePos();
glm::vec2 mouseDelta();
private:
void updateMouse(int key);
static void keyCallback(GLFWwindow* window, int key, int code, int action, int mode);
static void scrollCallback(GLFWwindow* window, double, double yO);
GLFWwindow* window = nullptr;
glm::ivec2* winDimensions = nullptr;
bool keysNew[1024] {false};
bool keysDown[1024] {false};
bool keysPressed[1024] {false};
bool keysReleased[1024] {false};
struct mouse { bool down = false; bool pressed = false; bool released = false; };
std::array<mouse, 3> mouseState {};
glm::vec2 delta;
bool mouseIsLocked = false;
bool forceMouseUnlocked = false;
std::function<void(bool, int)> callback = nullptr;
public:
Input();
void init(GLFWwindow* window, glm::ivec2* winDimensions);
void setCallback(std::function<void(bool, int)> callback);
void update();
bool keyDown(int key);
bool keyPressed(int key);
bool keyReleased(int key);
bool mouseDown(int button);
bool mousePressed(int button);
bool mouseReleased(int button);
void lockMouse(bool lock);
glm::ivec2 mousePos();
glm::vec2 mouseDelta();
private:
void updateMouse(int key);
static void keyCallback(GLFWwindow* window, int key, int code, int action, int mode);
static void scrollCallback(GLFWwindow* window, double, double yO);
GLFWwindow* window = nullptr;
glm::ivec2* winDimensions = nullptr;
bool keysNew[1024]{ false };
bool keysDown[1024]{ false };
bool keysPressed[1024]{ false };
bool keysReleased[1024]{ false };
struct mouse {
bool down = false;
bool pressed = false;
bool released = false;
};
std::array<mouse, 3> mouseState{};
glm::vec2 delta;
bool mouseIsLocked = false;
bool forceMouseUnlocked = false;
std::function<void(bool, int)> callback = nullptr;
};

View File

@ -7,45 +7,45 @@
#include "server/Server.h"
#include <iostream>
LocalServerInstance::LocalServerInstance(const std::string &path, unsigned short port, const std::string& subgame) :
port(port),
path(path),
subgame(subgame) {}
LocalServerInstance::LocalServerInstance(const std::string& path, unsigned short port, const std::string& subgame) :
port(port),
path(path),
subgame(subgame) {}
bool LocalServerInstance::start() {
#ifndef _WIN32
pid = fork();
if (pid == 0) {
const auto sub = ("--subgame=" + subgame);
char *arr[] = {
const_cast <char*>(""),
pid = fork();
if (pid == 0) {
const auto sub = ("--subgame=" + subgame);
char* arr[] = {
const_cast <char*>(""),
// const_cast <char*>("-iconic"),
const_cast <char*>("-e"),
const_cast <char*>(path.data()),
const_cast <char*>("--mode=server"),
const_cast <char*>(sub.data()),
static_cast<char*>(nullptr)
};
execvp("xterm", arr);
}
return true;
const_cast <char*>("-e"),
const_cast <char*>(path.data()),
const_cast <char*>("--mode=server"),
const_cast <char*>(sub.data()),
static_cast<char*>(nullptr)
};
execvp("xterm", arr);
}
return true;
#else
std::thread([&]() {
Server s(port, subgame);
}).detach();
return true;
std::thread([&]() {
Server s(port, subgame);
}).detach();
return true;
#endif
}
void LocalServerInstance::stop() {
#ifndef _WIN32
if (pid != 0) kill(pid, SIGKILL);
#else
std::cout << Log::err << "Local Server destructor not implemented on Windows!" << Log::endl;
#endif
#ifndef _WIN32
if (pid != 0) kill(pid, SIGKILL);
#else
std::cout << Log::err << "Local Server destructor not implemented on Windows!" << Log::endl;
#endif
}
LocalServerInstance::~LocalServerInstance() {
stop();
stop();
}

View File

@ -7,23 +7,27 @@
#include <string>
#ifndef _WIN32
#include <thread>
#include <zconf.h>
#include <signal.h>
#endif
class LocalServerInstance {
public:
LocalServerInstance(const std::string& path, unsigned short port, const std::string& subgame);
bool start();
void stop();
~LocalServerInstance();
private:
std::string path;
std::string subgame;
unsigned short port = 0;
int pid = 0;
public:
LocalServerInstance(const std::string& path, unsigned short port, const std::string& subgame);
bool start();
void stop();
~LocalServerInstance();
private:
std::string path;
std::string subgame;
unsigned short port = 0;
int pid = 0;
};

View File

@ -6,85 +6,85 @@
#include "util/Log.h"
Window::Window() : Window({800, 600}) {};
Window::Window() : Window({ 800, 600 }) {};
Window::Window(glm::ivec2 win) :
win(win), center(win.x / 2, win.y / 2) {
if (!glfwInit()) {
glfwTerminate();
throw std::runtime_error("Failed to initialize GLFW context.");
}
// Version 3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// Compatibility - No Backwards compat, only forwards
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
// Create the window
if (!(mainWindow = glfwCreateWindow(win.x, win.y, "Zepha", nullptr, nullptr))) {
glfwTerminate();
throw std::runtime_error("Failed to initialize GLFW window.");
}
glfwGetFramebufferSize(mainWindow, &win.x, &win.y);
glfwMakeContextCurrent(mainWindow);
glewExperimental = GL_TRUE;
handCursor = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
// Initialize GLEW
GLenum error;
if ((error = glewInit()) != GLEW_OK) {
glfwTerminate();
glfwDestroyWindow(mainWindow);
printf("%s", reinterpret_cast<const char *>(glewGetErrorString(error)));
throw std::runtime_error("GLEW Fatal error.");
}
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, win.x, win.y);
// Setup callbacks
glfwSetWindowUserPointer(mainWindow, this);
glfwSetScrollCallback(mainWindow, scrollCallback);
glfwSetWindowSizeCallback(mainWindow, resizeCallback);
glfwSetInputMode(mainWindow, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
glfwMaximizeWindow(mainWindow);
input.init(mainWindow, &this->win);
win(win), center(win.x / 2, win.y / 2) {
if (!glfwInit()) {
glfwTerminate();
throw std::runtime_error("Failed to initialize GLFW context.");
}
// Version 3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// Compatibility - No Backwards compat, only forwards
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
// Create the window
if (!(mainWindow = glfwCreateWindow(win.x, win.y, "Zepha", nullptr, nullptr))) {
glfwTerminate();
throw std::runtime_error("Failed to initialize GLFW window.");
}
glfwGetFramebufferSize(mainWindow, &win.x, &win.y);
glfwMakeContextCurrent(mainWindow);
glewExperimental = GL_TRUE;
handCursor = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
// Initialize GLEW
GLenum error;
if ((error = glewInit()) != GLEW_OK) {
glfwTerminate();
glfwDestroyWindow(mainWindow);
printf("%s", reinterpret_cast<const char*>(glewGetErrorString(error)));
throw std::runtime_error("GLEW Fatal error.");
}
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, win.x, win.y);
// Setup callbacks
glfwSetWindowUserPointer(mainWindow, this);
glfwSetScrollCallback(mainWindow, scrollCallback);
glfwSetWindowSizeCallback(mainWindow, resizeCallback);
glfwSetInputMode(mainWindow, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
glfwMaximizeWindow(mainWindow);
input.init(mainWindow, &this->win);
}
void Window::update() {
input.update();
input.update();
}
bool Window::shouldClose() {
return static_cast<bool>(glfwWindowShouldClose(mainWindow));
return static_cast<bool>(glfwWindowShouldClose(mainWindow));
}
void Window::swapBuffers() {
glfwSwapBuffers(mainWindow);
glfwSwapBuffers(mainWindow);
}
void Window::addResizeCallback(const std::string &identifier, std::function<void(glm::ivec2)> cb) {
resizeCallbacks.emplace(identifier, cb);
void Window::addResizeCallback(const std::string& identifier, std::function<void(glm::ivec2)> cb) {
resizeCallbacks.emplace(identifier, cb);
}
void Window::removeResizeCallback(const std::string &identifier) {
resizeCallbacks.erase(identifier);
void Window::removeResizeCallback(const std::string& identifier) {
resizeCallbacks.erase(identifier);
}
glm::ivec2 Window::getSize() {
return win;
return win;
}
void Window::setCursorHand(bool hand) {
glfwSetCursor(mainWindow, hand ? handCursor : nullptr);
glfwSetCursor(mainWindow, hand ? handCursor : nullptr);
}
void Window::scrollCallback(GLFWwindow* window, double xO, double yO) {
@ -93,16 +93,16 @@ void Window::scrollCallback(GLFWwindow* window, double xO, double yO) {
}
void Window::resizeCallback(GLFWwindow* window, int width, int height) {
auto w = static_cast<Window*>(glfwGetWindowUserPointer(window));
glfwGetFramebufferSize(window, &w->win.x, &w->win.y);
glViewport(0, 0, w->win.x, w->win.y);
w->center = glm::ivec2(w->win.x / 2, w->win.y / 2);
for (auto& cb : w->resizeCallbacks) cb.second(w->win);
auto w = static_cast<Window*>(glfwGetWindowUserPointer(window));
glfwGetFramebufferSize(window, &w->win.x, &w->win.y);
glViewport(0, 0, w->win.x, w->win.y);
w->center = glm::ivec2(w->win.x / 2, w->win.y / 2);
for (auto& cb : w->resizeCallbacks) cb.second(w->win);
}
Window::~Window() {
glfwDestroyWindow(mainWindow);
glfwTerminate();
glfwDestroyWindow(mainWindow);
glfwTerminate();
}

View File

@ -11,36 +11,42 @@
#include "Input.h"
class Window {
public:
Window();
Window(glm::ivec2 win);
void update();
bool shouldClose();
void swapBuffers();
void addResizeCallback(const std::string& identifier, std::function<void(glm::ivec2)> cb);
void removeResizeCallback(const std::string& identifier);
glm::ivec2 getSize();
void setCursorHand(bool hand);
~Window();
Input input;
GLFWwindow* mainWindow = nullptr;
private:
static void scrollCallback(GLFWwindow* window, double xO, double yO);
static void resizeCallback(GLFWwindow* window, int width, int height);
GLFWcursor* handCursor = nullptr;
glm::ivec2 win;
glm::ivec2 center;
bool keys[1024] {};
std::map<std::string, std::function<void(glm::ivec2)>> resizeCallbacks;
public:
Window();
Window(glm::ivec2 win);
void update();
bool shouldClose();
void swapBuffers();
void addResizeCallback(const std::string& identifier, std::function<void(glm::ivec2)> cb);
void removeResizeCallback(const std::string& identifier);
glm::ivec2 getSize();
void setCursorHand(bool hand);
~Window();
Input input;
GLFWwindow* mainWindow = nullptr;
private:
static void scrollCallback(GLFWwindow* window, double xO, double yO);
static void resizeCallback(GLFWwindow* window, int width, int height);
GLFWcursor* handCursor = nullptr;
glm::ivec2 win;
glm::ivec2 center;
bool keys[1024]{};
std::map<std::string, std::function<void(glm::ivec2)>> resizeCallbacks;
};

View File

@ -14,126 +14,131 @@
#include "util/net/NetHandler.h"
#include "world/player/LocalPlayer.h"
ClientNetworkInterpreter::ClientNetworkInterpreter(ServerConnection &connection, LocalWorld& world) :
world(world), connection(connection) {}
ClientNetworkInterpreter::ClientNetworkInterpreter(ServerConnection& connection, LocalWorld& world) :
world(world), connection(connection) {}
void ClientNetworkInterpreter::init(std::function<void(std::unique_ptr<PacketView>)> invCallback) {
this->onInvPacket = invCallback;
this->onInvPacket = invCallback;
}
void ClientNetworkInterpreter::update() {
recvPackets = 0;
ENetEvent event;
while (connection.pollEvents(&event)) {
recvPackets++;
switch (event.type) {
default: break;
case ENET_EVENT_TYPE_CONNECT: {
std::cout << Log::info << "Connected to server "
<< NetHandler::intToIPString(event.peer->address.host)
<< ":" << event.peer->address.port << "." << Log::endl;
break;
}
case ENET_EVENT_TYPE_RECEIVE: {
std::unique_ptr<PacketView> p = std::make_unique<PacketView>(event.packet);
receivedPacket(std::move(p));
break;
}
case ENET_EVENT_TYPE_DISCONNECT: {
std::cout << Log::info << "Disconnected from server "
<< event.peer->address.host << ":" << event.peer->address.port << "." << Log::endl;
break;
}
}
}
auto player = world.getPlayer();
if (player) Serializer()
.appendE(NetField::POS).append(player->getPos())
.appendE(NetField::VEL).append(player->getVel())
.appendE(NetField::LOOK_PITCH).append(player->getPitch())
.appendE(NetField::LOOK_YAW).append(player->getYaw())
.packet(Packet::Type::THIS_PLAYER_INFO, false).sendTo(connection.getPeer(), Packet::Channel::INTERACT);
recvPackets = 0;
ENetEvent event;
while (connection.pollEvents(&event)) {
recvPackets++;
switch (event.type) {
default: break;
case ENET_EVENT_TYPE_CONNECT: {
std::cout << Log::info << "Connected to server "
<< NetHandler::intToIPString(event.peer->address.host)
<< ":" << event.peer->address.port << "." << Log::endl;
break;
}
case ENET_EVENT_TYPE_RECEIVE: {
std::unique_ptr<PacketView> p = std::make_unique<PacketView>(event.packet);
receivedPacket(std::move(p));
break;
}
case ENET_EVENT_TYPE_DISCONNECT: {
std::cout << Log::info << "Disconnected from server "
<< event.peer->address.host << ":" << event.peer->address.port << "." << Log::endl;
break;
}
}
}
auto player = world.getPlayer();
if (player)
Serializer()
.appendE(NetField::POS).append(player->getPos())
.appendE(NetField::VEL).append(player->getVel())
.appendE(NetField::LOOK_PITCH).append(player->getPitch())
.appendE(NetField::LOOK_YAW).append(player->getYaw())
.packet(Packet::Type::THIS_PLAYER_INFO, false).sendTo(connection.getPeer(), Packet::Channel::INTERACT);
}
void ClientNetworkInterpreter::receivedPacket(std::unique_ptr<PacketView> p) {
switch (p->type) {
default:
std::cout << Log::err << "Received unknown packet of type " << static_cast<int>(p->type)
<< ". Is the server on a different protocol version?" << Log::endl; break;
case Packet::Type::SERVER_INFO:
serverSideChunkGens = p->d.read<unsigned int>(); break;
case Packet::Type::THIS_PLAYER_INFO:
world.getPlayer()->handleAssertion(p->d); break;
case Packet::Type::PLAYER_ENT_INFO:
world.handlePlayerEntPacket(std::move(p)); break;
case Packet::Type::CHUNK:
case Packet::Type::MAPBLOCK:
world.handleWorldPacket(std::move(p)); break;
case Packet::Type::BLOCK_SET: {
auto pos = p->d.read<glm::ivec3>();
auto block = p->d.read<unsigned int>();
world.getActiveDimension()->setBlock(pos, block);
break; }
case Packet::Type::ENTITY_INFO:
world.getActiveDimension().l()->serverEntitiesInfo(p->d); break;
case Packet::Type::ENTITY_REMOVED:
world.getActiveDimension().l()->serverEntitiesRemoved(p->d); break;
case Packet::Type::INV_DATA:
onInvPacket(std::move(p)); break;
case Packet::Type::INV_INVALID: {
std::string source = p->d.read<std::string>();
std::string list = p->d.read<std::string>();
throw std::runtime_error("Invalid inventory " + source + ":" + list + " was request by client."); }
}
switch (p->type) {
default:
std::cout << Log::err << "Received unknown packet of type " << static_cast<int>(p->type)
<< ". Is the server on a different protocol version?" << Log::endl;
break;
case Packet::Type::SERVER_INFO:serverSideChunkGens = p->d.read<unsigned int>();
break;
case Packet::Type::THIS_PLAYER_INFO:world.getPlayer()->handleAssertion(p->d);
break;
case Packet::Type::PLAYER_ENT_INFO:world.handlePlayerEntPacket(std::move(p));
break;
case Packet::Type::CHUNK:
case Packet::Type::MAPBLOCK:world.handleWorldPacket(std::move(p));
break;
case Packet::Type::BLOCK_SET: {
auto pos = p->d.read<glm::ivec3>();
auto block = p->d.read<unsigned int>();
world.getActiveDimension()->setBlock(pos, block);
break;
}
case Packet::Type::ENTITY_INFO:world.getActiveDimension().l()->serverEntitiesInfo(p->d);
break;
case Packet::Type::ENTITY_REMOVED:world.getActiveDimension().l()->serverEntitiesRemoved(p->d);
break;
case Packet::Type::INV_DATA:onInvPacket(std::move(p));
break;
case Packet::Type::INV_INVALID: {
std::string source = p->d.read<std::string>();
std::string list = p->d.read<std::string>();
throw std::runtime_error("Invalid inventory " + source + ":" + list + " was request by client.");
}
}
}
void ClientNetworkInterpreter::blockHit(const Target &target) {
Serializer().append<glm::ivec3>(target.pos).append(static_cast<unsigned short>(target.face))
.packet(Packet::Type::BLOCK_HIT).sendTo(connection.getPeer(), Packet::Channel::INTERACT);
void ClientNetworkInterpreter::blockHit(const Target& target) {
Serializer().append<glm::ivec3>(target.pos).append(static_cast<unsigned short>(target.face))
.packet(Packet::Type::BLOCK_HIT).sendTo(connection.getPeer(), Packet::Channel::INTERACT);
}
void ClientNetworkInterpreter::blockPlace(const Target &target) {
Serializer().append<glm::ivec3>(target.pos).append(static_cast<unsigned short>(target.face))
.packet(Packet::Type::BLOCK_PLACE).sendTo(connection.getPeer(), Packet::Channel::INTERACT);
void ClientNetworkInterpreter::blockPlace(const Target& target) {
Serializer().append<glm::ivec3>(target.pos).append(static_cast<unsigned short>(target.face))
.packet(Packet::Type::BLOCK_PLACE).sendTo(connection.getPeer(), Packet::Channel::INTERACT);
}
void ClientNetworkInterpreter::blockInteract(const Target &target) {
Serializer().append<glm::ivec3>(target.pos).append(static_cast<unsigned short>(target.face))
.packet(Packet::Type::BLOCK_INTERACT).sendTo(connection.getPeer(), Packet::Channel::INTERACT);
void ClientNetworkInterpreter::blockInteract(const Target& target) {
Serializer().append<glm::ivec3>(target.pos).append(static_cast<unsigned short>(target.face))
.packet(Packet::Type::BLOCK_INTERACT).sendTo(connection.getPeer(), Packet::Channel::INTERACT);
}
void ClientNetworkInterpreter::blockPlaceOrInteract(const Target &target) {
Serializer().append<glm::ivec3>(target.pos).append(static_cast<unsigned short>(target.face))
.packet(Packet::Type::BLOCK_PLACE_OR_INTERACT).sendTo(connection.getPeer(), Packet::Channel::INTERACT);
void ClientNetworkInterpreter::blockPlaceOrInteract(const Target& target) {
Serializer().append<glm::ivec3>(target.pos).append(static_cast<unsigned short>(target.face))
.packet(Packet::Type::BLOCK_PLACE_OR_INTERACT).sendTo(connection.getPeer(), Packet::Channel::INTERACT);
}
void ClientNetworkInterpreter::invWatch(const std::string& inv, const std::string& list) {
Serializer().append(inv).append(list).packet(Packet::Type::INV_WATCH)
.sendTo(connection.getPeer(), Packet::Channel::INTERACT);
Serializer().append(inv).append(list).packet(Packet::Type::INV_WATCH)
.sendTo(connection.getPeer(), Packet::Channel::INTERACT);
}
void ClientNetworkInterpreter::invUnwatch(const std::string& inv, const std::string& list) {
Serializer().append(inv).append(list).packet(Packet::Type::INV_UNWATCH)
.sendTo(connection.getPeer(), Packet::Channel::INTERACT);
Serializer().append(inv).append(list).packet(Packet::Type::INV_UNWATCH)
.sendTo(connection.getPeer(), Packet::Channel::INTERACT);
}
void ClientNetworkInterpreter::invInteract(const std::string &inv, const std::string &list, bool primary, unsigned short ind) {
Serializer().append<unsigned short>(primary).append(inv).append(list).append<unsigned short>(ind)
.packet(Packet::Type::INV_INTERACT).sendTo(connection.getPeer(), Packet::Channel::INTERACT);
void ClientNetworkInterpreter::invInteract(const std::string& inv, const std::string& list, bool primary,
unsigned short ind) {
Serializer().append<unsigned short>(primary).append(inv).append(list).append<unsigned short>(ind)
.packet(Packet::Type::INV_INTERACT).sendTo(connection.getPeer(), Packet::Channel::INTERACT);
}
void ClientNetworkInterpreter::sendPacket(const Packet &packet, Packet::Channel channel) {
packet.sendTo(connection.getPeer(), channel);
void ClientNetworkInterpreter::sendPacket(const Packet& packet, Packet::Channel channel) {
packet.sendTo(connection.getPeer(), channel);
}

View File

@ -13,40 +13,53 @@
#include "client/conn/ServerConnection.h"
class Model;
class Target;
class LocalWorld;
class PacketView;
class LocalPlayer;
class LocalSubgame;
enum class NetPlayerField;
class ClientNetworkInterpreter {
public:
ClientNetworkInterpreter(const ClientNetworkInterpreter& other) = delete;
ClientNetworkInterpreter(ServerConnection& connection, LocalWorld& world);
void init(std::function<void(std::unique_ptr<PacketView>)> invCallback);
void update();
void blockHit(const Target& target);
void blockPlace(const Target& target);
void blockInteract(const Target& target);
void blockPlaceOrInteract(const Target& target);
void invWatch(const std::string& inv, const std::string& list);
void invUnwatch(const std::string& inv, const std::string& list);
void invInteract(const std::string& inv, const std::string& list, bool primary, unsigned short ind);
void sendPacket(const Packet& packet, Packet::Channel channel);
int recvPackets = 0;
int serverSideChunkGens = 0;
private:
void receivedPacket(std::unique_ptr<PacketView> ePacket);
LocalWorld& world;
ServerConnection& connection;
std::function<void(std::unique_ptr<PacketView>)> onInvPacket;
public:
ClientNetworkInterpreter(const ClientNetworkInterpreter& other) = delete;
ClientNetworkInterpreter(ServerConnection& connection, LocalWorld& world);
void init(std::function<void(std::unique_ptr<PacketView>)> invCallback);
void update();
void blockHit(const Target& target);
void blockPlace(const Target& target);
void blockInteract(const Target& target);
void blockPlaceOrInteract(const Target& target);
void invWatch(const std::string& inv, const std::string& list);
void invUnwatch(const std::string& inv, const std::string& list);
void invInteract(const std::string& inv, const std::string& list, bool primary, unsigned short ind);
void sendPacket(const Packet& packet, Packet::Channel channel);
int recvPackets = 0;
int serverSideChunkGens = 0;
private:
void receivedPacket(std::unique_ptr<PacketView> ePacket);
LocalWorld& world;
ServerConnection& connection;
std::function<void(std::unique_ptr<PacketView>)> onInvPacket;
};

View File

@ -12,94 +12,94 @@
#include "util/net/NetHandler.h"
void ServerConnection::attemptConnect(Address addr) {
if (state != State::UNCONNECTED) {
disconnect();
}
if (enet_initialize() != 0) {
std::cout << Log::err << "Failed to Initialize ENet." << Log::endl;
state = State::ENET_ERROR;
return;
}
host = enet_host_create(nullptr, 1, NetHandler::PACKET_CHANNELS, 0, 0);
if (host == nullptr) {
std::cout << Log::err << "Failed to create ENet client." << Log::endl;
state = State::ENET_ERROR;
return;
}
ENetAddress eNetAddr;
enet_address_set_host(&eNetAddr, addr.host.c_str());
eNetAddr.port = addr.port;
peer = enet_host_connect(host, &eNetAddr, NetHandler::PACKET_CHANNELS, 0);
if (peer == nullptr) {
std::cout << Log::err << "Failed to initialize ENet peer." << Log::endl;
state = State::ENET_ERROR;
return;
}
connectionTime = std::chrono::high_resolution_clock::now();
state = State::ATTEMPTING_CONNECT;
if (state != State::UNCONNECTED) {
disconnect();
}
if (enet_initialize() != 0) {
std::cout << Log::err << "Failed to Initialize ENet." << Log::endl;
state = State::ENET_ERROR;
return;
}
host = enet_host_create(nullptr, 1, NetHandler::PACKET_CHANNELS, 0, 0);
if (host == nullptr) {
std::cout << Log::err << "Failed to create ENet client." << Log::endl;
state = State::ENET_ERROR;
return;
}
ENetAddress eNetAddr;
enet_address_set_host(&eNetAddr, addr.host.c_str());
eNetAddr.port = addr.port;
peer = enet_host_connect(host, &eNetAddr, NetHandler::PACKET_CHANNELS, 0);
if (peer == nullptr) {
std::cout << Log::err << "Failed to initialize ENet peer." << Log::endl;
state = State::ENET_ERROR;
return;
}
connectionTime = std::chrono::high_resolution_clock::now();
state = State::ATTEMPTING_CONNECT;
}
void ServerConnection::processConnecting() {
if (state == State::ATTEMPTING_CONNECT) {
ENetEvent event;
auto time = std::chrono::high_resolution_clock::now();
long elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(time - connectionTime).count();
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(event.peer->address.host)
<< ":" << event.peer->address.port << "." << Log::endl;
state = State::CONNECTED;
}
}
else {
enet_peer_reset(peer);
if (attempt < attempts) {
std::cout << Log::info << "Failed to connect to server, retrying." << Log::endl;
connectionTime = std::chrono::high_resolution_clock::now();
attempt ++;
}
else {
std::cout << Log::err << "Failed to connect to server." << Log::endl;
state = State::FAILED_CONNECT;
}
}
}
if (state == State::ATTEMPTING_CONNECT) {
ENetEvent event;
auto time = std::chrono::high_resolution_clock::now();
long elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(time - connectionTime).count();
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(event.peer->address.host)
<< ":" << event.peer->address.port << "." << Log::endl;
state = State::CONNECTED;
}
}
else {
enet_peer_reset(peer);
if (attempt < attempts) {
std::cout << Log::info << "Failed to connect to server, retrying." << Log::endl;
connectionTime = std::chrono::high_resolution_clock::now();
attempt++;
}
else {
std::cout << Log::err << "Failed to connect to server." << Log::endl;
state = State::FAILED_CONNECT;
}
}
}
}
ServerConnection::State ServerConnection::getConnectionStatus() {
return state;
return state;
}
void ServerConnection::disconnect() {
if (state == State::CONNECTED) {
std::cout << Log::info << "Disconnecting from server." << Log::endl;
enet_peer_disconnect(peer, 0);
enet_host_flush(host);
state = State::DISCONNECTED;
}
if (state == State::CONNECTED) {
std::cout << Log::info << "Disconnecting from server." << Log::endl;
enet_peer_disconnect(peer, 0);
enet_host_flush(host);
state = State::DISCONNECTED;
}
}
bool ServerConnection::pollEvents(ENetEvent *event) {
return enet_host_service(host, event, 0) > 0;
bool ServerConnection::pollEvents(ENetEvent* event) {
return enet_host_service(host, event, 0) > 0;
}
ENetPeer *ServerConnection::getPeer() {
return peer;
ENetPeer* ServerConnection::getPeer() {
return peer;
}
ServerConnection::~ServerConnection() {
disconnect();
delete host;
delete peer;
disconnect();
delete host;
delete peer;
}

View File

@ -10,38 +10,41 @@
class Address;
class ServerConnection {
public:
enum class State {
UNCONNECTED,
ATTEMPTING_CONNECT,
CONNECTED,
FAILED_CONNECT,
DISCONNECTED,
ENET_ERROR
};
ServerConnection() = default;
void attemptConnect(Address addr);
State getConnectionStatus();
void disconnect();
void processConnecting();
bool pollEvents(ENetEvent* event);
ENetPeer* getPeer();
~ServerConnection();
private:
unsigned long timeout = 1000;
unsigned int attempts = 10;
ENetHost* host = nullptr;
ENetPeer* peer = nullptr;
State state = State::UNCONNECTED;
unsigned int attempt = 0;
std::chrono::time_point<std::chrono::high_resolution_clock> connectionTime;
public:
enum class State {
UNCONNECTED,
ATTEMPTING_CONNECT,
CONNECTED,
FAILED_CONNECT,
DISCONNECTED,
ENET_ERROR
};
ServerConnection() = default;
void attemptConnect(Address addr);
State getConnectionStatus();
void disconnect();
void processConnecting();
bool pollEvents(ENetEvent* event);
ENetPeer* getPeer();
~ServerConnection();
private:
unsigned long timeout = 1000;
unsigned int attempts = 10;
ENetHost* host = nullptr;
ENetPeer* peer = nullptr;
State state = State::UNCONNECTED;
unsigned int attempt = 0;
std::chrono::time_point<std::chrono::high_resolution_clock> connectionTime;
};

View File

@ -9,65 +9,65 @@
#include "game/def/BlockDef.h"
#include "game/atlas/asset/AtlasRef.h"
ParticleEntity::ParticleEntity(SubgamePtr game, DimensionPtr dim, glm::vec3 pos, BlockDef &block) :
DrawableEntity(game, dim, std::make_shared<Model>()), Entity(game, dim) {
setPos(pos + glm::vec3(.5,.3,.5));
std::set<std::shared_ptr<AtlasRef>>& textureRefs = block.model.textureRefs;
auto it = textureRefs.cbegin();
advance(it, rand() % textureRefs.size());
auto uv = (*it)->uv;
auto spanX = uv.z - uv.x;
auto spanY = uv.w - uv.y;
float offX = spanX / 16 * (rand() % 12);
float offY = spanX / 16 * (rand() % 12);
uv -= glm::vec4(0, 0, spanX * 0.75, spanY * 0.75);
uv += glm::vec4(offX, offY, offX, offY);
std::vector<EntityVertex> vertices {
{{-0.05, -0.05, 0}, {uv.x, uv.w, 0, 1}, {1, 1, 1}, true, {0, 0, 1}, {}, {}},
{{-0.05, 0.05, 0}, {uv.x, uv.y, 0, 1}, {1, 1, 1}, true, {0, 0, 1}, {}, {}},
{{ 0.05, 0.05, 0}, {uv.z, uv.y, 0, 1}, {1, 1, 1}, true, {0, 0, 1}, {}, {}},
{{ 0.05, -0.05, 0}, {uv.z, uv.w, 0, 1}, {1, 1, 1}, true, {0, 0, 1}, {}, {}},
};
std::vector<unsigned int> indices {
0, 1, 2, 2, 3, 0,
0, 2, 1, 2, 0, 3,
};
auto dir = glm::radians(static_cast<float>(rand() % 360));
float xDir = sinf(dir);
float zDir = cosf(dir);
float horiScale = 0.5f + (rand() % 100 / 100.f);
velocity.y = 6.f;
velocity.x = xDir * 2.f * horiScale;
velocity.z = zDir * 2.f * horiScale;
setPos(getPos() + glm::vec3(xDir, 0, zDir) / 4.f);
std::unique_ptr<EntityMesh> mesh = std::make_unique<EntityMesh>();
mesh->create(vertices, indices);
this->model->fromMesh(std::move(mesh));
this->setScale(0.75f + (rand() % 10 / 20.f));
ParticleEntity::ParticleEntity(SubgamePtr game, DimensionPtr dim, glm::vec3 pos, BlockDef& block) :
DrawableEntity(game, dim, std::make_shared<Model>()), Entity(game, dim) {
setPos(pos + glm::vec3(.5, .3, .5));
std::set<std::shared_ptr<AtlasRef>>& textureRefs = block.model.textureRefs;
auto it = textureRefs.cbegin();
advance(it, rand() % textureRefs.size());
auto uv = (*it)->uv;
auto spanX = uv.z - uv.x;
auto spanY = uv.w - uv.y;
float offX = spanX / 16 * (rand() % 12);
float offY = spanX / 16 * (rand() % 12);
uv -= glm::vec4(0, 0, spanX * 0.75, spanY * 0.75);
uv += glm::vec4(offX, offY, offX, offY);
std::vector<EntityVertex> vertices{
{{ -0.05, -0.05, 0 }, { uv.x, uv.w, 0, 1 }, { 1, 1, 1 }, true, { 0, 0, 1 }, {}, {}},
{{ -0.05, 0.05, 0 }, { uv.x, uv.y, 0, 1 }, { 1, 1, 1 }, true, { 0, 0, 1 }, {}, {}},
{{ 0.05, 0.05, 0 }, { uv.z, uv.y, 0, 1 }, { 1, 1, 1 }, true, { 0, 0, 1 }, {}, {}},
{{ 0.05, -0.05, 0 }, { uv.z, uv.w, 0, 1 }, { 1, 1, 1 }, true, { 0, 0, 1 }, {}, {}},
};
std::vector<unsigned int> indices{
0, 1, 2, 2, 3, 0,
0, 2, 1, 2, 0, 3,
};
auto dir = glm::radians(static_cast<float>(rand() % 360));
float xDir = sinf(dir);
float zDir = cosf(dir);
float horiScale = 0.5f + (rand() % 100 / 100.f);
velocity.y = 6.f;
velocity.x = xDir * 2.f * horiScale;
velocity.z = zDir * 2.f * horiScale;
setPos(getPos() + glm::vec3(xDir, 0, zDir) / 4.f);
std::unique_ptr<EntityMesh> mesh = std::make_unique<EntityMesh>();
mesh->create(vertices, indices);
this->model->fromMesh(std::move(mesh));
this->setScale(0.75f + (rand() % 10 / 20.f));
}
void ParticleEntity::update(double delta, glm::vec3 player) {
time += delta;
setPos(getPos() + velocity * glm::vec3(static_cast<float>(delta)));
double angle = -glm::degrees(std::atan2(player.z - pos.z, player.x - pos.x)) + 90.f;
setRotateY(static_cast<float>(angle));
velocity.y -= 32.f * delta;
time += delta;
setPos(getPos() + velocity * glm::vec3(static_cast<float>(delta)));
double angle = -glm::degrees(std::atan2(player.z - pos.z, player.x - pos.x)) + 90.f;
setRotateY(static_cast<float>(angle));
velocity.y -= 32.f * delta;
}
void ParticleEntity::draw(Renderer &renderer) {
DrawableEntity::draw(renderer);
void ParticleEntity::draw(Renderer& renderer) {
DrawableEntity::draw(renderer);
}

View File

@ -9,14 +9,15 @@
class BlockDef;
class ParticleEntity : public DrawableEntity {
public:
ParticleEntity(SubgamePtr game, DimensionPtr dim, glm::vec3 pos, BlockDef& block);
void update(double delta, glm::vec3 player);
void draw(Renderer& renderer) override;
float time = 0;
private:
glm::vec3 velocity {};
public:
ParticleEntity(SubgamePtr game, DimensionPtr dim, glm::vec3 pos, BlockDef& block);
void update(double delta, glm::vec3 player);
void draw(Renderer& renderer) override;
float time = 0;
private:
glm::vec3 velocity{};
};

View File

@ -7,16 +7,17 @@
#include "world/dim/ent/DrawableEntity.h"
class PlayerEntity : public DrawableEntity {
public:
PlayerEntity(SubgamePtr game, DimensionPtr dim, glm::vec3 pos, unsigned int id, const std::shared_ptr<Model>& model) :
DrawableEntity(game, dim, model), Entity(game, dim), id(id) {
setPos(pos);
}
unsigned int getId() {
return id;
}
private:
unsigned int id;
public:
PlayerEntity(SubgamePtr game, DimensionPtr dim, glm::vec3 pos, unsigned int id, const std::shared_ptr<Model>& model)
:
DrawableEntity(game, dim, model), Entity(game, dim), id(id) {
setPos(pos);
}
unsigned int getId() {
return id;
}
private:
unsigned int id;
};

View File

@ -7,71 +7,83 @@
#include "world/dim/ent/DrawableEntity.h"
void WireframeEntity::updateMesh(const std::vector<SelectionBox>& boxes, float width) {
this->width = width;
buildMesh(boxes);
this->width = width;
buildMesh(boxes);
}
void WireframeEntity::buildMesh(const std::vector<SelectionBox>& boxes) {
indOffset = 0;
vertices.clear();
indices.clear();
for (auto& box : boxes) {
glm::vec3 a = box.a;
glm::vec3 b = box.b - box.a;
createBox(a, b, 0, 0, 0, 0, b.y, 0);
createBox(a, b, b.x, 0, 0, 0, b.y, 0);
createBox(a, b, b.x, 0, b.z, 0, b.y, 0);
createBox(a, b, 0, 0, b.z, 0, b.y, 0);
createBox(a, b, 0, 0, 0, b.x, 0, 0);
createBox(a, b, 0, b.y, 0, b.x, 0, 0);
createBox(a, b, 0, b.y, b.z, b.x, 0, 0);
createBox(a, b, 0, 0, b.z, b.x, 0, 0);
createBox(a, b, 0, 0, 0, 0, 0, b.z);
createBox(a, b, 0, b.y, 0, 0, 0, b.z);
createBox(a, b, b.x, b.y, 0, 0, 0, b.z);
createBox(a, b, b.x, 0, 0, 0, 0, b.z);
}
std::unique_ptr<EntityMesh> mesh = std::make_unique<EntityMesh>();
mesh->create(vertices, indices);
this->model->fromMesh(std::move(mesh));
indOffset = 0;
vertices.clear();
indices.clear();
for (auto& box : boxes) {
glm::vec3 a = box.a;
glm::vec3 b = box.b - box.a;
createBox(a, b, 0, 0, 0, 0, b.y, 0);
createBox(a, b, b.x, 0, 0, 0, b.y, 0);
createBox(a, b, b.x, 0, b.z, 0, b.y, 0);
createBox(a, b, 0, 0, b.z, 0, b.y, 0);
createBox(a, b, 0, 0, 0, b.x, 0, 0);
createBox(a, b, 0, b.y, 0, b.x, 0, 0);
createBox(a, b, 0, b.y, b.z, b.x, 0, 0);
createBox(a, b, 0, 0, b.z, b.x, 0, 0);
createBox(a, b, 0, 0, 0, 0, 0, b.z);
createBox(a, b, 0, b.y, 0, 0, 0, b.z);
createBox(a, b, b.x, b.y, 0, 0, 0, b.z);
createBox(a, b, b.x, 0, 0, 0, 0, b.z);
}
std::unique_ptr<EntityMesh> mesh = std::make_unique<EntityMesh>();
mesh->create(vertices, indices);
this->model->fromMesh(std::move(mesh));
}
void WireframeEntity::createBox(glm::vec3 a, glm::vec3 b, float x, float y, float z, float xSize, float ySize, float zSize) {
float hw = (width/2.0f);
float w = width;
glm::vec3 c = color;
std::vector<EntityVertex> myVerts {
/*0*/ {{x - hw + a.x, y - hw + a.y, z - hw + a.z }, {c.x, c.y, c.z, 1}, {1, 1, 1}, false, {0, 1, 0}, {}, {}},
/*1*/ {{x - hw + a.x + xSize + w, y - hw + a.y, z - hw + a.z }, {c.x, c.y, c.z, 1}, {1, 1, 1}, false, {0, 1, 0}, {}, {}},
/*2*/ {{x - hw + a.x + xSize + w, y - hw + a.y, z - hw + a.z + zSize + w}, {c.x, c.y, c.z, 1}, {1, 1, 1}, false, {0, 1, 0}, {}, {}},
/*3*/ {{x - hw + a.x, y - hw + a.y, z - hw + a.z + zSize + w}, {c.x, c.y, c.z, 1}, {1, 1, 1}, false, {0, 1, 0}, {}, {}},
/*4*/ {{x - hw + a.x, y - hw + a.y + ySize + w, z - hw + a.z }, {c.x, c.y, c.z, 1}, {1, 1, 1}, false, {0, 1, 0}, {}, {}},
/*5*/ {{x - hw + a.x + xSize + w, y - hw + a.y + ySize + w, z - hw + a.z }, {c.x, c.y, c.z, 1}, {1, 1, 1}, false, {0, 1, 0}, {}, {}},
/*6*/ {{x - hw + a.x + xSize + w, y - hw + a.y + ySize + w, z - hw + a.z + zSize + w}, {c.x, c.y, c.z, 1}, {1, 1, 1}, false, {0, 1, 0}, {}, {}},
/*7*/ {{x - hw + a.x, y - hw + a.y + ySize + w, z - hw + a.z + zSize + w}, {c.x, c.y, c.z, 1}, {1, 1, 1}, false, {0, 1, 0}, {}, {}},
};
std::vector<unsigned int> myInds {
0, 1, 2, 2, 3, 0,
4, 7, 6, 6, 5, 4,
0, 4, 5, 5, 1, 0,
3, 2, 6, 6, 7, 3,
0, 3, 7, 7, 4, 0,
1, 5, 6, 6, 2, 1,
};
vertices.insert(vertices.end(), myVerts.begin(), myVerts.end());
for (auto i : myInds) indices.push_back(i + indOffset);
indOffset += 8;
void
WireframeEntity::createBox(glm::vec3 a, glm::vec3 b, float x, float y, float z, float xSize, float ySize, float zSize) {
float hw = (width / 2.0f);
float w = width;
glm::vec3 c = color;
std::vector<EntityVertex> myVerts{
/*0*/
{{ x - hw + a.x, y - hw + a.y, z - hw + a.z }, { c.x, c.y, c.z, 1 }, { 1, 1, 1 }, false, { 0, 1, 0 }, {}, {}},
/*1*/{{ x - hw + a.x + xSize + w, y - hw + a.y, z - hw + a.z }, { c.x, c.y, c.z, 1 }, { 1, 1, 1 }, false,
{ 0, 1, 0 }, {}, {}},
/*2*/
{{ x - hw + a.x + xSize + w, y - hw + a.y, z - hw + a.z + zSize + w }, { c.x, c.y, c.z, 1 }, { 1, 1, 1 }, false,
{ 0, 1, 0 }, {}, {}},
/*3*/{{ x - hw + a.x, y - hw + a.y, z - hw + a.z + zSize + w }, { c.x, c.y, c.z, 1 }, { 1, 1, 1 }, false,
{ 0, 1, 0 }, {}, {}},
/*4*/{{ x - hw + a.x, y - hw + a.y + ySize + w, z - hw + a.z }, { c.x, c.y, c.z, 1 }, { 1, 1, 1 }, false,
{ 0, 1, 0 }, {}, {}},
/*5*/
{{ x - hw + a.x + xSize + w, y - hw + a.y + ySize + w, z - hw + a.z }, { c.x, c.y, c.z, 1 }, { 1, 1, 1 }, false,
{ 0, 1, 0 }, {}, {}},
/*6*/{{ x - hw + a.x + xSize + w, y - hw + a.y + ySize + w, z - hw + a.z + zSize + w }, { c.x, c.y, c.z, 1 },
{ 1, 1, 1 }, false, { 0, 1, 0 }, {}, {}},
/*7*/
{{ x - hw + a.x, y - hw + a.y + ySize + w, z - hw + a.z + zSize + w }, { c.x, c.y, c.z, 1 }, { 1, 1, 1 }, false,
{ 0, 1, 0 }, {}, {}},
};
std::vector<unsigned int> myInds{
0, 1, 2, 2, 3, 0,
4, 7, 6, 6, 5, 4,
0, 4, 5, 5, 1, 0,
3, 2, 6, 6, 7, 3,
0, 3, 7, 7, 4, 0,
1, 5, 6, 6, 2, 1,
};
vertices.insert(vertices.end(), myVerts.begin(), myVerts.end());
for (auto i : myInds) indices.push_back(i + indOffset);
indOffset += 8;
}

View File

@ -10,21 +10,23 @@
#include "client/graph/mesh/EntityVertex.h"
class WireframeEntity : public DrawableEntity {
public:
WireframeEntity(SubgamePtr game, DimensionPtr dim, glm::vec3 color) :
DrawableEntity(game, dim, std::make_shared<Model>()), Entity(game, dim),
color(color) {};
void updateMesh(const std::vector<SelectionBox>& boxes, float width);
private:
std::vector<EntityVertex> vertices {};
std::vector<unsigned int> indices {};
void buildMesh(const std::vector<SelectionBox>& boxes);
void createBox(glm::vec3 a, glm::vec3 b, float x, float y, float z, float xSize, float ySize, float zSize);
glm::vec3 color {};
float width = 0.5;
int indOffset = 0;
public:
WireframeEntity(SubgamePtr game, DimensionPtr dim, glm::vec3 color) :
DrawableEntity(game, dim, std::make_shared<Model>()), Entity(game, dim),
color(color) {};
void updateMesh(const std::vector<SelectionBox>& boxes, float width);
private:
std::vector<EntityVertex> vertices{};
std::vector<unsigned int> indices{};
void buildMesh(const std::vector<SelectionBox>& boxes);
void createBox(glm::vec3 a, glm::vec3 b, float x, float y, float z, float xSize, float ySize, float zSize);
glm::vec3 color{};
float width = 0.5;
int indOffset = 0;
};

View File

@ -9,91 +9,91 @@
Camera::Camera() = default;
void Camera::create(float buffWidth, float buffHeight, glm::vec3 up) {
this->bufferDimensions = glm::vec2(buffWidth, buffHeight);
this->position = glm::vec3(0, 0, 0);
this->worldUp = up;
this->yaw = 0;
this->pitch = 0;
this->front = glm::vec3(0.0f, 0.0f, -1.0f);
createMatrices();
this->bufferDimensions = glm::vec2(buffWidth, buffHeight);
this->position = glm::vec3(0, 0, 0);
this->worldUp = up;
this->yaw = 0;
this->pitch = 0;
this->front = glm::vec3(0.0f, 0.0f, -1.0f);
createMatrices();
}
void Camera::createMatrices() {
ratio = bufferDimensions.x / bufferDimensions.y;
projectionMatrix = glm::perspective(glm::radians(fov), ratio, nearClip, farClip);
frustum.setCamInternals(glm::radians(fov) / 1.2f, ratio, nearClip, farClip);
orthographicMatrix = glm::ortho(0.0f, bufferDimensions.x, bufferDimensions.y, 0.0f, -1000.0f, 1000.0f);
ratio = bufferDimensions.x / bufferDimensions.y;
projectionMatrix = glm::perspective(glm::radians(fov), ratio, nearClip, farClip);
frustum.setCamInternals(glm::radians(fov) / 1.2f, ratio, nearClip, farClip);
orthographicMatrix = glm::ortho(0.0f, bufferDimensions.x, bufferDimensions.y, 0.0f, -1000.0f, 1000.0f);
}
void Camera::changeWindowDimensions(glm::vec2 size) {
this->bufferDimensions = size;
createMatrices();
this->bufferDimensions = size;
createMatrices();
}
glm::mat4 Camera::getProjectionMatrix() {
return projectionMatrix;
return projectionMatrix;
}
glm::mat4 Camera::getOrthographicMatrix() {
return orthographicMatrix;
return orthographicMatrix;
}
glm::mat4 Camera::getViewMatrix() {
update();
return glm::lookAt(position, position + front, up);
update();
return glm::lookAt(position, position + front, up);
}
void Camera::setPos(glm::vec3 pos) {
position = pos;
position = pos;
}
glm::vec3 Camera::getPos() {
return position;
return position;
}
void Camera::setYaw(double yaw) {
this->yaw = yaw;
this->yaw = yaw;
}
void Camera::setPitch(double pitch) {
this->pitch = pitch;
this->pitch = pitch;
}
void Camera::update() {
front.x = (float)(cos(glm::radians(yaw)) * cos(glm::radians(pitch)));
front.y = (float)(sin(glm::radians(pitch)));
front.z = (float)(sin(glm::radians(yaw)) * cos(glm::radians(pitch)));
front = glm::normalize(front);
right = glm::normalize(glm::cross(front, worldUp));
up = glm::normalize(glm::cross(right, front));
frustum.update(position, front, up, right);
front.x = (float) (cos(glm::radians(yaw)) * cos(glm::radians(pitch)));
front.y = (float) (sin(glm::radians(pitch)));
front.z = (float) (sin(glm::radians(yaw)) * cos(glm::radians(pitch)));
front = glm::normalize(front);
right = glm::normalize(glm::cross(front, worldUp));
up = glm::normalize(glm::cross(right, front));
frustum.update(position, front, up, right);
}
glm::vec3 Camera::getFront() {
return front;
return front;
}
glm::vec3 Camera::getRight() {
return right;
return right;
}
glm::vec2 Camera::getBufferDimensions() {
return bufferDimensions;
return bufferDimensions;
}
bool Camera::inFrustum(glm::vec3 &p) {
return frustum.pointInFrustum(p) == Frustum::INSIDE;
bool Camera::inFrustum(glm::vec3& p) {
return frustum.pointInFrustum(p) == Frustum::INSIDE;
}
int Camera::inFrustum(FrustumAABB &b) {
return frustum.boxInFrustum(b);
int Camera::inFrustum(FrustumAABB& b) {
return frustum.boxInFrustum(b);
}
Camera::~Camera() = default;

View File

@ -11,61 +11,69 @@
#include "util/frustum/Frustum.h"
class Camera {
public:
Camera();
void create(float buffWidth, float buffHeight, glm::vec3 up);
void changeWindowDimensions(glm::vec2 size);
glm::vec3 getPos();
void setPos(glm::vec3 pos);
void setYaw(double yaw);
void setPitch(double pitch);
glm::mat4 getProjectionMatrix();
glm::mat4 getOrthographicMatrix();
glm::mat4 getViewMatrix();
glm::vec3 getFront();
glm::vec3 getRight();
glm::vec2 getBufferDimensions();
bool inFrustum(glm::vec3 &p);
int inFrustum(FrustumAABB &b);
~Camera();
private:
//Window Size
glm::vec2 bufferDimensions;
//Matrices
glm::mat4 projectionMatrix;
glm::mat4 orthographicMatrix;
//Perspective Matrix Properties
float fov = 80.0f;
float ratio;
float nearClip = 0.1f;
float farClip = 1000.0f;
//View Frustum
Frustum frustum;
//Movement translation variables
glm::vec3 front;
glm::vec3 up;
glm::vec3 right;
glm::vec3 worldUp;
//Angle and Position
glm::vec3 position;
double yaw;
double pitch;
void createMatrices();
void update();
public:
Camera();
void create(float buffWidth, float buffHeight, glm::vec3 up);
void changeWindowDimensions(glm::vec2 size);
glm::vec3 getPos();
void setPos(glm::vec3 pos);
void setYaw(double yaw);
void setPitch(double pitch);
glm::mat4 getProjectionMatrix();
glm::mat4 getOrthographicMatrix();
glm::mat4 getViewMatrix();
glm::vec3 getFront();
glm::vec3 getRight();
glm::vec2 getBufferDimensions();
bool inFrustum(glm::vec3& p);
int inFrustum(FrustumAABB& b);
~Camera();
private:
//Window Size
glm::vec2 bufferDimensions;
//Matrices
glm::mat4 projectionMatrix;
glm::mat4 orthographicMatrix;
//Perspective Matrix Properties
float fov = 80.0f;
float ratio;
float nearClip = 0.1f;
float farClip = 1000.0f;
//View Frustum
Frustum frustum;
//Movement translation variables
glm::vec3 front;
glm::vec3 up;
glm::vec3 right;
glm::vec3 worldUp;
//Angle and Position
glm::vec3 position;
double yaw;
double pitch;
void createMatrices();
void update();
};

View File

@ -7,15 +7,18 @@
class Renderer;
class Drawable {
public:
virtual void update(double delta) {};
virtual void draw(Renderer& renderer) {};
virtual bool isVisible() { return visible; }
virtual void setVisible(bool visible) { this->visible = visible; }
virtual ~Drawable() = default;
protected:
bool visible = true;
public:
virtual void update(double delta) {};
virtual void draw(Renderer& renderer) {};
virtual bool isVisible() { return visible; }
virtual void setVisible(bool visible) { this->visible = visible; }
virtual ~Drawable() = default;
protected:
bool visible = true;
};

View File

@ -4,37 +4,37 @@
#include "DrawableGroup.h"
void DrawableGroup::draw(Renderer &renderer) {
for (auto drawable : children) {
drawable->draw(renderer);
}
void DrawableGroup::draw(Renderer& renderer) {
for (auto drawable : children) {
drawable->draw(renderer);
}
}
void DrawableGroup::addDrawable(Drawable *drawable) {
children.push_back(drawable);
void DrawableGroup::addDrawable(Drawable* drawable) {
children.push_back(drawable);
}
void DrawableGroup::removeDrawable(Drawable *drawable) {
for (auto it = children.begin(); it < children.end(); ++it) {
if (*it == drawable) {
children.erase(it);
delete *it;
return;
}
}
void DrawableGroup::removeDrawable(Drawable* drawable) {
for (auto it = children.begin(); it < children.end(); ++it) {
if (*it == drawable) {
children.erase(it);
delete *it;
return;
}
}
}
void DrawableGroup::clearDrawables() {
for (auto drawable : children) {
delete drawable;
}
children.clear();
for (auto drawable : children) {
delete drawable;
}
children.clear();
}
DrawableGroup::~DrawableGroup() {
clearDrawables();
clearDrawables();
}
std::vector<Drawable *> &DrawableGroup::getChildren() {
return children;
std::vector<Drawable*>& DrawableGroup::getChildren() {
return children;
}

View File

@ -9,17 +9,20 @@
#include "Drawable.h"
class DrawableGroup : public Drawable {
public:
void draw(Renderer& renderer) override;
void addDrawable(Drawable* drawable);
void removeDrawable(Drawable* drawable);
void clearDrawables();
std::vector<Drawable*>& getChildren();
~DrawableGroup() override;
protected:
std::vector<Drawable*> children {};
public:
void draw(Renderer& renderer) override;
void addDrawable(Drawable* drawable);
void removeDrawable(Drawable* drawable);
void clearDrawables();
std::vector<Drawable*>& getChildren();
~DrawableGroup() override;
protected:
std::vector<Drawable*> children{};
};

View File

@ -10,62 +10,62 @@
#include "game/atlas/TextureAtlas.h"
Font::Font(TextureAtlas& atlas, std::shared_ptr<AtlasRef> tex) :
fontTex(std::move(tex)),
atlasSize(atlas.pixelSize) {
getCharWidths(atlas);
fontTex(std::move(tex)),
atlasSize(atlas.pixelSize) {
getCharWidths(atlas);
}
unsigned int Font::getCharWidth(char c) {
unsigned int index = static_cast<unsigned int>(c) - 32;
if (index >= amountOfChars) throw std::runtime_error("Invalid char index.");
return charWidths[index];
unsigned int index = static_cast<unsigned int>(c) - 32;
if (index >= amountOfChars) throw std::runtime_error("Invalid char index.");
return charWidths[index];
}
void Font::getCharWidths(TextureAtlas &atlas) {
auto& data = atlas.atlasData;
charWidths[0] = 2;
for (unsigned int i = 1; i < amountOfChars; i++) {
glm::vec2 charPos = {i % 18 * charWidth, std::floor(i / 18) * charHeight};
unsigned int xBase = static_cast<unsigned int>(fontTex->pos.x) + static_cast<unsigned int>(charPos.x);
unsigned int yBase = static_cast<unsigned int>(fontTex->pos.y) + static_cast<unsigned int>(charPos.y);
unsigned short width = 0;
for (unsigned int j = 0; j < charWidth; j++) {
bool empty = true;
for (unsigned int k = 0; k < charHeight; k++) {
unsigned int xx = xBase + j;
unsigned int yy = yBase + k;
unsigned int offset = yy * static_cast<unsigned int>(atlasSize.x) * 4 + xx * 4 + 3;
if (data[offset] != 0) {
empty = false;
break;
}
}
if (!empty) width = static_cast<unsigned short>(j);
}
charWidths[i] = width;
}
void Font::getCharWidths(TextureAtlas& atlas) {
auto& data = atlas.atlasData;
charWidths[0] = 2;
for (unsigned int i = 1; i < amountOfChars; i++) {
glm::vec2 charPos = { i % 18 * charWidth, std::floor(i / 18) * charHeight };
unsigned int xBase = static_cast<unsigned int>(fontTex->pos.x) + static_cast<unsigned int>(charPos.x);
unsigned int yBase = static_cast<unsigned int>(fontTex->pos.y) + static_cast<unsigned int>(charPos.y);
unsigned short width = 0;
for (unsigned int j = 0; j < charWidth; j++) {
bool empty = true;
for (unsigned int k = 0; k < charHeight; k++) {
unsigned int xx = xBase + j;
unsigned int yy = yBase + k;
unsigned int offset = yy * static_cast<unsigned int>(atlasSize.x) * 4 + xx * 4 + 3;
if (data[offset] != 0) {
empty = false;
break;
}
}
if (!empty) width = static_cast<unsigned short>(j);
}
charWidths[i] = width;
}
}
glm::vec4 Font::getCharUVs(char c) {
unsigned int index = static_cast<unsigned int>(c) - 32;
if (index >= amountOfChars) throw std::runtime_error("Invalid char index.");
glm::vec2 charPos = {(index % 18) * charWidth, std::floor(index / 18) * charHeight};
glm::vec4 uv = {
fontTex->uv.x + (charPos.x) / atlasSize.x,
fontTex->uv.y + (charPos.y) / atlasSize.y,
fontTex->uv.x + (charPos.x + getCharWidth(c) + 1) / atlasSize.x,
fontTex->uv.y + (charPos.y + charHeight) / atlasSize.y
};
return uv;
unsigned int index = static_cast<unsigned int>(c) - 32;
if (index >= amountOfChars) throw std::runtime_error("Invalid char index.");
glm::vec2 charPos = { (index % 18) * charWidth, std::floor(index / 18) * charHeight };
glm::vec4 uv = {
fontTex->uv.x + (charPos.x) / atlasSize.x,
fontTex->uv.y + (charPos.y) / atlasSize.y,
fontTex->uv.x + (charPos.x + getCharWidth(c) + 1) / atlasSize.x,
fontTex->uv.y + (charPos.y + charHeight) / atlasSize.y
};
return uv;
}

View File

@ -9,23 +9,27 @@
#include <glm/vec4.hpp>
class AtlasRef;
class TextureAtlas;
class Font {
public:
Font() = default;
Font(TextureAtlas& atlas, std::shared_ptr<AtlasRef> tex);
unsigned int getCharWidth(char c);
glm::vec4 getCharUVs(char c);
const static unsigned int amountOfChars = 95;
const static unsigned int charWidth = 7;
const static unsigned int charHeight = 9;
private:
void getCharWidths(TextureAtlas& atlas);
glm::vec2 atlasSize {};
std::shared_ptr<AtlasRef> fontTex = nullptr;
std::array<unsigned short, 95> charWidths {};
public:
Font() = default;
Font(TextureAtlas& atlas, std::shared_ptr<AtlasRef> tex);
unsigned int getCharWidth(char c);
glm::vec4 getCharUVs(char c);
const static unsigned int amountOfChars = 95;
const static unsigned int charWidth = 7;
const static unsigned int charHeight = 9;
private:
void getCharWidths(TextureAtlas& atlas);
glm::vec2 atlasSize{};
std::shared_ptr<AtlasRef> fontTex = nullptr;
std::array<unsigned short, 95> charWidths{};
};

View File

@ -17,56 +17,57 @@
#include "game/atlas/asset/SerializedModel.h"
void Model::fromMesh(std::unique_ptr<EntityMesh> mesh) {
meshes.clear();
meshes.push_back(std::move(mesh));
meshes.clear();
meshes.push_back(std::move(mesh));
}
int Model::fromFile(const std::string &path, const std::vector<std::shared_ptr<AtlasRef>> &textures) {
this->textures = textures;
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenNormals);
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
std::cout << Log::err << "ERROR::ASSIMP::" << importer.GetErrorString() << Log::endl;
return 1;
}
loadModelMeshes(scene->mRootNode, scene);
loadAnimations(scene);
calcBoneHeirarchy(scene->mRootNode, scene, -1);
globalInverseTransform = glm::inverse(MatConv::AiToGLMMat4(scene->mRootNode->mTransformation));
return 0;
int Model::fromFile(const std::string& path, const std::vector<std::shared_ptr<AtlasRef>>& textures) {
this->textures = textures;
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenNormals);
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
std::cout << Log::err << "ERROR::ASSIMP::" << importer.GetErrorString() << Log::endl;
return 1;
}
loadModelMeshes(scene->mRootNode, scene);
loadAnimations(scene);
calcBoneHeirarchy(scene->mRootNode, scene, -1);
globalInverseTransform = glm::inverse(MatConv::AiToGLMMat4(scene->mRootNode->mTransformation));
return 0;
}
int Model::fromSerialized(const SerializedModel& model, const std::vector<std::shared_ptr<AtlasRef>>& textures) {
this->textures = textures;
Assimp::Importer importer;
const aiScene* scene = importer.ReadFileFromMemory(model.data.data(), model.data.length(), aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenNormals, "B3D");
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
std::cout << Log::err << "ERROR::ASSIMP::" << importer.GetErrorString() << Log::endl;
return 1;
}
loadModelMeshes(scene->mRootNode, scene);
loadAnimations(scene);
calcBoneHeirarchy(scene->mRootNode, scene, -1);
globalInverseTransform = glm::inverse(MatConv::AiToGLMMat4(scene->mRootNode->mTransformation));
return 0;
this->textures = textures;
Assimp::Importer importer;
const aiScene* scene = importer.ReadFileFromMemory(model.data.data(), model.data.length(),
aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenNormals, "B3D");
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
std::cout << Log::err << "ERROR::ASSIMP::" << importer.GetErrorString() << Log::endl;
return 1;
}
loadModelMeshes(scene->mRootNode, scene);
loadAnimations(scene);
calcBoneHeirarchy(scene->mRootNode, scene, -1);
globalInverseTransform = glm::inverse(MatConv::AiToGLMMat4(scene->mRootNode->mTransformation));
return 0;
}
void Model::getTransformsByFrame(double frame, glm::ivec2 bounds, std::vector<glm::mat4>& transforms) {
transforms.resize(bones.size());
if (!rootBones.empty())
for (auto bone : rootBones)
calcBoneTransformation(frame, *bone, glm::mat4(1.0f), bounds, transforms);
transforms.resize(bones.size());
if (!rootBones.empty())
for (auto bone : rootBones)
calcBoneTransformation(frame, *bone, glm::mat4(1.0f), bounds, transforms);
}
//void Model::getTransformsByTime(double time, std::vector<glm::mat4>& transforms) {
@ -76,187 +77,191 @@ void Model::getTransformsByFrame(double frame, glm::ivec2 bounds, std::vector<gl
// getTransformsByFrame(frameTime, transforms);
//}
const ModelAnimation &Model::getAnimation() {
return animation;
const ModelAnimation& Model::getAnimation() {
return animation;
}
void Model::loadModelMeshes(aiNode *node, const aiScene *scene) {
for (unsigned int i = 0; i < node->mNumMeshes; i++) {
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
meshes.emplace_back(std::make_unique<EntityMesh>());
loadMeshAndBone(mesh, meshes[i]);
}
for (unsigned int i = 0; i < node->mNumChildren; i++) {
loadModelMeshes(node->mChildren[i], scene); //Recurse down
}
void Model::loadModelMeshes(aiNode* node, const aiScene* scene) {
for (unsigned int i = 0; i < node->mNumMeshes; i++) {
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
meshes.emplace_back(std::make_unique<EntityMesh>());
loadMeshAndBone(mesh, meshes[i]);
}
for (unsigned int i = 0; i < node->mNumChildren; i++) {
loadModelMeshes(node->mChildren[i], scene); //Recurse down
}
}
void Model::loadMeshAndBone(aiMesh *mesh, std::unique_ptr<EntityMesh>& target) {
std::vector<EntityVertex> vertices;
std::vector<unsigned int> indices;
//Process Vertices
for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
EntityVertex vertex {};
vertex.position = {mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z};
vertex.normal = {mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z};
vertex.colorBlend = {1, 1, 1};
assert(mesh->mMaterialIndex >= 0 && mesh->mMaterialIndex < textures.size());
if (mesh->mTextureCoords[0]) {
auto& texture = textures[mesh->mMaterialIndex];
//Set texture coordinates
vertex.useTex = true;
vertex.colorData = {
texture->uv.x + mesh->mTextureCoords[0][i].x * (texture->uv.z - texture->uv.x),
texture->uv.y + mesh->mTextureCoords[0][i].y * (texture->uv.w - texture->uv.y), 0, 1 //Alpha
};
}
else vertex.colorData = {1, 1, 1, 1};
vertices.push_back(vertex);
}
//Process Indices
for (unsigned int i = 0; i < mesh->mNumFaces; i++) {
aiFace face = mesh->mFaces[i];
for (unsigned int j = 0; j < face.mNumIndices; j++) {
indices.push_back(face.mIndices[j]);
}
}
//Process Mesh Bones and add to bone list
bones.resize(mesh->mNumBones);
for (unsigned int i = 0; i < mesh->mNumBones; i++) {
aiBone* bone = mesh->mBones[i];
bones[i] = ModelBone(static_cast<unsigned int>(i), -1, {bone->mName.data});
bones[i].offsetMatrix = glm::transpose(MatConv::AiToGLMMat4(bone->mOffsetMatrix));
for (unsigned int j = 0; j < bone->mNumWeights; j++) {
aiVertexWeight* weight = &bone->mWeights[j];
if (weight->mVertexId >= vertices.size()) assert(0);
unsigned int bid = 0;
while (vertices[weight->mVertexId].boneWeights[bid] != 0) {
bid++;
assert(bid < 4);
}
vertices[weight->mVertexId].boneIDs[bid] = i;
vertices[weight->mVertexId].boneWeights[bid] = weight->mWeight;
}
}
//Create mesh
target->create(vertices, indices);
void Model::loadMeshAndBone(aiMesh* mesh, std::unique_ptr<EntityMesh>& target) {
std::vector<EntityVertex> vertices;
std::vector<unsigned int> indices;
//Process Vertices
for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
EntityVertex vertex{};
vertex.position = { mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z };
vertex.normal = { mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z };
vertex.colorBlend = { 1, 1, 1 };
assert(mesh->mMaterialIndex >= 0 && mesh->mMaterialIndex < textures.size());
if (mesh->mTextureCoords[0]) {
auto& texture = textures[mesh->mMaterialIndex];
//Set texture coordinates
vertex.useTex = true;
vertex.colorData = {
texture->uv.x + mesh->mTextureCoords[0][i].x * (texture->uv.z - texture->uv.x),
texture->uv.y + mesh->mTextureCoords[0][i].y * (texture->uv.w - texture->uv.y), 0, 1 //Alpha
};
}
else vertex.colorData = { 1, 1, 1, 1 };
vertices.push_back(vertex);
}
//Process Indices
for (unsigned int i = 0; i < mesh->mNumFaces; i++) {
aiFace face = mesh->mFaces[i];
for (unsigned int j = 0; j < face.mNumIndices; j++) {
indices.push_back(face.mIndices[j]);
}
}
//Process Mesh Bones and add to bone list
bones.resize(mesh->mNumBones);
for (unsigned int i = 0; i < mesh->mNumBones; i++) {
aiBone* bone = mesh->mBones[i];
bones[i] = ModelBone(static_cast<unsigned int>(i), -1, { bone->mName.data });
bones[i].offsetMatrix = glm::transpose(MatConv::AiToGLMMat4(bone->mOffsetMatrix));
for (unsigned int j = 0; j < bone->mNumWeights; j++) {
aiVertexWeight* weight = &bone->mWeights[j];
if (weight->mVertexId >= vertices.size()) assert(0);
unsigned int bid = 0;
while (vertices[weight->mVertexId].boneWeights[bid] != 0) {
bid++;
assert(bid < 4);
}
vertices[weight->mVertexId].boneIDs[bid] = i;
vertices[weight->mVertexId].boneWeights[bid] = weight->mWeight;
}
}
//Create mesh
target->create(vertices, indices);
}
void Model::loadAnimations(const aiScene *scene) {
assert(scene->mNumAnimations <= 1);
if (scene->mNumAnimations == 1) {
const aiAnimation* aiAnim = scene->mAnimations[0];
animation = ModelAnimation(aiAnim->mName.data);
animation.duration = static_cast<unsigned int>(aiAnim->mDuration);
animation.ticksPerSecond = aiAnim->mTicksPerSecond;
animation.channels.resize(bones.size());
for (unsigned int j = 0; j < aiAnim->mNumChannels; j++) {
const aiNodeAnim* aiChannel = aiAnim->mChannels[j];
int index = -1;
for (unsigned int k = 0; k < bones.size(); k++) {
if (std::string {aiChannel->mNodeName.data} == bones[k].name) {
index = k;
continue;
}
}
if (index == -1) {
void Model::loadAnimations(const aiScene* scene) {
assert(scene->mNumAnimations <= 1);
if (scene->mNumAnimations == 1) {
const aiAnimation* aiAnim = scene->mAnimations[0];
animation = ModelAnimation(aiAnim->mName.data);
animation.duration = static_cast<unsigned int>(aiAnim->mDuration);
animation.ticksPerSecond = aiAnim->mTicksPerSecond;
animation.channels.resize(bones.size());
for (unsigned int j = 0; j < aiAnim->mNumChannels; j++) {
const aiNodeAnim* aiChannel = aiAnim->mChannels[j];
int index = -1;
for (unsigned int k = 0; k < bones.size(); k++) {
if (std::string{ aiChannel->mNodeName.data } == bones[k].name) {
index = k;
continue;
}
}
if (index == -1) {
// std::cout << aiChannel->mNodeName.data << std::endl;
}
else {
animation.channels[index] = AnimChannel(static_cast<unsigned int>(index), aiChannel->mNodeName.data);
AnimChannel &channel = animation.channels[index];
//Copy Rotation Keys
channel.rotationKeys.reserve(aiChannel->mNumRotationKeys);
for (unsigned int k = 0; k < aiChannel->mNumRotationKeys; k++) {
aiQuatKey *key = &aiChannel->mRotationKeys[k];
channel.rotationKeys.emplace_back(key->mTime, key->mValue);
}
//Copy Position Keys
channel.positionKeys.reserve(aiChannel->mNumPositionKeys);
for (unsigned int k = 0; k < aiChannel->mNumPositionKeys; k++) {
aiVectorKey *key = &aiChannel->mPositionKeys[k];
channel.positionKeys.emplace_back(key->mTime,
glm::vec3{key->mValue.x, key->mValue.y, key->mValue.z});
}
//Copy Scale Keys
channel.scaleKeys.reserve(aiChannel->mNumScalingKeys);
for (unsigned int k = 0; k < aiChannel->mNumScalingKeys; k++) {
aiVectorKey *key = &aiChannel->mScalingKeys[k];
channel.scaleKeys.emplace_back(key->mTime, glm::vec3{key->mValue.x, key->mValue.y, key->mValue.z});
}
}
}
}
}
else {
animation.channels[index] = AnimChannel(static_cast<unsigned int>(index), aiChannel->mNodeName.data);
AnimChannel& channel = animation.channels[index];
//Copy Rotation Keys
channel.rotationKeys.reserve(aiChannel->mNumRotationKeys);
for (unsigned int k = 0; k < aiChannel->mNumRotationKeys; k++) {
aiQuatKey* key = &aiChannel->mRotationKeys[k];
channel.rotationKeys.emplace_back(key->mTime, key->mValue);
}
//Copy Position Keys
channel.positionKeys.reserve(aiChannel->mNumPositionKeys);
for (unsigned int k = 0; k < aiChannel->mNumPositionKeys; k++) {
aiVectorKey* key = &aiChannel->mPositionKeys[k];
channel.positionKeys.emplace_back(key->mTime,
glm::vec3{ key->mValue.x, key->mValue.y, key->mValue.z });
}
//Copy Scale Keys
channel.scaleKeys.reserve(aiChannel->mNumScalingKeys);
for (unsigned int k = 0; k < aiChannel->mNumScalingKeys; k++) {
aiVectorKey* key = &aiChannel->mScalingKeys[k];
channel.scaleKeys.emplace_back(key->mTime,
glm::vec3{ key->mValue.x, key->mValue.y, key->mValue.z });
}
}
}
}
}
void Model::calcBoneHeirarchy(aiNode *node, const aiScene *scene, int parentBoneIndex) {
int index = -1;
for (auto &bone : bones) {
if (bone.name == std::string(node->mName.data)) {
bone.parent = parentBoneIndex;
index = bone.index;
if (parentBoneIndex == -1) rootBones.push_back(&bone);
else bones[bone.parent].children.push_back(&bone);
break;
}
}
for (unsigned int i = 0; i < node->mNumChildren; i++) calcBoneHeirarchy(node->mChildren[i], scene, index);
void Model::calcBoneHeirarchy(aiNode* node, const aiScene* scene, int parentBoneIndex) {
int index = -1;
for (auto& bone : bones) {
if (bone.name == std::string(node->mName.data)) {
bone.parent = parentBoneIndex;
index = bone.index;
if (parentBoneIndex == -1) rootBones.push_back(&bone);
else bones[bone.parent].children.push_back(&bone);
break;
}
}
for (unsigned int i = 0; i < node->mNumChildren; i++) calcBoneHeirarchy(node->mChildren[i], scene, index);
}
void Model::calcBoneTransformation(double animTime, ModelBone& bone, glm::mat4 parentTransform, glm::ivec2 bounds, std::vector<glm::mat4>& transforms) {
AnimChannel* channel = nullptr;
for (auto &i : animation.channels) {
if (i.index == bone.index) {
channel = &i;
break;
}
}
glm::mat4 boneTransformation(1.0f);
if (channel) {
glm::mat4 position = glm::translate(glm::mat4(1.0), calcBoneVal<glm::vec3>(animTime, bounds, channel->positionKeys, {},
[](const glm::vec3 &a, const glm::vec3 &b, float factor) { return glm::mix(a, b, factor); }));
glm::mat4 scale = glm::scale(glm::mat4(1.0), calcBoneVal<glm::vec3>(animTime, bounds, channel->scaleKeys, {},
[](const glm::vec3 &a, const glm::vec3 &b, float factor) { return glm::mix(a, b, factor); }));
glm::mat4 rotation = glm::transpose(glm::mat4(MatConv::AiToGLMMat3(
calcBoneVal<aiQuaternion>(animTime, bounds, channel->rotationKeys, {},
[](const aiQuaternion& a, const aiQuaternion& b, float factor) {
aiQuaternion result;
aiQuaternion::Interpolate(result, a, b, factor);
return result.Normalize();
}).GetMatrix())));
boneTransformation = position * rotation * scale;
}
glm::mat4 globalTransformation = parentTransform * boneTransformation;
transforms[bone.index] = globalInverseTransform * globalTransformation * bone.offsetMatrix;
for (auto& child : bone.children) calcBoneTransformation(animTime, *child, globalTransformation, bounds, transforms);
void Model::calcBoneTransformation(double animTime, ModelBone& bone, glm::mat4 parentTransform, glm::ivec2 bounds,
std::vector<glm::mat4>& transforms) {
AnimChannel* channel = nullptr;
for (auto& i : animation.channels) {
if (i.index == bone.index) {
channel = &i;
break;
}
}
glm::mat4 boneTransformation(1.0f);
if (channel) {
glm::mat4 position = glm::translate(glm::mat4(1.0),
calcBoneVal<glm::vec3>(animTime, bounds, channel->positionKeys, {},
[](const glm::vec3& a, const glm::vec3& b, float factor) { return glm::mix(a, b, factor); }));
glm::mat4 scale = glm::scale(glm::mat4(1.0), calcBoneVal<glm::vec3>(animTime, bounds, channel->scaleKeys, {},
[](const glm::vec3& a, const glm::vec3& b, float factor) { return glm::mix(a, b, factor); }));
glm::mat4 rotation = glm::transpose(glm::mat4(MatConv::AiToGLMMat3(
calcBoneVal<aiQuaternion>(animTime, bounds, channel->rotationKeys, {},
[](const aiQuaternion& a, const aiQuaternion& b, float factor) {
aiQuaternion result;
aiQuaternion::Interpolate(result, a, b, factor);
return result.Normalize();
}).GetMatrix())));
boneTransformation = position * rotation * scale;
}
glm::mat4 globalTransformation = parentTransform * boneTransformation;
transforms[bone.index] = globalInverseTransform * globalTransformation * bone.offsetMatrix;
for (auto& child : bone.children)
calcBoneTransformation(animTime, *child, globalTransformation, bounds, transforms);
}

View File

@ -16,60 +16,68 @@
#include "client/graph/mesh/EntityMesh.h"
class AtlasRef;
class SerializedModel;
class Model {
public:
Model() = default;
void fromMesh(std::unique_ptr<EntityMesh> mesh);
int fromFile(const std::string &path, const std::vector<std::shared_ptr<AtlasRef>> &texture);
int fromSerialized(const SerializedModel &model, const std::vector<std::shared_ptr<AtlasRef>> &texture);
void getTransformsByFrame(double frame, glm::ivec2 bounds, std::vector<glm::mat4>& transforms);
public:
Model() = default;
void fromMesh(std::unique_ptr<EntityMesh> mesh);
int fromFile(const std::string& path, const std::vector<std::shared_ptr<AtlasRef>>& texture);
int fromSerialized(const SerializedModel& model, const std::vector<std::shared_ptr<AtlasRef>>& texture);
void getTransformsByFrame(double frame, glm::ivec2 bounds, std::vector<glm::mat4>& transforms);
// void getTransformsByTime(double time, std::tuple<uint> bounds, std::vector<glm::mat4>& transforms);
const ModelAnimation& getAnimation();
std::vector<std::unique_ptr<EntityMesh>> meshes;
private:
void loadModelMeshes(aiNode *node, const aiScene *scene);
void loadMeshAndBone(aiMesh *mesh, std::unique_ptr<EntityMesh> &target);
void loadAnimations(const aiScene *scene);
void calcBoneHeirarchy(aiNode *node, const aiScene *scene, int parentBoneIndex);
void calcBoneTransformation(double animTime, ModelBone& bone, glm::mat4 parentTransform, glm::ivec2 bounds, std::vector<glm::mat4>& transforms);
template <typename T> static inline T calcBoneVal(
double animTime, glm::ivec2 bounds, const std::vector<std::pair<double, T>>& keysArray,
const T& def, std::function<T(const T& a, const T& b, float factor)> merge) {
if (keysArray.empty()) return def;
if (keysArray.size() == 1) return keysArray[0].second;
unsigned int index = 0;
for (unsigned int i = 1; i < keysArray.size(); i++) {
if (keysArray[i].first > animTime) {
index = i - 1;
break;
}
}
float factor = 1;
unsigned int nextIndex = index + 1;
if (nextIndex >= keysArray.size() || nextIndex > bounds.y) nextIndex = bounds.x;
else {
double delta = keysArray[nextIndex].first - keysArray[index].first;
factor = (animTime - keysArray[index].first) / delta;
}
return merge(keysArray[index].second, keysArray[nextIndex].second, factor);
}
ModelAnimation animation {};
std::vector<ModelBone*> rootBones {};
std::vector<ModelBone> bones {};
std::vector<std::shared_ptr<AtlasRef>> textures {};
glm::mat4 globalInverseTransform {};
const ModelAnimation& getAnimation();
std::vector<std::unique_ptr<EntityMesh>> meshes;
private:
void loadModelMeshes(aiNode* node, const aiScene* scene);
void loadMeshAndBone(aiMesh* mesh, std::unique_ptr<EntityMesh>& target);
void loadAnimations(const aiScene* scene);
void calcBoneHeirarchy(aiNode* node, const aiScene* scene, int parentBoneIndex);
void calcBoneTransformation(double animTime, ModelBone& bone, glm::mat4 parentTransform, glm::ivec2 bounds,
std::vector<glm::mat4>& transforms);
template<typename T>
static inline T calcBoneVal(
double animTime, glm::ivec2 bounds, const std::vector<std::pair<double, T>>& keysArray,
const T& def, std::function<T(const T& a, const T& b, float factor)> merge) {
if (keysArray.empty()) return def;
if (keysArray.size() == 1) return keysArray[0].second;
unsigned int index = 0;
for (unsigned int i = 1; i < keysArray.size(); i++) {
if (keysArray[i].first > animTime) {
index = i - 1;
break;
}
}
float factor = 1;
unsigned int nextIndex = index + 1;
if (nextIndex >= keysArray.size() || nextIndex > bounds.y) nextIndex = bounds.x;
else {
double delta = keysArray[nextIndex].first - keysArray[index].first;
factor = (animTime - keysArray[index].first) / delta;
}
return merge(keysArray[index].second, keysArray[nextIndex].second, factor);
}
ModelAnimation animation{};
std::vector<ModelBone*> rootBones{};
std::vector<ModelBone> bones{};
std::vector<std::shared_ptr<AtlasRef>> textures{};
glm::mat4 globalInverseTransform{};
};

View File

@ -5,4 +5,4 @@
#include "ModelAnimation.h"
ModelAnimation::ModelAnimation(const std::string& name)
: name(name) {}
: name(name) {}

View File

@ -10,12 +10,13 @@
#include "world/dim/ent/AnimChannel.h"
class ModelAnimation {
public:
ModelAnimation() = default;
explicit ModelAnimation(const std::string& name);
std::string name = "";
std::vector<AnimChannel> channels {};
unsigned int duration = 0;
double ticksPerSecond = 0;
public:
ModelAnimation() = default;
explicit ModelAnimation(const std::string& name);
std::string name = "";
std::vector<AnimChannel> channels{};
unsigned int duration = 0;
double ticksPerSecond = 0;
};

View File

@ -5,6 +5,6 @@
#include "ModelBone.h"
ModelBone::ModelBone(unsigned int index, int parent, const std::string& name) :
index(index),
parent(parent),
name(name) {}
index(index),
parent(parent),
name(name) {}

View File

@ -9,15 +9,16 @@
#include <glm/mat4x4.hpp>
class ModelBone {
public:
ModelBone() = default;
ModelBone(unsigned int index, int parent, const std::string& name);
std::string name {};
unsigned int index = 0;
int parent = 0;
glm::mat4 offsetMatrix {};
std::vector<ModelBone*> children;
public:
ModelBone() = default;
ModelBone(unsigned int index, int parent, const std::string& name);
std::string name{};
unsigned int index = 0;
int parent = 0;
glm::mat4 offsetMatrix{};
std::vector<ModelBone*> children;
};

View File

@ -6,229 +6,232 @@
#include "Renderer.h"
Renderer::Renderer() : Renderer({1366, 768}) {};
Renderer::Renderer() : Renderer({ 1366, 768 }) {};
Renderer::Renderer(glm::ivec2 win) :
activeTexture(nullptr),
window(win),
world (win, 2),
entity(win, 2),
ssao (win, 1, 24),
blur (win, 1),
light (win, 2) {
camera.create(window.getSize().x, window.getSize().y, glm::vec3(0, 1, 0));
ssao.createFromFile("../assets/shader/post/passThrough.vs", "../assets/shader/post/ssaoCalc.fs");
blur.createFromFile("../assets/shader/post/passThrough.vs", "../assets/shader/post/ssaoBlur.fs");
light.createFromFile("../assets/shader/post/passThrough.vs", "../assets/shader/post/deferredLighting.fs");
world.createFromFile("../assets/shader/world/world.vs", "../assets/shader/world/world.fs", "../assets/shader/world/world.gs");
entity.createFromFile("../assets/shader/world/entity.vs", "../assets/shader/world/entity.fs");
guiShader = Shader();
guiShader.createFromFile("../assets/shader/ortho/hud.vs", "../assets/shader/ortho/hud.fs");
gu.matrix = camera.getOrthographicMatrix();
gu.ortho = guiShader.get("ortho");
gu.model = guiShader.get("model");
gu.bones = guiShader.get("uBones");
gu.clipBounds = guiShader.get("uClipBounds");
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
window.addResizeCallback("renderer", [&](glm::ivec2 win) {
ssao.windowResized(win);
blur.windowResized(win);
light.windowResized(win);
world.windowResized(win);
camera.changeWindowDimensions(win);
gu.matrix = camera.getOrthographicMatrix();
});
activeTexture(nullptr),
window(win),
world(win, 2),
entity(win, 2),
ssao(win, 1, 24),
blur(win, 1),
light(win, 2) {
camera.create(window.getSize().x, window.getSize().y, glm::vec3(0, 1, 0));
ssao.createFromFile("../assets/shader/post/passThrough.vs", "../assets/shader/post/ssaoCalc.fs");
blur.createFromFile("../assets/shader/post/passThrough.vs", "../assets/shader/post/ssaoBlur.fs");
light.createFromFile("../assets/shader/post/passThrough.vs", "../assets/shader/post/deferredLighting.fs");
world.createFromFile("../assets/shader/world/world.vs", "../assets/shader/world/world.fs",
"../assets/shader/world/world.gs");
entity.createFromFile("../assets/shader/world/entity.vs", "../assets/shader/world/entity.fs");
guiShader = Shader();
guiShader.createFromFile("../assets/shader/ortho/hud.vs", "../assets/shader/ortho/hud.fs");
gu.matrix = camera.getOrthographicMatrix();
gu.ortho = guiShader.get("ortho");
gu.model = guiShader.get("model");
gu.bones = guiShader.get("uBones");
gu.clipBounds = guiShader.get("uClipBounds");
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
window.addResizeCallback("renderer", [&](glm::ivec2 win) {
ssao.windowResized(win);
blur.windowResized(win);
light.windowResized(win);
world.windowResized(win);
camera.changeWindowDimensions(win);
gu.matrix = camera.getOrthographicMatrix();
});
}
void Renderer::update(double delta) {
//VSync 1 = On, 0 = Off
glfwSwapInterval(1);
elapsedTime += delta;
window.update();
world.updateSwayMap(delta);
//VSync 1 = On, 0 = Off
glfwSwapInterval(1);
elapsedTime += delta;
window.update();
world.updateSwayMap(delta);
}
void Renderer::beginChunkDeferredCalls() {
activeTexture = nullptr;
currentModelUniform = world.uniforms.model;
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDisable(GL_BLEND);
glViewport(0, 0, static_cast<int>(world.windowSize.x * world.bufferScale), static_cast<int>(world.windowSize.y * world.bufferScale));
glBindFramebuffer(GL_FRAMEBUFFER, light.gBuffer);
glClear(GL_DEPTH_BUFFER_BIT);
const float skyColor[] = {clearColor.x, clearColor.y, clearColor.z, 1};
static const float clearTransparent[] = {0, 0, 0, 1};
glClearBufferfv(GL_COLOR, 0, clearTransparent);
glClearBufferfv(GL_COLOR, 1, clearTransparent);
glClearBufferfv(GL_COLOR, 2, skyColor);
setShader(world);
world.set(world.uniforms.proj, camera.getProjectionMatrix());
world.set(world.uniforms.view, camera.getViewMatrix());
world.set(world.uniforms.time, static_cast<float>(elapsedTime));
world.swayTex.use(1);
activeTexture = nullptr;
currentModelUniform = world.uniforms.model;
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDisable(GL_BLEND);
glViewport(0, 0, static_cast<int>(world.windowSize.x * world.bufferScale),
static_cast<int>(world.windowSize.y * world.bufferScale));
glBindFramebuffer(GL_FRAMEBUFFER, light.gBuffer);
glClear(GL_DEPTH_BUFFER_BIT);
const float skyColor[] = { clearColor.x, clearColor.y, clearColor.z, 1 };
static const float clearTransparent[] = { 0, 0, 0, 1 };
glClearBufferfv(GL_COLOR, 0, clearTransparent);
glClearBufferfv(GL_COLOR, 1, clearTransparent);
glClearBufferfv(GL_COLOR, 2, skyColor);
setShader(world);
world.set(world.uniforms.proj, camera.getProjectionMatrix());
world.set(world.uniforms.view, camera.getViewMatrix());
world.set(world.uniforms.time, static_cast<float>(elapsedTime));
world.swayTex.use(1);
}
void Renderer::beginEntityDeferredCalls() {
currentModelUniform = entity.uniforms.model;
setShader(entity);
entity.set(entity.uniforms.proj, camera.getProjectionMatrix());
entity.set(entity.uniforms.view, camera.getViewMatrix());
currentModelUniform = entity.uniforms.model;
setShader(entity);
entity.set(entity.uniforms.proj, camera.getProjectionMatrix());
entity.set(entity.uniforms.view, camera.getViewMatrix());
}
void Renderer::endDeferredCalls() {
activeTexture = nullptr;
glBindFramebuffer(GL_FRAMEBUFFER, ssao.fbo);
glClearColor(clearColor.x, clearColor.y, clearColor.z, 0);
glClear(GL_COLOR_BUFFER_BIT);
setShader(ssao);
ssao.set(ssao.uniforms.proj, camera.getProjectionMatrix());
ssao.set(ssao.uniforms.view, camera.getViewMatrix());
ssao.set(ssao.uniforms.kernelCount, ssao.kernelCount);
for (unsigned int i = 0; i < ssao.kernelCount; i++) {
GLint uni = ssao.get("samples[" + std::to_string(i) + "]");
ssao.set(uni, ssao.kernels[i]);
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, light.gPosition);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, light.gNormal);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, ssao.tex);
renderQuad();
auto winSize = window.getSize();
glViewport(0, 0, static_cast<int>(winSize.x), static_cast<int>(winSize.y));
glBindFramebuffer(GL_FRAMEBUFFER, blur.fbo);
glClear(GL_COLOR_BUFFER_BIT);
setShader(blur);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, ssao.colorBuffer);
renderQuad();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
setShader(light);
light.set(light.uniforms.camPosition, camera.getPos());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, light.gPosition);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, light.gNormal);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, light.gColorSpec);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, blur.colorBuffer);
glEnable(GL_BLEND);
renderQuad();
activeTexture = nullptr;
glBindFramebuffer(GL_FRAMEBUFFER, ssao.fbo);
glClearColor(clearColor.x, clearColor.y, clearColor.z, 0);
glClear(GL_COLOR_BUFFER_BIT);
setShader(ssao);
ssao.set(ssao.uniforms.proj, camera.getProjectionMatrix());
ssao.set(ssao.uniforms.view, camera.getViewMatrix());
ssao.set(ssao.uniforms.kernelCount, ssao.kernelCount);
for (unsigned int i = 0; i < ssao.kernelCount; i++) {
GLint uni = ssao.get("samples[" + std::to_string(i) + "]");
ssao.set(uni, ssao.kernels[i]);
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, light.gPosition);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, light.gNormal);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, ssao.tex);
renderQuad();
auto winSize = window.getSize();
glViewport(0, 0, static_cast<int>(winSize.x), static_cast<int>(winSize.y));
glBindFramebuffer(GL_FRAMEBUFFER, blur.fbo);
glClear(GL_COLOR_BUFFER_BIT);
setShader(blur);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, ssao.colorBuffer);
renderQuad();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
setShader(light);
light.set(light.uniforms.camPosition, camera.getPos());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, light.gPosition);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, light.gNormal);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, light.gColorSpec);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, blur.colorBuffer);
glEnable(GL_BLEND);
renderQuad();
}
void Renderer::beginGUIDrawCalls() {
activeTexture = nullptr;
currentModelUniform = gu.model;
glClear(GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
setShader(guiShader);
guiShader.set(gu.ortho, gu.matrix);
activeTexture = nullptr;
currentModelUniform = gu.model;
glClear(GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
setShader(guiShader);
guiShader.set(gu.ortho, gu.matrix);
}
void Renderer::swapBuffers() {
Shader::clearShader();
window.swapBuffers();
Shader::clearShader();
window.swapBuffers();
}
void Renderer::setShader(Shader& s) {
s.use();
this->currentShader = &s;
s.use();
this->currentShader = &s;
}
void Renderer::setClearColor(unsigned char r, unsigned char g, unsigned char b) {
clearColor = {static_cast<float>(r)/255.f, static_cast<float>(g)/255.f, static_cast<float>(b)/255.f, 1};
clearColor = { static_cast<float>(r) / 255.f, static_cast<float>(g) / 255.f, static_cast<float>(b) / 255.f, 1 };
}
void Renderer::toggleDepthTest(bool enable) {
enable ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
enable ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
}
void Renderer::clearDepthBuffer() {
glClear(GL_DEPTH_BUFFER_BIT);
glClear(GL_DEPTH_BUFFER_BIT);
}
void Renderer::setModelMatrix(const glm::mat4& modelMatrix) {
glUniformMatrix4fv(currentModelUniform, 1, GL_FALSE, glm::value_ptr(modelMatrix));
glUniformMatrix4fv(currentModelUniform, 1, GL_FALSE, glm::value_ptr(modelMatrix));
}
void Renderer::setBones(std::vector<glm::mat4> &transforms) {
if (transforms.empty()) return;
currentShader->setArr((currentShader == &entity ? entity.uniforms.bones : gu.bones), static_cast<GLsizei>(transforms.size()), transforms.at(0));
void Renderer::setBones(std::vector<glm::mat4>& transforms) {
if (transforms.empty()) return;
currentShader->setArr((currentShader == &entity ? entity.uniforms.bones : gu.bones),
static_cast<GLsizei>(transforms.size()), transforms.at(0));
}
void Renderer::setClipBounds(glm::vec4 bounds) {
guiShader.set(gu.clipBounds, {bounds.x, window.getSize().y - bounds.w, bounds.z, window.getSize().y - bounds.y});
guiShader.set(gu.clipBounds, { bounds.x, window.getSize().y - bounds.w, bounds.z, window.getSize().y - bounds.y });
}
void Renderer::enableTexture(Texture *texture) {
if (texture != activeTexture) {
activeTexture = texture;
texture->use(0);
}
void Renderer::enableTexture(Texture* texture) {
if (texture != activeTexture) {
activeTexture = texture;
texture->use(0);
}
}
void Renderer::renderQuad() {
if (quadVAO == 0) {
float quadVertices[] = {
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
};
glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO);
glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *) nullptr);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *) (3 * sizeof(float)));
}
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
if (quadVAO == 0) {
float quadVertices[] = {
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
};
glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO);
glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*) nullptr);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*) (3 * sizeof(float)));
}
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}

View File

@ -17,52 +17,62 @@
#include "shader/GuiUniforms.h"
class Renderer {
public:
Renderer();
Renderer(glm::ivec2 win);
void update(double delta);
void beginChunkDeferredCalls();
void beginEntityDeferredCalls();
void endDeferredCalls();
void beginGUIDrawCalls();
void swapBuffers();
void setShader(Shader& s);
void setClearColor(unsigned char r, unsigned char g, unsigned char b);
static void toggleDepthTest(bool enable);
static void clearDepthBuffer();
void setModelMatrix(const glm::mat4& modelMatrix);
void setBones(std::vector<glm::mat4>& transforms);
void setClipBounds(glm::vec4 bounds);
void enableTexture(Texture* texture);
Window window;
Camera camera;
private:
void renderQuad();
unsigned int quadVAO = 0;
unsigned int quadVBO = 0;
glm::vec4 clearColor {0, 0, 0, 1};
Texture* activeTexture;
WorldGeometryShader world;
EntityGeometryShader entity;
SSAOShader ssao;
BlurShader blur;
LightingShader light;
Shader guiShader;
GuiUniforms gu;
Shader* currentShader;
GLint currentModelUniform;
double elapsedTime = 0;
public:
Renderer();
Renderer(glm::ivec2 win);
void update(double delta);
void beginChunkDeferredCalls();
void beginEntityDeferredCalls();
void endDeferredCalls();
void beginGUIDrawCalls();
void swapBuffers();
void setShader(Shader& s);
void setClearColor(unsigned char r, unsigned char g, unsigned char b);
static void toggleDepthTest(bool enable);
static void clearDepthBuffer();
void setModelMatrix(const glm::mat4& modelMatrix);
void setBones(std::vector<glm::mat4>& transforms);
void setClipBounds(glm::vec4 bounds);
void enableTexture(Texture* texture);
Window window;
Camera camera;
private:
void renderQuad();
unsigned int quadVAO = 0;
unsigned int quadVBO = 0;
glm::vec4 clearColor{ 0, 0, 0, 1 };
Texture* activeTexture;
WorldGeometryShader world;
EntityGeometryShader entity;
SSAOShader ssao;
BlurShader blur;
LightingShader light;
Shader guiShader;
GuiUniforms gu;
Shader* currentShader;
GLint currentModelUniform;
double elapsedTime = 0;
};

View File

@ -8,59 +8,59 @@
#include "Texture.h"
Texture::Texture(const std::string& file) :
fileLocation(file) {
loadFromFile(this->fileLocation);
fileLocation(file) {
loadFromFile(this->fileLocation);
}
void Texture::loadFromFile(std::string file) {
unsigned char *texData = stbi_load(file.c_str(), &width, &height, &bitDepth, 0);
if (!texData) throw std::runtime_error("Failed to find texture at " + file + ".");
loadFromBytes(texData, width, height);
stbi_image_free(texData);
unsigned char* texData = stbi_load(file.c_str(), &width, &height, &bitDepth, 0);
if (!texData) throw std::runtime_error("Failed to find texture at " + file + ".");
loadFromBytes(texData, width, height);
stbi_image_free(texData);
}
void Texture::loadFromBytes(unsigned char* bytes, int width, int height, GLint interpolation, GLint repeatMode) {
if (textureID != 0) clear();
this->width = width;
this->height = height;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, repeatMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, repeatMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, interpolation);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, interpolation);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bytes);
glGenerateMipmap(GL_TEXTURE_2D);
//Unbind current texture
glBindTexture(GL_TEXTURE_2D, 0);
if (textureID != 0) clear();
this->width = width;
this->height = height;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, repeatMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, repeatMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, interpolation);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, interpolation);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bytes);
glGenerateMipmap(GL_TEXTURE_2D);
//Unbind current texture
glBindTexture(GL_TEXTURE_2D, 0);
}
void Texture::updateTexture(int x, int y, int width, int height, unsigned char *bytes) {
glBindTexture(GL_TEXTURE_2D, textureID);
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, bytes);
void Texture::updateTexture(int x, int y, int width, int height, unsigned char* bytes) {
glBindTexture(GL_TEXTURE_2D, textureID);
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, bytes);
}
void Texture::use(GLuint position) {
glActiveTexture(GL_TEXTURE0 + position);
glBindTexture(GL_TEXTURE_2D, textureID);
glActiveTexture(GL_TEXTURE0 + position);
glBindTexture(GL_TEXTURE_2D, textureID);
}
void Texture::clear() {
glDeleteTextures(1, &textureID);
textureID = 0;
fileLocation = "";
width = 0;
height = 0;
bitDepth = 0;
glDeleteTextures(1, &textureID);
textureID = 0;
fileLocation = "";
width = 0;
height = 0;
bitDepth = 0;
}
Texture::~Texture() {
clear();
clear();
}

View File

@ -8,25 +8,30 @@
#include <GL/glew.h>
class Texture {
public:
Texture() = default;
explicit Texture(const std::string& file);
void loadFromFile(std::string file);
void loadFromBytes(unsigned char* bytes, int width, int height, GLint interpolation = GL_NEAREST, GLint repeatMode = GL_CLAMP_TO_EDGE);
void updateTexture(int x, int y, int width, int height, unsigned char* bytes);
void use(GLuint position = 0);
void clear();
~Texture();
protected:
unsigned int textureID = 0;
int width = 0;
int height = 0;
int bitDepth = 0;
std::string fileLocation;
public:
Texture() = default;
explicit Texture(const std::string& file);
void loadFromFile(std::string file);
void loadFromBytes(unsigned char* bytes, int width, int height, GLint interpolation = GL_NEAREST,
GLint repeatMode = GL_CLAMP_TO_EDGE);
void updateTexture(int x, int y, int width, int height, unsigned char* bytes);
void use(GLuint position = 0);
void clear();
~Texture();
protected:
unsigned int textureID = 0;
int width = 0;
int height = 0;
int bitDepth = 0;
std::string fileLocation;
};

View File

@ -7,23 +7,23 @@
#include "ChunkVertex.h"
void ChunkMesh::create(const std::vector<ChunkVertex>& vertices, const std::vector<unsigned int>& indices) {
indCount = static_cast<GLsizei>(indices.size());
genArrays(static_cast<unsigned int>(vertices.size() * sizeof(ChunkVertex)),
static_cast<unsigned int>(indices.size() * sizeof(unsigned int)),
&vertices.front(), &indices.front());
unsigned int idx = 0;
createVertexAttrib(idx++, 3, GL_FLOAT, STRIDE_OFFSET_CHUNK(position));
createVertexAttrib(idx++, 2, GL_FLOAT, STRIDE_OFFSET_CHUNK(texCoords));
createVertexAttrib(idx++, 3, GL_FLOAT, STRIDE_OFFSET_CHUNK(blendColor));
createVertexAttrib(idx++, 2, GL_FLOAT, STRIDE_OFFSET_CHUNK(blendMaskCoords));
createVertexAttrib(idx++, 1, GL_FLOAT, STRIDE_OFFSET_CHUNK(normal));
createVertexAttrib(idx++, 4, GL_FLOAT, STRIDE_OFFSET_CHUNK(light));
createVertexAttrib(idx++, 1, GL_FLOAT, STRIDE_OFFSET_CHUNK(shaderMod));
createVertexAttrib(idx , 3, GL_FLOAT, STRIDE_OFFSET_CHUNK(modValues));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
indCount = static_cast<GLsizei>(indices.size());
genArrays(static_cast<unsigned int>(vertices.size() * sizeof(ChunkVertex)),
static_cast<unsigned int>(indices.size() * sizeof(unsigned int)),
&vertices.front(), &indices.front());
unsigned int idx = 0;
createVertexAttrib(idx++, 3, GL_FLOAT, STRIDE_OFFSET_CHUNK(position));
createVertexAttrib(idx++, 2, GL_FLOAT, STRIDE_OFFSET_CHUNK(texCoords));
createVertexAttrib(idx++, 3, GL_FLOAT, STRIDE_OFFSET_CHUNK(blendColor));
createVertexAttrib(idx++, 2, GL_FLOAT, STRIDE_OFFSET_CHUNK(blendMaskCoords));
createVertexAttrib(idx++, 1, GL_FLOAT, STRIDE_OFFSET_CHUNK(normal));
createVertexAttrib(idx++, 4, GL_FLOAT, STRIDE_OFFSET_CHUNK(light));
createVertexAttrib(idx++, 1, GL_FLOAT, STRIDE_OFFSET_CHUNK(shaderMod));
createVertexAttrib(idx, 3, GL_FLOAT, STRIDE_OFFSET_CHUNK(modValues));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}

View File

@ -12,11 +12,12 @@
class ChunkVertex;
class ChunkMesh : public Mesh {
public:
ChunkMesh() = default;
ChunkMesh(const ChunkMesh& o) { throw std::runtime_error("No copy constructor for ChunkMeshes"); };
void create(const std::vector<ChunkVertex>& vertices, const std::vector<unsigned int>& indices);
~ChunkMesh() = default;
public:
ChunkMesh() = default;
ChunkMesh(const ChunkMesh& o) { throw std::runtime_error("No copy constructor for ChunkMeshes"); };
void create(const std::vector<ChunkVertex>& vertices, const std::vector<unsigned int>& indices);
~ChunkMesh() = default;
};

View File

@ -5,6 +5,7 @@
#include <vector>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/normal.hpp>
#include "ChunkMeshGenerator.h"
@ -21,129 +22,141 @@
#include "game/atlas/LocalBiomeAtlas.h"
#include "game/atlas/LocalDefinitionAtlas.h"
ChunkMeshGenerator::ChunkMeshGenerator(ChunkMeshDetails* meshDetails, LocalDefinitionAtlas& defs, LocalBiomeAtlas& biomes,
std::shared_ptr<Chunk> chunk, std::array<std::shared_ptr<Chunk>, 6> adjacent, std::array<NoiseSample, 3>& blockOffsets) :
meshDetails(meshDetails),
adjacent(adjacent),
biomes(biomes),
chunk(chunk),
defs(defs) {
Timer t("Mesh generation");
meshDetails->vertices.reserve(5000);
meshDetails->indices.reserve(7000);
auto l = chunk->getReadLock();
RIE::expand<unsigned int, 4096>(chunk->cGetBlocks(), eBlocks);
RIE::expand<unsigned short, 4096>(chunk->cGetBiomes(), eBiomes);
l.unlock();
BlockDef* block = nullptr;
BiomeDef* biome = nullptr;
for (unsigned short i = 0; i < 4096; i++) {
if (!block || block->index != eBlocks[i]) block = &defs.blockFromId(eBlocks[i]);
if (!biome || biome->index != eBiomes[i]) biome = &biomes.biomeFromId(eBiomes[i]);
BlockModel& model = block->model;
glm::vec3 biomeTint = biome->tint;
if (!model.visible) continue;
glm::ivec3 off = Space::Block::fromIndex(i);
glm::vec3 vis = off;
for (auto& mod : model.meshMods) {
switch (mod.first) {
default: break;
case MeshMod::OFFSET_X: vis.x += blockOffsets[0].get(vis / 16.f) * mod.second; break;
case MeshMod::OFFSET_Y: vis.y += blockOffsets[1].get(vis / 16.f) * mod.second; break;
case MeshMod::OFFSET_Z: vis.z += blockOffsets[2].get(vis / 16.f) * mod.second; break;
}
}
glm::ivec3 pos = { off.x - 1, off.y, off.z };
if (!getBlockAt(pos).culls) addFaces(vis, model.parts[static_cast<int>(EVec::XNEG)], biomeTint, getLightAt(pos));
pos = { off.x + 1, off.y, off.z };
if (!getBlockAt(pos).culls) addFaces(vis, model.parts[static_cast<int>(EVec::XPOS)], biomeTint, getLightAt(pos));
pos = { off.x, off.y - 1, off.z };
if (!getBlockAt(pos).culls) addFaces(vis, model.parts[static_cast<int>(EVec::YNEG)], biomeTint, getLightAt(pos));
pos = { off.x, off.y + 1, off.z };
if (!getBlockAt(pos).culls) addFaces(vis, model.parts[static_cast<int>(EVec::YPOS)], biomeTint, getLightAt(pos));
pos = { off.x, off.y, off.z - 1 };
if (!getBlockAt(pos).culls) addFaces(vis, model.parts[static_cast<int>(EVec::ZNEG)], biomeTint, getLightAt(pos));
pos = { off.x, off.y, off.z + 1 };
if (!getBlockAt(pos).culls) addFaces(vis, model.parts[static_cast<int>(EVec::ZPOS)], biomeTint, getLightAt(pos));
addFaces(vis, model.parts[static_cast<int>(EVec::NO_CULL)], biomeTint, getLightAt(vis));
}
meshDetails->vertices.shrink_to_fit();
meshDetails->indices.shrink_to_fit();
ChunkMeshGenerator::ChunkMeshGenerator(ChunkMeshDetails* meshDetails, LocalDefinitionAtlas& defs,
LocalBiomeAtlas& biomes,
std::shared_ptr<Chunk> chunk, std::array<std::shared_ptr<Chunk>, 6> adjacent,
std::array<NoiseSample, 3>& blockOffsets) :
meshDetails(meshDetails),
adjacent(adjacent),
biomes(biomes),
chunk(chunk),
defs(defs) {
Timer t("Mesh generation");
meshDetails->vertices.reserve(5000);
meshDetails->indices.reserve(7000);
auto l = chunk->getReadLock();
RIE::expand<unsigned int, 4096>(chunk->cGetBlocks(), eBlocks);
RIE::expand<unsigned short, 4096>(chunk->cGetBiomes(), eBiomes);
l.unlock();
BlockDef* block = nullptr;
BiomeDef* biome = nullptr;
for (unsigned short i = 0; i < 4096; i++) {
if (!block || block->index != eBlocks[i]) block = &defs.blockFromId(eBlocks[i]);
if (!biome || biome->index != eBiomes[i]) biome = &biomes.biomeFromId(eBiomes[i]);
BlockModel& model = block->model;
glm::vec3 biomeTint = biome->tint;
if (!model.visible) continue;
glm::ivec3 off = Space::Block::fromIndex(i);
glm::vec3 vis = off;
for (auto& mod : model.meshMods) {
switch (mod.first) {
default: break;
case MeshMod::OFFSET_X: vis.x += blockOffsets[0].get(vis / 16.f) * mod.second;
break;
case MeshMod::OFFSET_Y: vis.y += blockOffsets[1].get(vis / 16.f) * mod.second;
break;
case MeshMod::OFFSET_Z: vis.z += blockOffsets[2].get(vis / 16.f) * mod.second;
break;
}
}
glm::ivec3 pos = { off.x - 1, off.y, off.z };
if (!getBlockAt(pos).culls)
addFaces(vis, model.parts[static_cast<int>(EVec::XNEG)], biomeTint, getLightAt(pos));
pos = { off.x + 1, off.y, off.z };
if (!getBlockAt(pos).culls)
addFaces(vis, model.parts[static_cast<int>(EVec::XPOS)], biomeTint, getLightAt(pos));
pos = { off.x, off.y - 1, off.z };
if (!getBlockAt(pos).culls)
addFaces(vis, model.parts[static_cast<int>(EVec::YNEG)], biomeTint, getLightAt(pos));
pos = { off.x, off.y + 1, off.z };
if (!getBlockAt(pos).culls)
addFaces(vis, model.parts[static_cast<int>(EVec::YPOS)], biomeTint, getLightAt(pos));
pos = { off.x, off.y, off.z - 1 };
if (!getBlockAt(pos).culls)
addFaces(vis, model.parts[static_cast<int>(EVec::ZNEG)], biomeTint, getLightAt(pos));
pos = { off.x, off.y, off.z + 1 };
if (!getBlockAt(pos).culls)
addFaces(vis, model.parts[static_cast<int>(EVec::ZPOS)], biomeTint, getLightAt(pos));
addFaces(vis, model.parts[static_cast<int>(EVec::NO_CULL)], biomeTint, getLightAt(vis));
}
meshDetails->vertices.shrink_to_fit();
meshDetails->indices.shrink_to_fit();
// t.printElapsedMs();
}
BlockDef& ChunkMeshGenerator::getBlockAt(const glm::ivec3& pos) {
glm::ivec3 dir = {(pos.x < 0 ? -1 : pos.x > 15 ? 1 : 0),
(pos.y < 0 ? -1 : pos.y > 15 ? 1 : 0), (pos.z < 0 ? -1 : pos.z > 15 ? 1 : 0)};
if (dir != glm::ivec3 {0, 0, 0}) {
unsigned int ind = static_cast<unsigned int>(Vec::TO_ENUM.at(dir));
auto& chunk = adjacent[ind];
return defs.blockFromId(chunk->getBlock(Space::Block::index(pos - dir * 16)));
}
return defs.blockFromId(eBlocks[Space::Block::index(pos)]);
glm::ivec3 dir = { (pos.x < 0 ? -1 : pos.x > 15 ? 1 : 0),
(pos.y < 0 ? -1 : pos.y > 15 ? 1 : 0), (pos.z < 0 ? -1 : pos.z > 15 ? 1 : 0) };
if (dir != glm::ivec3{ 0, 0, 0 }) {
unsigned int ind = static_cast<unsigned int>(Vec::TO_ENUM.at(dir));
auto& chunk = adjacent[ind];
return defs.blockFromId(chunk->getBlock(Space::Block::index(pos - dir * 16)));
}
return defs.blockFromId(eBlocks[Space::Block::index(pos)]);
}
glm::vec4 ChunkMeshGenerator::getLightAt(const glm::ivec3& pos) {
glm::ivec3 dir = {(pos.x < 0 ? -1 : pos.x > 15 ? 1 : 0),
(pos.y < 0 ? -1 : pos.y > 15 ? 1 : 0), (pos.z < 0 ? -1 : pos.z > 15 ? 1 : 0)};
if (dir != glm::ivec3 {0, 0, 0}) {
unsigned int ind = static_cast<unsigned int>(Vec::TO_ENUM.at(dir));
auto& chunk = adjacent[ind];
return chunk->getLight(Space::Block::index(pos - dir * 16));
}
return chunk->getLight(Space::Block::index(pos));
glm::ivec3 dir = { (pos.x < 0 ? -1 : pos.x > 15 ? 1 : 0),
(pos.y < 0 ? -1 : pos.y > 15 ? 1 : 0), (pos.z < 0 ? -1 : pos.z > 15 ? 1 : 0) };
if (dir != glm::ivec3{ 0, 0, 0 }) {
unsigned int ind = static_cast<unsigned int>(Vec::TO_ENUM.at(dir));
auto& chunk = adjacent[ind];
return chunk->getLight(Space::Block::index(pos - dir * 16));
}
return chunk->getLight(Space::Block::index(pos));
}
void ChunkMeshGenerator::addFaces(const glm::vec3 &offset, const std::vector<MeshPart> &meshParts, const glm::vec3& tint, glm::vec4 light) {
for (const MeshPart& mp : meshParts) {
glm::vec3 modData = {};
switch (mp.shaderMod) {
default: break;
case ShaderMod::ROTATE_X:
case ShaderMod::ROTATE_Y:
case ShaderMod::ROTATE_Z:
case ShaderMod::SWAY_ATTACHED:
case ShaderMod::SWAY_FULL_BLOCK:
modData = { Util::packFloat((offset - 8.f) / 8.f), mp.modValue, 0 };
break;
}
for (const BlockModelVertex &vertex : mp.vertices) {
meshDetails->vertices.push_back({
vertex.pos + offset,
vertex.tex,
mp.blendInd ? tint : glm::vec3 {1, 1, 1},
mp.blendInd ? vertex.blendMask : glm::vec2 {-1, -1},
Util::packFloat(vertex.nml),
glm::vec4(light),
static_cast<float>(mp.shaderMod),
modData
});
}
for (unsigned int index : mp.indices) {
meshDetails->indices.push_back(indOffset + index);
}
indOffset += mp.vertices.size();
}
void
ChunkMeshGenerator::addFaces(const glm::vec3& offset, const std::vector<MeshPart>& meshParts, const glm::vec3& tint,
glm::vec4 light) {
for (const MeshPart& mp : meshParts) {
glm::vec3 modData = {};
switch (mp.shaderMod) {
default: break;
case ShaderMod::ROTATE_X:
case ShaderMod::ROTATE_Y:
case ShaderMod::ROTATE_Z:
case ShaderMod::SWAY_ATTACHED:
case ShaderMod::SWAY_FULL_BLOCK:modData = { Util::packFloat((offset - 8.f) / 8.f), mp.modValue, 0 };
break;
}
for (const BlockModelVertex& vertex : mp.vertices) {
meshDetails->vertices.push_back({
vertex.pos + offset,
vertex.tex,
mp.blendInd ? tint : glm::vec3{ 1, 1, 1 },
mp.blendInd ? vertex.blendMask : glm::vec2{ -1, -1 },
Util::packFloat(vertex.nml),
glm::vec4(light),
static_cast<float>(mp.shaderMod),
modData
});
}
for (unsigned int index : mp.indices) {
meshDetails->indices.push_back(indOffset + index);
}
indOffset += mp.vertices.size();
}
}

View File

@ -9,33 +9,42 @@
#include <memory>
class Chunk;
class MeshPart;
class BlockDef;
class NoiseSample;
class LocalBiomeAtlas;
class ChunkMeshDetails;
class LocalDefinitionAtlas;
class ChunkMeshGenerator {
public:
ChunkMeshGenerator(ChunkMeshDetails* meshDetails, LocalDefinitionAtlas& defs, LocalBiomeAtlas& biomes,
std::shared_ptr<Chunk> chunk, std::array<std::shared_ptr<Chunk>, 6> adjacent,
std::array<NoiseSample, 3>& blockOffsets);
private:
inline BlockDef& getBlockAt(const glm::ivec3& pos);
inline glm::vec4 getLightAt(const glm::ivec3& pos);
void addFaces(const glm::vec3 &offset, const std::vector<MeshPart> &meshParts, const glm::vec3& tint, glm::vec4 light);
LocalDefinitionAtlas& defs;
LocalBiomeAtlas& biomes;
unsigned int indOffset = 0;
ChunkMeshDetails* meshDetails;
std::shared_ptr<Chunk> chunk;
std::array<std::shared_ptr<Chunk>, 6> adjacent;
std::array<unsigned int, 4096> eBlocks;
std::array<unsigned short, 4096> eBiomes;
public:
ChunkMeshGenerator(ChunkMeshDetails* meshDetails, LocalDefinitionAtlas& defs, LocalBiomeAtlas& biomes,
std::shared_ptr<Chunk> chunk, std::array<std::shared_ptr<Chunk>, 6> adjacent,
std::array<NoiseSample, 3>& blockOffsets);
private:
inline BlockDef& getBlockAt(const glm::ivec3& pos);
inline glm::vec4 getLightAt(const glm::ivec3& pos);
void
addFaces(const glm::vec3& offset, const std::vector<MeshPart>& meshParts, const glm::vec3& tint, glm::vec4 light);
LocalDefinitionAtlas& defs;
LocalBiomeAtlas& biomes;
unsigned int indOffset = 0;
ChunkMeshDetails* meshDetails;
std::shared_ptr<Chunk> chunk;
std::array<std::shared_ptr<Chunk>, 6> adjacent;
std::array<unsigned int, 4096> eBlocks;
std::array<unsigned short, 4096> eBiomes;
};

View File

@ -9,10 +9,12 @@
class Renderer;
struct ChunkRenderElem {
virtual void draw(Renderer& renderer) = 0;
virtual glm::vec3 getPos() = 0;
// Used to determine if the RenderElem should be deleted.
// Bool is if the RenderElem should be kept alive.
// True = keep, False = remove
virtual bool updateChunkUse(glm::vec3 chunk, bool used) = 0;
virtual void draw(Renderer& renderer) = 0;
virtual glm::vec3 getPos() = 0;
// Used to determine if the RenderElem should be deleted.
// Bool is if the RenderElem should be kept alive.
// True = keep, False = remove
virtual bool updateChunkUse(glm::vec3 chunk, bool used) = 0;
};

View File

@ -9,14 +9,14 @@
#include <glm/vec4.hpp>
struct ChunkVertex {
glm::vec3 position;
glm::vec2 texCoords;
glm::vec3 blendColor;
glm::vec2 blendMaskCoords;
float normal;
glm::vec4 light;
float shaderMod;
glm::vec3 modValues;
glm::vec3 position;
glm::vec2 texCoords;
glm::vec3 blendColor;
glm::vec2 blendMaskCoords;
float normal;
glm::vec4 light;
float shaderMod;
glm::vec3 modValues;
};
#define STRIDE_OFFSET_CHUNK(m) sizeof(struct ChunkVertex), (void *)offsetof(struct ChunkVertex, m)

View File

@ -4,38 +4,38 @@
#include "EntityMesh.h"
EntityMesh::EntityMesh(const EntityMesh &o) :
vertices(o.vertices),
indices(o.indices) {
this->indCount = o.indCount;
if (indCount > 0) initModel();
EntityMesh::EntityMesh(const EntityMesh& o) :
vertices(o.vertices),
indices(o.indices) {
this->indCount = o.indCount;
if (indCount > 0) initModel();
}
void EntityMesh::create(const std::vector<EntityVertex>& vertices, const std::vector<unsigned int>& indices) {
indCount = static_cast<GLsizei>(indices.size());
this->vertices = vertices;
this->indices = indices;
initModel();
indCount = static_cast<GLsizei>(indices.size());
this->vertices = vertices;
this->indices = indices;
initModel();
}
void EntityMesh::initModel() {
if (vertices.size() == 0) return;
genArrays(static_cast<unsigned int>(vertices.size() * sizeof(EntityVertex)),
static_cast<unsigned int>(indices.size() * sizeof(unsigned int)),
&vertices.front(), &indices.front());
unsigned int idx = 0;
createVertexAttrib(idx++, 3, GL_FLOAT, STRIDE_OFFSET_ENTITY(position));
createVertexAttrib(idx++, 4, GL_FLOAT, STRIDE_OFFSET_ENTITY(colorData));
createVertexAttrib(idx++, 3, GL_FLOAT, STRIDE_OFFSET_ENTITY(colorBlend));
createVertexAttrib(idx++, 1, GL_FLOAT, STRIDE_OFFSET_ENTITY(useTex));
createVertexAttrib(idx++, 3, GL_FLOAT, STRIDE_OFFSET_ENTITY(normal));
createVertexAttrib(idx++, 4, GL_INT, STRIDE_OFFSET_ENTITY(boneIDs));
createVertexAttrib(idx , 4, GL_FLOAT, STRIDE_OFFSET_ENTITY(boneWeights));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
if (vertices.size() == 0) return;
genArrays(static_cast<unsigned int>(vertices.size() * sizeof(EntityVertex)),
static_cast<unsigned int>(indices.size() * sizeof(unsigned int)),
&vertices.front(), &indices.front());
unsigned int idx = 0;
createVertexAttrib(idx++, 3, GL_FLOAT, STRIDE_OFFSET_ENTITY(position));
createVertexAttrib(idx++, 4, GL_FLOAT, STRIDE_OFFSET_ENTITY(colorData));
createVertexAttrib(idx++, 3, GL_FLOAT, STRIDE_OFFSET_ENTITY(colorBlend));
createVertexAttrib(idx++, 1, GL_FLOAT, STRIDE_OFFSET_ENTITY(useTex));
createVertexAttrib(idx++, 3, GL_FLOAT, STRIDE_OFFSET_ENTITY(normal));
createVertexAttrib(idx++, 4, GL_INT, STRIDE_OFFSET_ENTITY(boneIDs));
createVertexAttrib(idx, 4, GL_FLOAT, STRIDE_OFFSET_ENTITY(boneWeights));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}

View File

@ -11,14 +11,18 @@
#include "EntityVertex.h"
class EntityMesh : public Mesh {
public:
EntityMesh() = default;
EntityMesh(const EntityMesh& o);
void create(const std::vector<EntityVertex>& vertices, const std::vector<unsigned int>& indices);
~EntityMesh() = default;
private:
void initModel();
std::vector<EntityVertex> vertices {};
std::vector<unsigned int> indices {};
public:
EntityMesh() = default;
EntityMesh(const EntityMesh& o);
void create(const std::vector<EntityVertex>& vertices, const std::vector<unsigned int>& indices);
~EntityMesh() = default;
private:
void initModel();
std::vector<EntityVertex> vertices{};
std::vector<unsigned int> indices{};
};

View File

@ -8,19 +8,20 @@
#include <glm/vec4.hpp>
class EntityVertex {
public:
EntityVertex() = default;
EntityVertex(glm::vec3 position, glm::vec4 colorData, glm::vec3 colorBlend, float useTex, glm::vec3 normal,
glm::ivec4 boneIDs, glm::vec4 boneWeights) : position(position), colorData(colorData),
colorBlend(colorBlend), useTex(useTex), normal(normal), boneIDs(boneIDs), boneWeights(boneWeights) {};
glm::vec3 position {};
glm::vec4 colorData {};
glm::vec3 colorBlend {};
float useTex = false;
glm::vec3 normal {};
glm::ivec4 boneIDs {};
glm::vec4 boneWeights {};
public:
EntityVertex() = default;
EntityVertex(glm::vec3 position, glm::vec4 colorData, glm::vec3 colorBlend, float useTex, glm::vec3 normal,
glm::ivec4 boneIDs, glm::vec4 boneWeights) : position(position), colorData(colorData),
colorBlend(colorBlend), useTex(useTex), normal(normal), boneIDs(boneIDs), boneWeights(boneWeights) {};
glm::vec3 position{};
glm::vec4 colorData{};
glm::vec3 colorBlend{};
float useTex = false;
glm::vec3 normal{};
glm::ivec4 boneIDs{};
glm::vec4 boneWeights{};
};
#define STRIDE_OFFSET_ENTITY(m) sizeof(struct EntityVertex), (void *)offsetof(struct EntityVertex, m)

View File

@ -5,44 +5,44 @@
#include "Mesh.h"
void Mesh::cleanup() {
if (VAO != 0) glDeleteVertexArrays(1, &VAO);
if (VBO != 0) glDeleteBuffers(1, &VBO);
if (IBO != 0) glDeleteBuffers(1, &IBO);
IBO = 0;
VBO = 0;
VAO = 0;
indCount = 0;
if (VAO != 0) glDeleteVertexArrays(1, &VAO);
if (VBO != 0) glDeleteBuffers(1, &VBO);
if (IBO != 0) glDeleteBuffers(1, &IBO);
IBO = 0;
VBO = 0;
VAO = 0;
indCount = 0;
}
void Mesh::genArrays(GLuint vboLength, GLuint iboLength, const void *verticesPtr, const void *indicesPtr) {
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, iboLength, indicesPtr, GL_STATIC_DRAW);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vboLength, verticesPtr, GL_STATIC_DRAW);
void Mesh::genArrays(GLuint vboLength, GLuint iboLength, const void* verticesPtr, const void* indicesPtr) {
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, iboLength, indicesPtr, GL_STATIC_DRAW);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vboLength, verticesPtr, GL_STATIC_DRAW);
}
void Mesh::createVertexAttrib(GLuint offset, GLuint size, GLenum type, GLsizei stride, const void *pointer) {
glEnableVertexAttribArray(offset);
if (type == GL_INT)
glVertexAttribIPointer(offset, size, type, stride, pointer);
else
glVertexAttribPointer(offset, size, type, GL_FALSE, stride, pointer);
void Mesh::createVertexAttrib(GLuint offset, GLuint size, GLenum type, GLsizei stride, const void* pointer) {
glEnableVertexAttribArray(offset);
if (type == GL_INT)
glVertexAttribIPointer(offset, size, type, stride, pointer);
else
glVertexAttribPointer(offset, size, type, GL_FALSE, stride, pointer);
}
void Mesh::draw() const {
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glDrawElements(GL_TRIANGLES, indCount, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glDrawElements(GL_TRIANGLES, indCount, GL_UNSIGNED_INT, nullptr);
}
Mesh::~Mesh() {
cleanup();
cleanup();
}

View File

@ -7,19 +7,22 @@
#include <GL/glew.h>
class Mesh {
public:
Mesh() = default;
void cleanup();
virtual void draw() const;
~Mesh();
protected:
void genArrays(GLuint vboLength, GLuint iboLength, const void* verticesPtr, const void* indicesPtr);
void createVertexAttrib(GLuint offset, GLuint size, GLenum type, GLsizei stride, const void* pointer);
GLuint VAO = 0;
GLuint VBO = 0;
GLuint IBO = 0;
GLsizei indCount = 0;
public:
Mesh() = default;
void cleanup();
virtual void draw() const;
~Mesh();
protected:
void genArrays(GLuint vboLength, GLuint iboLength, const void* verticesPtr, const void* indicesPtr);
void createVertexAttrib(GLuint offset, GLuint size, GLenum type, GLsizei stride, const void* pointer);
GLuint VAO = 0;
GLuint VBO = 0;
GLuint IBO = 0;
GLsizei indCount = 0;
};

View File

@ -10,26 +10,26 @@
#include "client/graph/Renderer.h"
#include "client/graph/mesh/ChunkMesh.h"
void MeshChunk::create(std::vector<ChunkVertex> &vertices, std::vector<unsigned int> &indices) {
this->mesh = std::make_shared<ChunkMesh>();
mesh->create(vertices, indices);
void MeshChunk::create(std::vector<ChunkVertex>& vertices, std::vector<unsigned int>& indices) {
this->mesh = std::make_shared<ChunkMesh>();
mesh->create(vertices, indices);
}
void MeshChunk::draw(Renderer& renderer) {
glm::mat4 model = glm::mat4(1.0);
model = glm::translate(model, pos * static_cast<float>(16));
renderer.setModelMatrix(model);
mesh->draw();
glm::mat4 model = glm::mat4(1.0);
model = glm::translate(model, pos * static_cast<float>(16));
renderer.setModelMatrix(model);
mesh->draw();
}
void MeshChunk::setPos(glm::vec3 pos) {
this->pos = pos;
this->pos = pos;
}
glm::vec3 MeshChunk::getPos() {
return pos;
return pos;
}
bool MeshChunk::updateChunkUse(glm::vec3 pos, bool used) {
return used;
return used;
}

View File

@ -11,19 +11,24 @@
#include "client/graph/Drawable.h"
class ChunkMesh;
class ChunkVertex;
class MeshChunk : public ChunkRenderElem, Drawable {
public:
MeshChunk() = default;
void create(std::vector<ChunkVertex> &vertices, std::vector<unsigned int> &indices);
void draw(Renderer& renderer) override;
bool updateChunkUse(glm::vec3 chunk, bool used) override;
void setPos(glm::vec3 pos);
glm::vec3 getPos() override;
private:
std::shared_ptr<ChunkMesh> mesh = nullptr;
glm::vec3 pos {};
public:
MeshChunk() = default;
void create(std::vector<ChunkVertex>& vertices, std::vector<unsigned int>& indices);
void draw(Renderer& renderer) override;
bool updateChunkUse(glm::vec3 chunk, bool used) override;
void setPos(glm::vec3 pos);
glm::vec3 getPos() override;
private:
std::shared_ptr<ChunkMesh> mesh = nullptr;
glm::vec3 pos{};
};

View File

@ -5,32 +5,34 @@
#include "BlurShader.h"
BlurShader::BlurShader(glm::ivec2 windowSize, float bufferScale) : Shader(),
windowSize(windowSize),
bufferScale(bufferScale) {}
windowSize(windowSize),
bufferScale(bufferScale) {}
void BlurShader::postCreate() {
uniforms.sampleScale = get("sampleScale");
use();
set(uniforms.sampleScale, 1.f);
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glGenTextures(1, &colorBuffer);
glBindTexture(GL_TEXTURE_2D, colorBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, static_cast<int>(windowSize.x * bufferScale), static_cast<int>(windowSize.y * bufferScale), 0, GL_RGB, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
uniforms.sampleScale = get("sampleScale");
use();
set(uniforms.sampleScale, 1.f);
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glGenTextures(1, &colorBuffer);
glBindTexture(GL_TEXTURE_2D, colorBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, static_cast<int>(windowSize.x * bufferScale),
static_cast<int>(windowSize.y * bufferScale), 0, GL_RGB, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void BlurShader::windowResized(glm::ivec2 windowSize) {
this->windowSize = windowSize;
glBindTexture(GL_TEXTURE_2D, colorBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, static_cast<int>(windowSize.x * bufferScale), static_cast<int>(windowSize.y * bufferScale), 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer, 0);
glBindTexture(GL_TEXTURE_2D, 0);
this->windowSize = windowSize;
glBindTexture(GL_TEXTURE_2D, colorBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, static_cast<int>(windowSize.x * bufferScale),
static_cast<int>(windowSize.y * bufferScale), 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer, 0);
glBindTexture(GL_TEXTURE_2D, 0);
}

View File

@ -9,22 +9,23 @@
#include "Shader.h"
class BlurShader : public Shader {
public:
explicit BlurShader(glm::ivec2 windowSize, float bufferScale);
void postCreate() override;
void windowResized(glm::ivec2 windowSize);
struct Uniforms {
GLint sampleScale;
};
Uniforms uniforms {};
unsigned int fbo = 0;
unsigned int colorBuffer = 0;
private:
glm::ivec2 windowSize {};
float bufferScale = 1;
public:
explicit BlurShader(glm::ivec2 windowSize, float bufferScale);
void postCreate() override;
void windowResized(glm::ivec2 windowSize);
struct Uniforms {
GLint sampleScale;
};
Uniforms uniforms{};
unsigned int fbo = 0;
unsigned int colorBuffer = 0;
private:
glm::ivec2 windowSize{};
float bufferScale = 1;
};

View File

@ -5,15 +5,15 @@
#include "EntityGeometryShader.h"
EntityGeometryShader::EntityGeometryShader(glm::ivec2 windowSize, float bufferScale) : Shader(),
windowSize(windowSize),
bufferScale(bufferScale) {}
windowSize(windowSize),
bufferScale(bufferScale) {}
void EntityGeometryShader::postCreate() {
uniforms.proj = get("projection");
uniforms.model = get("model");
uniforms.view = get("view");
uniforms.bones = get("uBones");
uniforms.proj = get("projection");
uniforms.model = get("model");
uniforms.view = get("view");
uniforms.bones = get("uBones");
}

View File

@ -9,21 +9,22 @@
#include "Shader.h"
class EntityGeometryShader : public Shader {
public:
explicit EntityGeometryShader(glm::ivec2 windowSize, float bufferScale);
void postCreate() override;
struct Uniforms {
GLint proj;
GLint model;
GLint view;
GLint bones;
};
Uniforms uniforms {};
private:
glm::ivec2 windowSize {};
float bufferScale = 1;
public:
explicit EntityGeometryShader(glm::ivec2 windowSize, float bufferScale);
void postCreate() override;
struct Uniforms {
GLint proj;
GLint model;
GLint view;
GLint bones;
};
Uniforms uniforms{};
private:
glm::ivec2 windowSize{};
float bufferScale = 1;
};

View File

@ -8,11 +8,11 @@
#include <glm/mat4x4.hpp>
struct GuiUniforms {
glm::mat4 matrix;
GLint ortho;
GLint model;
GLint bones;
GLint clipBounds;
glm::mat4 matrix;
GLint ortho;
GLint model;
GLint bones;
GLint clipBounds;
};

View File

@ -7,94 +7,102 @@
#include "LightingShader.h"
LightingShader::LightingShader(glm::ivec2 windowSize, float bufferScale) : Shader(),
windowSize(windowSize),
bufferScale(bufferScale) {}
windowSize(windowSize),
bufferScale(bufferScale) {}
void LightingShader::postCreate() {
uniforms.gPosition = get("gPosition");
uniforms.gNormal = get("gNormal");
uniforms.gColorSpec = get("gColorSpec");
uniforms.ssaoSampler = get("ssaoSampler");
uniforms.camPosition = get("camPosition");
use();
set(uniforms.gPosition, 0);
set(uniforms.gNormal, 1);
set(uniforms.gColorSpec, 2);
set(uniforms.ssaoSampler, 3);
glGenFramebuffers(1, &gBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, gBuffer);
glGenTextures(1, &gPosition);
glBindTexture(GL_TEXTURE_2D, gPosition);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, static_cast<int>(windowSize.x * bufferScale), static_cast<int>(windowSize.y * bufferScale), 0, GL_RGB, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gPosition, 0);
glGenTextures(1, &gNormal);
glBindTexture(GL_TEXTURE_2D, gNormal);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, static_cast<int>(windowSize.x * bufferScale), static_cast<int>(windowSize.y * bufferScale), 0, GL_RGB, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, gNormal, 0);
glGenTextures(1, &gColorSpec);
glBindTexture(GL_TEXTURE_2D, gColorSpec);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast<int>(windowSize.x), static_cast<int>(windowSize.y), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, gColorSpec, 0);
unsigned int attachments[3] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
glDrawBuffers(3, attachments);
glGenRenderbuffers(1, &rDepth);
glBindRenderbuffer(GL_RENDERBUFFER, rDepth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, static_cast<int>(windowSize.x * bufferScale), static_cast<int>(windowSize.y * bufferScale));
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rDepth);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
throw std::runtime_error("Lighting framebuffer incomplete.");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
uniforms.gPosition = get("gPosition");
uniforms.gNormal = get("gNormal");
uniforms.gColorSpec = get("gColorSpec");
uniforms.ssaoSampler = get("ssaoSampler");
uniforms.camPosition = get("camPosition");
use();
set(uniforms.gPosition, 0);
set(uniforms.gNormal, 1);
set(uniforms.gColorSpec, 2);
set(uniforms.ssaoSampler, 3);
glGenFramebuffers(1, &gBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, gBuffer);
glGenTextures(1, &gPosition);
glBindTexture(GL_TEXTURE_2D, gPosition);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, static_cast<int>(windowSize.x * bufferScale),
static_cast<int>(windowSize.y * bufferScale), 0, GL_RGB, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gPosition, 0);
glGenTextures(1, &gNormal);
glBindTexture(GL_TEXTURE_2D, gNormal);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, static_cast<int>(windowSize.x * bufferScale),
static_cast<int>(windowSize.y * bufferScale), 0, GL_RGB, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, gNormal, 0);
glGenTextures(1, &gColorSpec);
glBindTexture(GL_TEXTURE_2D, gColorSpec);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast<int>(windowSize.x), static_cast<int>(windowSize.y), 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, gColorSpec, 0);
unsigned int attachments[3] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
glDrawBuffers(3, attachments);
glGenRenderbuffers(1, &rDepth);
glBindRenderbuffer(GL_RENDERBUFFER, rDepth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, static_cast<int>(windowSize.x * bufferScale),
static_cast<int>(windowSize.y * bufferScale));
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rDepth);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
throw std::runtime_error("Lighting framebuffer incomplete.");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void LightingShader::windowResized(glm::ivec2 windowSize) {
this->windowSize = windowSize;
glBindFramebuffer(GL_FRAMEBUFFER, gBuffer);
glBindTexture(GL_TEXTURE_2D, gPosition);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, static_cast<int>(windowSize.x * bufferScale), static_cast<int>(windowSize.y * bufferScale), 0, GL_RGB, GL_FLOAT, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gPosition, 0);
glBindTexture(GL_TEXTURE_2D, gNormal);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, static_cast<int>(windowSize.x * bufferScale), static_cast<int>(windowSize.y * bufferScale), 0, GL_RGB, GL_FLOAT, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, gNormal, 0);
glBindTexture(GL_TEXTURE_2D, gColorSpec);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast<int>(windowSize.x * bufferScale), static_cast<int>(windowSize.y * bufferScale), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, gColorSpec, 0);
unsigned int attachments[3] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
glDrawBuffers(3, attachments);
glBindRenderbuffer(GL_RENDERBUFFER, rDepth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, static_cast<int>(windowSize.x * bufferScale), static_cast<int>(windowSize.y * bufferScale));
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rDepth);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
throw std::runtime_error("Lighting framebuffer incomplete.");
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
this->windowSize = windowSize;
glBindFramebuffer(GL_FRAMEBUFFER, gBuffer);
glBindTexture(GL_TEXTURE_2D, gPosition);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, static_cast<int>(windowSize.x * bufferScale),
static_cast<int>(windowSize.y * bufferScale), 0, GL_RGB, GL_FLOAT, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gPosition, 0);
glBindTexture(GL_TEXTURE_2D, gNormal);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, static_cast<int>(windowSize.x * bufferScale),
static_cast<int>(windowSize.y * bufferScale), 0, GL_RGB, GL_FLOAT, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, gNormal, 0);
glBindTexture(GL_TEXTURE_2D, gColorSpec);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast<int>(windowSize.x * bufferScale),
static_cast<int>(windowSize.y * bufferScale), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, gColorSpec, 0);
unsigned int attachments[3] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
glDrawBuffers(3, attachments);
glBindRenderbuffer(GL_RENDERBUFFER, rDepth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, static_cast<int>(windowSize.x * bufferScale),
static_cast<int>(windowSize.y * bufferScale));
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rDepth);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
throw std::runtime_error("Lighting framebuffer incomplete.");
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

View File

@ -9,30 +9,31 @@
#include "Shader.h"
class LightingShader : public Shader {
public:
explicit LightingShader(glm::ivec2 windowSize, float bufferScale);
void postCreate() override;
void windowResized(glm::ivec2 windowSize);
struct Uniforms {
GLint gPosition;
GLint gNormal;
GLint gColorSpec;
GLint ssaoSampler;
GLint camPosition;
};
Uniforms uniforms {};
unsigned int gBuffer = 0;
unsigned int gPosition = 0;
unsigned int gNormal = 0;
unsigned int gColorSpec = 0;
unsigned int rDepth = 0;
private:
glm::ivec2 windowSize {};
float bufferScale = 1;
public:
explicit LightingShader(glm::ivec2 windowSize, float bufferScale);
void postCreate() override;
void windowResized(glm::ivec2 windowSize);
struct Uniforms {
GLint gPosition;
GLint gNormal;
GLint gColorSpec;
GLint ssaoSampler;
GLint camPosition;
};
Uniforms uniforms{};
unsigned int gBuffer = 0;
unsigned int gPosition = 0;
unsigned int gNormal = 0;
unsigned int gColorSpec = 0;
unsigned int rDepth = 0;
private:
glm::ivec2 windowSize{};
float bufferScale = 1;
};

View File

@ -7,73 +7,75 @@
#include "SSAOShader.h"
SSAOShader::SSAOShader(glm::ivec2 windowSize, float bufferScale, unsigned int kernelCount) : Shader(),
windowSize(windowSize),
bufferScale(bufferScale),
kernelCount(kernelCount) {}
windowSize(windowSize),
bufferScale(bufferScale),
kernelCount(kernelCount) {}
float lerp(float a, float b, float f) {
return a + f * (b - a);
return a + f * (b - a);
}
void SSAOShader::postCreate() {
uniforms.proj = get("projection");
uniforms.view = get("view");
uniforms.kernelCount = get("kernels");
uniforms.sampleScale = get("sampleScale");
use();
set(uniforms.sampleScale, 2.0f);
std::uniform_real_distribution<float> rand(0.0, 1.0);
std::default_random_engine generator;
for (unsigned int i = 0; i < kernelCount; i++) {
glm::vec3 sample {
rand(generator) * 2.0 - 1.0,
rand(generator) * 2.0 - 1.0,
rand(generator)
};
sample = glm::normalize(sample);
sample *= rand(generator);
float scale = static_cast<float>(i / kernelCount);
scale = lerp(0.1f, 1.0f, scale * scale);
sample *= scale;
kernels.push_back(sample);
}
for (unsigned int i = 0; i < sampleCount; i++) {
noise.emplace_back(rand(generator) * 2.0 - 1.0, rand(generator) * 2.0 - 1.0, 0.0f);
}
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, 4, 4, 0, GL_RGB, GL_FLOAT, &noise[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glBindTexture(GL_TEXTURE_2D, 0);
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glGenTextures(1, &colorBuffer);
glBindTexture(GL_TEXTURE_2D, colorBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, static_cast<int>(windowSize.x * bufferScale), static_cast<int>(windowSize.y * bufferScale), 0, GL_RGB, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
uniforms.proj = get("projection");
uniforms.view = get("view");
uniforms.kernelCount = get("kernels");
uniforms.sampleScale = get("sampleScale");
use();
set(uniforms.sampleScale, 2.0f);
std::uniform_real_distribution<float> rand(0.0, 1.0);
std::default_random_engine generator;
for (unsigned int i = 0; i < kernelCount; i++) {
glm::vec3 sample{
rand(generator) * 2.0 - 1.0,
rand(generator) * 2.0 - 1.0,
rand(generator)
};
sample = glm::normalize(sample);
sample *= rand(generator);
float scale = static_cast<float>(i / kernelCount);
scale = lerp(0.1f, 1.0f, scale * scale);
sample *= scale;
kernels.push_back(sample);
}
for (unsigned int i = 0; i < sampleCount; i++) {
noise.emplace_back(rand(generator) * 2.0 - 1.0, rand(generator) * 2.0 - 1.0, 0.0f);
}
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, 4, 4, 0, GL_RGB, GL_FLOAT, &noise[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glBindTexture(GL_TEXTURE_2D, 0);
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glGenTextures(1, &colorBuffer);
glBindTexture(GL_TEXTURE_2D, colorBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, static_cast<int>(windowSize.x * bufferScale),
static_cast<int>(windowSize.y * bufferScale), 0, GL_RGB, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void SSAOShader::windowResized(glm::ivec2 windowSize) {
this->windowSize = windowSize;
glBindTexture(GL_TEXTURE_2D, colorBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, static_cast<int>(windowSize.x * bufferScale), static_cast<int>(windowSize.y * bufferScale), 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer, 0);
glBindTexture(GL_TEXTURE_2D, 0);
this->windowSize = windowSize;
glBindTexture(GL_TEXTURE_2D, colorBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, static_cast<int>(windowSize.x * bufferScale),
static_cast<int>(windowSize.y * bufferScale), 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer, 0);
glBindTexture(GL_TEXTURE_2D, 0);
}

View File

@ -10,32 +10,33 @@
#include "Shader.h"
class SSAOShader : public Shader {
public:
explicit SSAOShader(glm::ivec2 windowSize, float bufferScale, unsigned int kernelCount);
void postCreate() override;
void windowResized(glm::ivec2 windowSize);
struct Uniforms {
GLint proj;
GLint view;
GLint kernelCount;
GLint sampleScale;
};
Uniforms uniforms {};
unsigned int kernelCount = 32;
unsigned int sampleCount = 16;
std::vector<glm::vec3> kernels {};
std::vector<glm::vec3> noise {};
unsigned int tex = 0;
unsigned int fbo = 0;
unsigned int colorBuffer = 0;
private:
glm::ivec2 windowSize {};
float bufferScale = 1;
public:
explicit SSAOShader(glm::ivec2 windowSize, float bufferScale, unsigned int kernelCount);
void postCreate() override;
void windowResized(glm::ivec2 windowSize);
struct Uniforms {
GLint proj;
GLint view;
GLint kernelCount;
GLint sampleScale;
};
Uniforms uniforms{};
unsigned int kernelCount = 32;
unsigned int sampleCount = 16;
std::vector<glm::vec3> kernels{};
std::vector<glm::vec3> noise{};
unsigned int tex = 0;
unsigned int fbo = 0;
unsigned int colorBuffer = 0;
private:
glm::ivec2 windowSize{};
float bufferScale = 1;
};

View File

@ -11,140 +11,143 @@
#include "../../../util/Log.h"
void Shader::createFromString(std::string& vertexSource, std::string& fragmentSource, const std::string& geoSource) {
compileShader(vertexSource, fragmentSource);
compileShader(vertexSource, fragmentSource);
}
void Shader::createFromFile(const std::string& vertexFile, const std::string& fragmentFile, const std::string& geoFile) {
compileShader(readFile(vertexFile), readFile(fragmentFile),
geoFile == "" ? "" : readFile(geoFile));
postCreate();
void
Shader::createFromFile(const std::string& vertexFile, const std::string& fragmentFile, const std::string& geoFile) {
compileShader(readFile(vertexFile), readFile(fragmentFile),
geoFile == "" ? "" : readFile(geoFile));
postCreate();
}
std::string Shader::readFile(const std::string& fileLocation) {
std::string contents;
std::ifstream fileStream(fileLocation, std::ios::in);
if (!fileStream.is_open()) throw std::runtime_error("Failed to open shader file " + fileLocation + ".");
std::string line;
while (!fileStream.eof()) {
std::getline(fileStream, line);
contents.append(line + "\n");
}
fileStream.close();
return contents;
std::string contents;
std::ifstream fileStream(fileLocation, std::ios::in);
if (!fileStream.is_open()) throw std::runtime_error("Failed to open shader file " + fileLocation + ".");
std::string line;
while (!fileStream.eof()) {
std::getline(fileStream, line);
contents.append(line + "\n");
}
fileStream.close();
return contents;
}
void Shader::use() {
glUseProgram(shaderID);
glUseProgram(shaderID);
}
void Shader::clearShader() {
glUseProgram(0);
glUseProgram(0);
}
GLint Shader::get(const std::string &name) {
return glGetUniformLocation(shaderID, name.c_str());
GLint Shader::get(const std::string& name) {
return glGetUniformLocation(shaderID, name.c_str());
}
void Shader::set(int loc, unsigned int val) {
checkActive();
glUniform1ui(loc, val);
checkActive();
glUniform1ui(loc, val);
}
void Shader::set(int loc, int val) {
checkActive();
glUniform1i(loc, val);
checkActive();
glUniform1i(loc, val);
}
void Shader::set(int loc, float val) {
checkActive();
glUniform1f(loc, val);
checkActive();
glUniform1f(loc, val);
}
void Shader::set(int loc, glm::vec3 val) {
checkActive();
glUniform3f(loc, val.x, val.y, val.z);
checkActive();
glUniform3f(loc, val.x, val.y, val.z);
}
void Shader::set(int loc, glm::vec4 val) {
checkActive();
glUniform4f(loc, val.x, val.y, val.z, val.w);
checkActive();
glUniform4f(loc, val.x, val.y, val.z, val.w);
}
void Shader::set(int loc, glm::mat4 val) {
checkActive();
glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(val));
checkActive();
glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(val));
}
void Shader::setArr(int loc, unsigned int count, glm::mat4 &start) {
checkActive();
glUniformMatrix4fv(loc, count, GL_FALSE, glm::value_ptr(start));
void Shader::setArr(int loc, unsigned int count, glm::mat4& start) {
checkActive();
glUniformMatrix4fv(loc, count, GL_FALSE, glm::value_ptr(start));
}
void Shader::compileShader(const std::string& vertexSource, const std::string& fragmentSource, const std::string& geoSource) {
shaderID = glCreateProgram();
if (!shaderID) throw std::runtime_error("Failed to create shader program.");
addShader(shaderID, vertexSource, GL_VERTEX_SHADER);
addShader(shaderID, fragmentSource, GL_FRAGMENT_SHADER);
if (geoSource != "") addShader(shaderID, geoSource, GL_GEOMETRY_SHADER);
GLint result = 0;
GLchar eLog[1024] = { 0 };
glLinkProgram(shaderID);
glGetProgramiv(shaderID, GL_LINK_STATUS, &result);
if (!result) {
glGetProgramInfoLog(shaderID, sizeof(eLog), nullptr, eLog);
throw std::runtime_error("Failed to link shader program. Error:\n" + std::string(eLog));
}
glValidateProgram(shaderID);
glGetProgramiv(shaderID, GL_VALIDATE_STATUS, &result);
if (!result) {
glGetProgramInfoLog(shaderID, sizeof(eLog), nullptr, eLog);
throw std::runtime_error("Failed to validate shader program. Error:\n" + std::string(eLog));
}
void Shader::compileShader(const std::string& vertexSource, const std::string& fragmentSource,
const std::string& geoSource) {
shaderID = glCreateProgram();
if (!shaderID) throw std::runtime_error("Failed to create shader program.");
addShader(shaderID, vertexSource, GL_VERTEX_SHADER);
addShader(shaderID, fragmentSource, GL_FRAGMENT_SHADER);
if (geoSource != "") addShader(shaderID, geoSource, GL_GEOMETRY_SHADER);
GLint result = 0;
GLchar eLog[1024] = { 0 };
glLinkProgram(shaderID);
glGetProgramiv(shaderID, GL_LINK_STATUS, &result);
if (!result) {
glGetProgramInfoLog(shaderID, sizeof(eLog), nullptr, eLog);
throw std::runtime_error("Failed to link shader program. Error:\n" + std::string(eLog));
}
glValidateProgram(shaderID);
glGetProgramiv(shaderID, GL_VALIDATE_STATUS, &result);
if (!result) {
glGetProgramInfoLog(shaderID, sizeof(eLog), nullptr, eLog);
throw std::runtime_error("Failed to validate shader program. Error:\n" + std::string(eLog));
}
}
void Shader::addShader(GLuint program, const std::string& shaderCode, GLenum shaderType) {
GLuint shader = glCreateShader(shaderType);
const GLchar* shaderCodeCStr = shaderCode.data();
int shaderLength = static_cast<int>(shaderCode.length());
glShaderSource(shader, 1, &shaderCodeCStr, &shaderLength);
glCompileShader(shader);
GLint result = 0;
GLchar eLog[1024] = { 0 };
glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
if (!result) {
glGetShaderInfoLog(shader, sizeof(eLog), nullptr, eLog);
std::string shaderTypeName = (shaderType == GL_VERTEX_SHADER) ? "vertex" : (shaderType == GL_FRAGMENT_SHADER) ? "fragment" : "geometry";
throw std::runtime_error("Failed to compile the " + shaderTypeName + " shader. Error:\n" + eLog);
}
glAttachShader(program, shader);
GLuint shader = glCreateShader(shaderType);
const GLchar* shaderCodeCStr = shaderCode.data();
int shaderLength = static_cast<int>(shaderCode.length());
glShaderSource(shader, 1, &shaderCodeCStr, &shaderLength);
glCompileShader(shader);
GLint result = 0;
GLchar eLog[1024] = { 0 };
glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
if (!result) {
glGetShaderInfoLog(shader, sizeof(eLog), nullptr, eLog);
std::string shaderTypeName = (shaderType == GL_VERTEX_SHADER) ? "vertex" : (shaderType == GL_FRAGMENT_SHADER)
? "fragment" : "geometry";
throw std::runtime_error("Failed to compile the " + shaderTypeName + " shader. Error:\n" + eLog);
}
glAttachShader(program, shader);
}
Shader::~Shader() {
cleanup();
cleanup();
}
void Shader::cleanup() {
if (shaderID != 0) glDeleteProgram(shaderID);
if (shaderID != 0) glDeleteProgram(shaderID);
}
void Shader::checkActive() {
int cProgram;
glGetIntegerv(GL_CURRENT_PROGRAM, &cProgram);
if (cProgram != shaderID) throw std::runtime_error("Attempted to set a uniform on an inactive shader!");
int cProgram;
glGetIntegerv(GL_CURRENT_PROGRAM, &cProgram);
if (cProgram != shaderID) throw std::runtime_error("Attempted to set a uniform on an inactive shader!");
}

View File

@ -10,38 +10,48 @@
#include <glm/mat4x4.hpp>
class Shader {
public:
void createFromString(std::string& vertexSource, std::string& fragmentSource, const std::string& geoSource = "");
void createFromFile(const std::string& vertexFile, const std::string& fragmentFile, const std::string& geoFile = "");
virtual void postCreate() {};
int get(const std::string &name);
void use();
static void clearShader();
void set(int loc, unsigned int val);
void set(int loc, int val);
void set(int loc, float val);
void set(int loc, glm::vec3 val);
void set(int loc, glm::vec4 val);
void set(int loc, glm::mat4 val);
void setArr(int loc, unsigned int count, glm::mat4 &start);
void cleanup();
~Shader();
private:
static std::string readFile(const std::string& fileLocation);
void compileShader(const std::string& vertexSource, const std::string& fragmentSource, const std::string& geoSource = "");
static void addShader(unsigned int program, const std::string& shaderCode, GLenum shaderType);
void checkActive();
unsigned int shaderID = 0;
public:
void createFromString(std::string& vertexSource, std::string& fragmentSource, const std::string& geoSource = "");
void
createFromFile(const std::string& vertexFile, const std::string& fragmentFile, const std::string& geoFile = "");
virtual void postCreate() {};
int get(const std::string& name);
void use();
static void clearShader();
void set(int loc, unsigned int val);
void set(int loc, int val);
void set(int loc, float val);
void set(int loc, glm::vec3 val);
void set(int loc, glm::vec4 val);
void set(int loc, glm::mat4 val);
void setArr(int loc, unsigned int count, glm::mat4& start);
void cleanup();
~Shader();
private:
static std::string readFile(const std::string& fileLocation);
void compileShader(const std::string& vertexSource, const std::string& fragmentSource,
const std::string& geoSource = "");
static void addShader(unsigned int program, const std::string& shaderCode, GLenum shaderType);
void checkActive();
unsigned int shaderID = 0;
};

View File

@ -7,37 +7,42 @@
#include "WorldGeometryShader.h"
WorldGeometryShader::WorldGeometryShader(glm::ivec2 windowSize, float bufferScale) : Shader(),
windowSize(windowSize),
bufferScale(bufferScale),
swayData(16 * 4 * 16) {
swayNoise.SetFrequency(0.20);
swayNoise.SetOctaveCount(2);
windowSize(windowSize),
bufferScale(bufferScale),
swayData(16 * 4 * 16) {
swayNoise.SetFrequency(0.20);
swayNoise.SetOctaveCount(2);
}
void WorldGeometryShader::postCreate() {
swayTex.loadFromBytes(&swayData[0], 16, 16, GL_LINEAR, GL_MIRRORED_REPEAT);
uniforms.proj = get("projection");
uniforms.model = get("model");
uniforms.view = get("view");
uniforms.swaySampler = get("swayTex");
uniforms.time = get("time");
use();
set(uniforms.swaySampler, 1);
swayTex.loadFromBytes(&swayData[0], 16, 16, GL_LINEAR, GL_MIRRORED_REPEAT);
uniforms.proj = get("projection");
uniforms.model = get("model");
uniforms.view = get("view");
uniforms.swaySampler = get("swayTex");
uniforms.time = get("time");
use();
set(uniforms.swaySampler, 1);
}
void WorldGeometryShader::windowResized(glm::ivec2 windowSize) {
this->windowSize = windowSize;
this->windowSize = 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.GetValue((i / 16) / 3.f, (i % 16) / 3.f, swayOffset))) + 1) / 2.f * 255.f);
swayData[i*4+1] = static_cast<unsigned char>((fmax(-1, fmin(1, swayNoise.GetValue((i / 16) / 3.f, (i % 16) / 3.f, swayOffset + 50))) + 1) / 2.f * 255.f);
swayData[i*4+2] = static_cast<unsigned char>((fmax(-1, fmin(1, swayNoise.GetValue((i / 16) / 3.f, (i % 16) / 3.f, swayOffset + 100))) + 1) / 2.f * 255.f);
}
swayTex.updateTexture(0, 0, 16, 16, &swayData[0]);
swayOffset += delta * 2.8;
for (int i = 0; i < 16 * 16; i++) {
swayData[i * 4] = static_cast<unsigned char>(
(fmax(-1, fmin(1, swayNoise.GetValue((i / 16) / 3.f, (i % 16) / 3.f, swayOffset))) + 1) / 2.f * 255.f);
swayData[i * 4 + 1] = static_cast<unsigned char>(
(fmax(-1, fmin(1, swayNoise.GetValue((i / 16) / 3.f, (i % 16) / 3.f, swayOffset + 50))) + 1) / 2.f * 255.f);
swayData[i * 4 + 2] = static_cast<unsigned char>(
(fmax(-1, fmin(1, swayNoise.GetValue((i / 16) / 3.f, (i % 16) / 3.f, swayOffset + 100))) + 1) / 2.f *
255.f);
}
swayTex.updateTexture(0, 0, 16, 16, &swayData[0]);
}

View File

@ -12,30 +12,32 @@
#include "../Texture.h"
class WorldGeometryShader : public Shader {
public:
explicit WorldGeometryShader(glm::ivec2 windowSize, float bufferScale);
void postCreate() override;
void windowResized(glm::ivec2 windowSize);
void updateSwayMap(double delta);
struct Uniforms {
GLint proj;
GLint model;
GLint view;
GLint swaySampler;
GLint time;
};
Uniforms uniforms {};
Texture swayTex;
double swayOffset = 0;
noise::module::Perlin swayNoise;
std::vector<unsigned char> swayData {};
glm::ivec2 windowSize {};
float bufferScale = 1;
public:
explicit WorldGeometryShader(glm::ivec2 windowSize, float bufferScale);
void postCreate() override;
void windowResized(glm::ivec2 windowSize);
void updateSwayMap(double delta);
struct Uniforms {
GLint proj;
GLint model;
GLint view;
GLint swaySampler;
GLint time;
};
Uniforms uniforms{};
Texture swayTex;
double swayOffset = 0;
noise::module::Perlin swayNoise;
std::vector<unsigned char> swayData{};
glm::ivec2 windowSize{};
float bufferScale = 1;
};

View File

@ -13,164 +13,171 @@
#include "client/gui/compound/GuiLabelledGraph.h"
DebugGui::DebugGui(glm::vec2 bufferSize, SubgamePtr game, WorldPtr world) :
game(game),
world(world) {
auto fontRef = game.l()->textures["font"];
auto fpsHistogramRef = game.l()->textures["histogram"];
auto genericHistogramRef = game.l()->textures["histogram_white"];
Font f(game.l()->textures, fontRef);
auto crosshairText = std::make_shared<GuiText>("crosshairText");
crosshairText->create({2, 2}, {}, {0.2, 0.2, 0.2, 0.5}, {1, 1, 1, 1}, f);
add(crosshairText);
auto dataText = std::make_shared<GuiText>("dataText");
dataText->create({2, 2}, {}, {0.2, 0.2, 0.2, 0.5}, {1, 1, 1, 1}, f);
add(dataText);
auto interpGraph = std::make_shared<GuiLabelledGraph>("interpGraph");
interpGraph->create({244, 64}, {}, "Interp", 120, 256, genericHistogramRef, f);
add(interpGraph);
auto meshGraph = std::make_shared<GuiLabelledGraph>("meshGraph");
meshGraph->create({244, 64}, {}, "Mesh", 120, 32, genericHistogramRef, f);
add(meshGraph);
auto genGraph = std::make_shared<GuiLabelledGraph>("genGraph");
genGraph->create({244, 64}, {}, "Gen", 120, 16, genericHistogramRef, f);
add(genGraph);
auto packetGraph = std::make_shared<GuiLabelledGraph>("packetGraph");
packetGraph->create({244, 64}, {}, "Packets", 120, 32, genericHistogramRef, f);
add(packetGraph);
auto fpsGraph = std::make_shared<GuiLabelledGraph>("fpsGraph");
fpsGraph->create({244, 64}, {}, "FPS", 120, 60, fpsHistogramRef, f);
add(fpsGraph);
auto drawsGraph = std::make_shared<GuiLabelledGraph>("drawsGraph");
drawsGraph->create({244, 64}, {}, "Draw Calls", 120, 0, genericHistogramRef, f);
add(drawsGraph);
auto gpuGraph = std::make_shared<GuiLabelledGraph>("gpuGraph");
gpuGraph->create({244, 64}, {}, "GPU", 120, 1, genericHistogramRef, f);
add(gpuGraph);
positionElements(bufferSize);
game(game),
world(world) {
auto fontRef = game.l()->textures["font"];
auto fpsHistogramRef = game.l()->textures["histogram"];
auto genericHistogramRef = game.l()->textures["histogram_white"];
Font f(game.l()->textures, fontRef);
auto crosshairText = std::make_shared<GuiText>("crosshairText");
crosshairText->create({ 2, 2 }, {}, { 0.2, 0.2, 0.2, 0.5 }, { 1, 1, 1, 1 }, f);
add(crosshairText);
auto dataText = std::make_shared<GuiText>("dataText");
dataText->create({ 2, 2 }, {}, { 0.2, 0.2, 0.2, 0.5 }, { 1, 1, 1, 1 }, f);
add(dataText);
auto interpGraph = std::make_shared<GuiLabelledGraph>("interpGraph");
interpGraph->create({ 244, 64 }, {}, "Interp", 120, 256, genericHistogramRef, f);
add(interpGraph);
auto meshGraph = std::make_shared<GuiLabelledGraph>("meshGraph");
meshGraph->create({ 244, 64 }, {}, "Mesh", 120, 32, genericHistogramRef, f);
add(meshGraph);
auto genGraph = std::make_shared<GuiLabelledGraph>("genGraph");
genGraph->create({ 244, 64 }, {}, "Gen", 120, 16, genericHistogramRef, f);
add(genGraph);
auto packetGraph = std::make_shared<GuiLabelledGraph>("packetGraph");
packetGraph->create({ 244, 64 }, {}, "Packets", 120, 32, genericHistogramRef, f);
add(packetGraph);
auto fpsGraph = std::make_shared<GuiLabelledGraph>("fpsGraph");
fpsGraph->create({ 244, 64 }, {}, "FPS", 120, 60, fpsHistogramRef, f);
add(fpsGraph);
auto drawsGraph = std::make_shared<GuiLabelledGraph>("drawsGraph");
drawsGraph->create({ 244, 64 }, {}, "Draw Calls", 120, 0, genericHistogramRef, f);
add(drawsGraph);
auto gpuGraph = std::make_shared<GuiLabelledGraph>("gpuGraph");
gpuGraph->create({ 244, 64 }, {}, "GPU", 120, 1, genericHistogramRef, f);
add(gpuGraph);
positionElements(bufferSize);
}
void DebugGui::positionElements(glm::vec2 bufferSize) {
auto bufferWidth = static_cast<int>(bufferSize.x);
auto bufferHeight = static_cast<int>(bufferSize.y);
get<GuiText>("crosshairText")->setPos({bufferWidth / 2 + 22, bufferHeight / 2 - 7});
get<GuiText>("dataText")->setPos({10, 10});
get<GuiLabelledGraph>("genGraph")->setPos({bufferWidth - 254, bufferHeight - 70 - 160});
get<GuiLabelledGraph>("packetGraph")->setPos({bufferWidth - 254, bufferHeight - 70 - 240});
get<GuiLabelledGraph>("meshGraph")->setPos({bufferWidth - 254, bufferHeight - 70 - 80});
get<GuiLabelledGraph>("interpGraph")->setPos({bufferWidth - 254, bufferHeight - 70});
get<GuiLabelledGraph>("fpsGraph")->setPos({bufferWidth - 254, 10});
get<GuiLabelledGraph>("drawsGraph")->setPos({bufferWidth - 254, 90});
get<GuiLabelledGraph>("gpuGraph")->setPos({bufferWidth - 254, 90 + 80});
auto bufferWidth = static_cast<int>(bufferSize.x);
auto bufferHeight = static_cast<int>(bufferSize.y);
get<GuiText>("crosshairText")->setPos({ bufferWidth / 2 + 22, bufferHeight / 2 - 7 });
get<GuiText>("dataText")->setPos({ 10, 10 });
get<GuiLabelledGraph>("genGraph")->setPos({ bufferWidth - 254, bufferHeight - 70 - 160 });
get<GuiLabelledGraph>("packetGraph")->setPos({ bufferWidth - 254, bufferHeight - 70 - 240 });
get<GuiLabelledGraph>("meshGraph")->setPos({ bufferWidth - 254, bufferHeight - 70 - 80 });
get<GuiLabelledGraph>("interpGraph")->setPos({ bufferWidth - 254, bufferHeight - 70 });
get<GuiLabelledGraph>("fpsGraph")->setPos({ bufferWidth - 254, 10 });
get<GuiLabelledGraph>("drawsGraph")->setPos({ bufferWidth - 254, 90 });
get<GuiLabelledGraph>("gpuGraph")->setPos({ bufferWidth - 254, 90 + 80 });
}
void DebugGui::update(std::shared_ptr<LocalPlayer> player, double fps, int /*chunks*/, int drawCalls, int ssGen, int ssPack) {
Target target = player->getTarget();
auto& onBiomeDef = game->getBiomes().biomeFromId(world.l()->getActiveDimension()->getBiome(glm::floor(player->getPos())));
auto& targetedBlockDef = game->getDefs().blockFromId(world.l()->getActiveDimension()->getBlock(target.pos));
/* Top-right Graphs */ {
get<GuiLabelledGraph>("fpsGraph")->pushValue(static_cast<float>(fps));
get<GuiLabelledGraph>("drawsGraph")->pushValue(drawCalls);
int videoMemAvail, videoMemTotal;
glGetIntegerv(0x9048, &videoMemTotal);
glGetIntegerv(0x9049, &videoMemAvail);
get<GuiLabelledGraph>("gpuGraph")->pushValue(static_cast<int>(std::round(
(videoMemTotal - videoMemAvail) / static_cast<float>(videoMemTotal) * 100.0)) / 100.0f);
}
/* Bottom-right Graphs */ {
get<GuiLabelledGraph>("meshGraph")->pushValue(world.l()->lastMeshUpdates);
get<GuiLabelledGraph>("interpGraph")->pushValue(world.l()->mapBlocksInterpolated);
get<GuiLabelledGraph>("genGraph")->pushValue(static_cast<float>(ssGen));
get<GuiLabelledGraph>("packetGraph")->pushValue(static_cast<float>(ssPack));
}
/* Top-left Data */ {
glm::vec3 playerPos = glm::floor(player->getPos());
glm::vec3 chunkPos = Space::Chunk::world::fromBlock(playerPos);
glm::vec3 mapBlockPos = Space::MapBlock::world::fromChunk(chunkPos);
glm::vec3 regionPos = Space::Region::world::fromChunk(chunkPos);
glm::vec3 posOffsetFromChunk = Space::Block::relative::toChunk(playerPos);
glm::vec3 posOffsetFromBlock = Space::Block::relative::toMapBlock(playerPos);
glm::vec3 posOffsetFromRegion = Space::Block::relative::toRegion(playerPos);
std::ostringstream str;
using namespace Util;
str << "Dimension: " << world.l()->getActiveDimension()->getIdentifier()
<< " [" << world.l()->getActiveDimension()->getInd() << "]" << std::endl << std::endl;
str << "Pos: " << vecToString(playerPos) << " (" << floatVecToString(player->getPos()) << ")" << std::endl;
str << "Vel: " << floatVecToString(player->getVel()) << std::endl;
str << "Yaw: " << floatToString(player->getYaw()) << ", ";
str << "Pitch: " << floatToString(player->getPitch()) << std::endl << std::endl;
str << "C: " << vecToString(posOffsetFromChunk) << " [" << vecToString(chunkPos) << "]" << std::endl;
str << "M: " << vecToString(posOffsetFromBlock) << " [" << vecToString(mapBlockPos) << "]" << std::endl;
str << "R: " << vecToString(posOffsetFromRegion) << " [" << vecToString(regionPos) << "]" << std::endl << std::endl;
str << "Texture Slots: " << game.l()->textures.textureSlotsUsed << " / " << game.l()->textures.maxTextureSlots
<< " (" << round(game.l()->textures.textureSlotsUsed / static_cast<float>(game.l()->textures.maxTextureSlots) * 100) << "%)" << std::endl << std::endl;
str << "Biome: " << onBiomeDef.identifier << " [" << onBiomeDef.index << "]" << std::endl << std::endl;
if (target.type == Target::Type::BLOCK) {
std::string face =
target.face == EVec::TOP ? "TOP" :
target.face == EVec::BOTTOM ? "BOTTOM" :
target.face == EVec::LEFT ? "LEFT" :
target.face == EVec::RIGHT ? "RIGHT" :
target.face == EVec::FRONT ? "FRONT" :
target.face == EVec::BACK ? "BACK" :
"NONE" ;
str << "Pointing At: " << targetedBlockDef.identifier << " [" << targetedBlockDef.index << "]" << std::endl;
str << "Pointed Position: " << vecToString(target.pos) << std::endl;
str << "Pointed Face: " << face << std::endl;
}
else {
str << "No Target";
}
get<GuiText>("dataText")->setText(str.str());
}
/* Crosshair Text */ {
if (target.type == Target::Type::BLOCK) get<GuiText>("crosshairText")->setText(targetedBlockDef.name + " (" +
targetedBlockDef.identifier + ") [" + std::to_string(targetedBlockDef.index) + "]");
else get<GuiText>("crosshairText")->setText("");
}
void DebugGui::update(std::shared_ptr<LocalPlayer> player, double fps, int /*chunks*/, int drawCalls, int ssGen,
int ssPack) {
Target target = player->getTarget();
auto& onBiomeDef = game->getBiomes().biomeFromId(
world.l()->getActiveDimension()->getBiome(glm::floor(player->getPos())));
auto& targetedBlockDef = game->getDefs().blockFromId(world.l()->getActiveDimension()->getBlock(target.pos));
/* Top-right Graphs */ {
get<GuiLabelledGraph>("fpsGraph")->pushValue(static_cast<float>(fps));
get<GuiLabelledGraph>("drawsGraph")->pushValue(drawCalls);
int videoMemAvail, videoMemTotal;
glGetIntegerv(0x9048, &videoMemTotal);
glGetIntegerv(0x9049, &videoMemAvail);
get<GuiLabelledGraph>("gpuGraph")->pushValue(static_cast<int>(std::round(
(videoMemTotal - videoMemAvail) / static_cast<float>(videoMemTotal) * 100.0)) / 100.0f);
}
/* Bottom-right Graphs */ {
get<GuiLabelledGraph>("meshGraph")->pushValue(world.l()->lastMeshUpdates);
get<GuiLabelledGraph>("interpGraph")->pushValue(world.l()->mapBlocksInterpolated);
get<GuiLabelledGraph>("genGraph")->pushValue(static_cast<float>(ssGen));
get<GuiLabelledGraph>("packetGraph")->pushValue(static_cast<float>(ssPack));
}
/* Top-left Data */ {
glm::vec3 playerPos = glm::floor(player->getPos());
glm::vec3 chunkPos = Space::Chunk::world::fromBlock(playerPos);
glm::vec3 mapBlockPos = Space::MapBlock::world::fromChunk(chunkPos);
glm::vec3 regionPos = Space::Region::world::fromChunk(chunkPos);
glm::vec3 posOffsetFromChunk = Space::Block::relative::toChunk(playerPos);
glm::vec3 posOffsetFromBlock = Space::Block::relative::toMapBlock(playerPos);
glm::vec3 posOffsetFromRegion = Space::Block::relative::toRegion(playerPos);
std::ostringstream str;
using namespace Util;
str << "Dimension: " << world.l()->getActiveDimension()->getIdentifier()
<< " [" << world.l()->getActiveDimension()->getInd() << "]" << std::endl << std::endl;
str << "Pos: " << vecToString(playerPos) << " (" << floatVecToString(player->getPos()) << ")" << std::endl;
str << "Vel: " << floatVecToString(player->getVel()) << std::endl;
str << "Yaw: " << floatToString(player->getYaw()) << ", ";
str << "Pitch: " << floatToString(player->getPitch()) << std::endl << std::endl;
str << "C: " << vecToString(posOffsetFromChunk) << " [" << vecToString(chunkPos) << "]" << std::endl;
str << "M: " << vecToString(posOffsetFromBlock) << " [" << vecToString(mapBlockPos) << "]" << std::endl;
str << "R: " << vecToString(posOffsetFromRegion) << " [" << vecToString(regionPos) << "]" << std::endl
<< std::endl;
str << "Texture Slots: " << game.l()->textures.textureSlotsUsed << " / " << game.l()->textures.maxTextureSlots
<< " ("
<< round(game.l()->textures.textureSlotsUsed / static_cast<float>(game.l()->textures.maxTextureSlots) * 100)
<< "%)" << std::endl << std::endl;
str << "Biome: " << onBiomeDef.identifier << " [" << onBiomeDef.index << "]" << std::endl << std::endl;
if (target.type == Target::Type::BLOCK) {
std::string face =
target.face == EVec::TOP ? "TOP" :
target.face == EVec::BOTTOM ? "BOTTOM" :
target.face == EVec::LEFT ? "LEFT" :
target.face == EVec::RIGHT ? "RIGHT" :
target.face == EVec::FRONT ? "FRONT" :
target.face == EVec::BACK ? "BACK" :
"NONE";
str << "Pointing At: " << targetedBlockDef.identifier << " [" << targetedBlockDef.index << "]" << std::endl;
str << "Pointed Position: " << vecToString(target.pos) << std::endl;
str << "Pointed Face: " << face << std::endl;
}
else {
str << "No Target";
}
get<GuiText>("dataText")->setText(str.str());
}
/* Crosshair Text */ {
if (target.type == Target::Type::BLOCK)
get<GuiText>("crosshairText")->setText(targetedBlockDef.name + " (" +
targetedBlockDef.identifier + ") [" +
std::to_string(targetedBlockDef.index) + "]");
else get<GuiText>("crosshairText")->setText("");
}
}
void DebugGui::bufferResized(glm::vec2 bufferSize) {
positionElements(bufferSize);
positionElements(bufferSize);
}
// 0 = All, 1 = None, 2 = FPS
void DebugGui::changeVisibilityState(int state) {
displayMode = state;
setVisible(displayMode == 0);
get<GuiLabelledGraph>("fpsGraph")->setVisible(displayMode != 1);
displayMode = state;
setVisible(displayMode == 0);
get<GuiLabelledGraph>("fpsGraph")->setVisible(displayMode != 1);
}

View File

@ -9,21 +9,26 @@
#include "util/CovariantPtr.h"
class LocalPlayer;
class LocalSubgame;
class LocalWorld;
class DebugGui : public GuiContainer {
public:
DebugGui(glm::vec2 bufferSize, SubgamePtr game, WorldPtr world);
void bufferResized(glm::vec2 bufferSize);
void changeVisibilityState(int state);
void positionElements(glm::vec2 bufferSize);
void update(std::shared_ptr<LocalPlayer> player, double fps, int chunks, int drawCalls, int ssGen, int ssPack);
private:
int displayMode;
WorldPtr world;
SubgamePtr game;
public:
DebugGui(glm::vec2 bufferSize, SubgamePtr game, WorldPtr world);
void bufferResized(glm::vec2 bufferSize);
void changeVisibilityState(int state);
void positionElements(glm::vec2 bufferSize);
void update(std::shared_ptr<LocalPlayer> player, double fps, int chunks, int drawCalls, int ssGen, int ssPack);
private:
int displayMode;
WorldPtr world;
SubgamePtr game;
};

View File

@ -7,76 +7,76 @@
#include "../graph/Renderer.h"
GameGui::GameGui(InventoryRefsPtr refs, glm::vec2 bufferSize, SubgamePtr defs, Renderer& renderer) :
refs(refs),
defs(defs),
win(bufferSize),
renderer(renderer),
hudBuilder(refs, defs, hudLuaRoot),
menuBuilder(refs, defs, menuLuaRoot) {
hudRoot->add(hudLuaRoot);
menuRoot->add(menuLuaRoot);
handList->create({3, 3}, {}, {}, refs.l()->getCursorList(), refs.l()->getCursorList(), defs);
menuRoot->add(handList);
refs(refs),
defs(defs),
win(bufferSize),
renderer(renderer),
hudBuilder(refs, defs, hudLuaRoot),
menuBuilder(refs, defs, menuLuaRoot) {
hudRoot->add(hudLuaRoot);
menuRoot->add(menuLuaRoot);
handList->create({ 3, 3 }, {}, {}, refs.l()->getCursorList(), refs.l()->getCursorList(), defs);
menuRoot->add(handList);
}
void GameGui::update(double delta) {
menuRoot->update(delta);
hudRoot->update(delta);
hudBuilder.update();
menuBuilder.update();
handList->setPos((renderer.window.input.mousePos() - glm::ivec2(24)) / 3 * 3);
menuRoot->handleMouseInput(renderer.window);
menuRoot->update(delta);
hudRoot->update(delta);
hudBuilder.update();
menuBuilder.update();
handList->setPos((renderer.window.input.mousePos() - glm::ivec2(24)) / 3 * 3);
menuRoot->handleMouseInput(renderer.window);
}
void GameGui::winResized(glm::ivec2 win) {
this->win = win;
menuBuilder.build(win);
hudBuilder.build(win);
this->win = win;
menuBuilder.build(win);
hudBuilder.build(win);
}
void GameGui::showMenu(std::shared_ptr<LuaGuiElement> root) {
menuBuilder.setGuiRoot(root);
menuBuilder.build(win);
inMenu = true;
menuBuilder.setGuiRoot(root);
menuBuilder.build(win);
inMenu = true;
}
void GameGui::closeMenu() {
menuBuilder.clear();
inMenu = false;
menuBuilder.clear();
inMenu = false;
}
const bool GameGui::isInMenu() const {
return inMenu;
return inMenu;
}
void GameGui::setHud(std::shared_ptr<LuaGuiElement> hud) {
this->hudRootElem = hud;
hudBuilder.setGuiRoot(hud);
hudBuilder.build(win);
this->hudRootElem = hud;
hudBuilder.setGuiRoot(hud);
hudBuilder.build(win);
}
std::shared_ptr<LuaGuiElement> GameGui::getHud() {
return hudRootElem;
return hudRootElem;
}
void GameGui::setVisible(bool visible) {
menuRoot->setVisible(visible);
hudRoot->setVisible(visible);
menuRoot->setVisible(visible);
hudRoot->setVisible(visible);
}
bool GameGui::isVisible() {
return menuRoot->isVisible();
return menuRoot->isVisible();
}
void GameGui::drawHud(Renderer &renderer) {
hudRoot->draw(renderer);
void GameGui::drawHud(Renderer& renderer) {
hudRoot->draw(renderer);
}
void GameGui::drawMenu(Renderer &renderer) {
menuRoot->draw(renderer);
void GameGui::drawMenu(Renderer& renderer) {
menuRoot->draw(renderer);
}

View File

@ -8,41 +8,49 @@
#include "client/gui/compound/GuiInventoryList.h"
class GameGui {
public:
explicit GameGui(InventoryRefsPtr refs, glm::vec2 bufferSize, SubgamePtr defs, Renderer& renderer);
void winResized(glm::ivec2 win);
void update(double delta);
void setVisible(bool visible);
bool isVisible();
void showMenu(std::shared_ptr<LuaGuiElement> root);
void closeMenu();
const bool isInMenu() const;
void setHud(std::shared_ptr<LuaGuiElement> hud);
std::shared_ptr<LuaGuiElement> getHud();
void drawHud(Renderer& renderer);
void drawMenu(Renderer& renderer);
private:
SubgamePtr defs;
Renderer& renderer;
glm::ivec2 win {};
bool inMenu = false;
std::shared_ptr<LuaGuiElement> hudRootElem = nullptr;
std::shared_ptr<GuiContainer> menuRoot = std::make_shared<GuiInventoryList>("menuRoot");
std::shared_ptr<GuiContainer> menuLuaRoot = std::make_shared<GuiInventoryList>("menuLuaRoot");
GameGuiBuilder menuBuilder;
std::shared_ptr<GuiContainer> hudRoot = std::make_shared<GuiInventoryList>("hudRoot");
std::shared_ptr<GuiContainer> hudLuaRoot = std::make_shared<GuiInventoryList>("hudLuaRoot");
GameGuiBuilder hudBuilder;
std::shared_ptr<GuiInventoryList> handList = std::make_shared<GuiInventoryList>("hand");
InventoryRefsPtr refs;
public:
explicit GameGui(InventoryRefsPtr refs, glm::vec2 bufferSize, SubgamePtr defs, Renderer& renderer);
void winResized(glm::ivec2 win);
void update(double delta);
void setVisible(bool visible);
bool isVisible();
void showMenu(std::shared_ptr<LuaGuiElement> root);
void closeMenu();
const bool isInMenu() const;
void setHud(std::shared_ptr<LuaGuiElement> hud);
std::shared_ptr<LuaGuiElement> getHud();
void drawHud(Renderer& renderer);
void drawMenu(Renderer& renderer);
private:
SubgamePtr defs;
Renderer& renderer;
glm::ivec2 win{};
bool inMenu = false;
std::shared_ptr<LuaGuiElement> hudRootElem = nullptr;
std::shared_ptr<GuiContainer> menuRoot = std::make_shared<GuiInventoryList>("menuRoot");
std::shared_ptr<GuiContainer> menuLuaRoot = std::make_shared<GuiInventoryList>("menuLuaRoot");
GameGuiBuilder menuBuilder;
std::shared_ptr<GuiContainer> hudRoot = std::make_shared<GuiInventoryList>("hudRoot");
std::shared_ptr<GuiContainer> hudLuaRoot = std::make_shared<GuiInventoryList>("hudLuaRoot");
GameGuiBuilder hudBuilder;
std::shared_ptr<GuiInventoryList> handList = std::make_shared<GuiInventoryList>("hand");
InventoryRefsPtr refs;
};

View File

@ -8,20 +8,20 @@
#include "client/gui/compound/GuiInventoryList.h"
std::shared_ptr<GuiComponent> GameGuiBuilder::createComponent(LuaGuiElement& elem, glm::ivec2 bounds) {
auto c = GuiBuilder::createComponent(elem, bounds);
if (c != nullptr) return c;
switch (Util::hash(elem.type.c_str())) {
default: break;
case Util::hash("InventoryList"): {
c = GuiInventoryList::fromSerialized(elem, defs, bounds, refs);
break;
}
}
if (!c) return nullptr;
elem.updateFunction = std::bind(&GameGuiBuilder::elementUpdated, this);
auto c = GuiBuilder::createComponent(elem, bounds);
if (c != nullptr) return c;
switch (Util::hash(elem.type.c_str())) {
default: break;
case Util::hash("InventoryList"): {
c = GuiInventoryList::fromSerialized(elem, defs, bounds, refs);
break;
}
}
if (!c) return nullptr;
elem.updateFunction = std::bind(&GameGuiBuilder::elementUpdated, this);
// if (elem.callbacks.count("primary")) c->setCallback(GuiComponent::CallbackType::PRIMARY, [=](bool b, glm::vec2 v) {
// elem.callbacks.at("primary")(b, LuaParser::luaVec(elem.callbacks.at("primary").lua_state(), {v.x, v.y, 0})); });
@ -31,6 +31,6 @@ std::shared_ptr<GuiComponent> GameGuiBuilder::createComponent(LuaGuiElement& ele
//
// if (elem.callbacks.count("hover")) c->setCallback(GuiComponent::CallbackType::HOVER, [=](bool b, glm::vec2 v) {
// elem.callbacks.at("hover")(b, LuaParser::luaVec(elem.callbacks.at("hover").lua_state(), {v.x, v.y, 0})); });
return c;
return c;
}

View File

@ -10,12 +10,13 @@
#include "world/inv/LocalInventoryRefs.h"
class GameGuiBuilder : public GuiBuilder {
public:
GameGuiBuilder(InventoryRefsPtr refs, SubgamePtr defs, std::shared_ptr<GuiContainer> root) :
defs(defs), refs(refs), GuiBuilder(defs.l()->textures, defs.l()->models, root) {};
std::shared_ptr<GuiComponent> createComponent(LuaGuiElement& elem, glm::ivec2 bounds) override;
private:
InventoryRefsPtr refs;
SubgamePtr defs;
public:
GameGuiBuilder(InventoryRefsPtr refs, SubgamePtr defs, std::shared_ptr<GuiContainer> root) :
defs(defs), refs(refs), GuiBuilder(defs.l()->textures, defs.l()->models, root) {};
std::shared_ptr<GuiComponent> createComponent(LuaGuiElement& elem, glm::ivec2 bounds) override;
private:
InventoryRefsPtr refs;
SubgamePtr defs;
};

View File

@ -12,68 +12,64 @@
#include "client/gui/compound/GuiImageButton.h"
GuiBuilder::GuiBuilder(TextureAtlas& textures, ModelStore& models, std::shared_ptr<GuiContainer> root) :
textures(textures), models(models), root(root) {}
textures(textures), models(models), root(root) {}
void GuiBuilder::setGuiRoot(std::shared_ptr<LuaGuiElement> menu) {
elements = menu;
elements = menu;
}
void GuiBuilder::update() {
if (dirty) {
build();
dirty = false;
}
if (dirty) {
build();
dirty = false;
}
}
void GuiBuilder::build(glm::ivec2 winBounds) {
clear(false);
if (winBounds != glm::ivec2 {}) this->winBounds = winBounds;
if (elements) create(*elements, root, this->winBounds);
clear(false);
if (winBounds != glm::ivec2{}) this->winBounds = winBounds;
if (elements) create(*elements, root, this->winBounds);
}
void GuiBuilder::clear(bool deleteRoot) {
clearCallbacks(root);
root->empty();
if (deleteRoot) elements = nullptr;
clearCallbacks(root);
root->empty();
if (deleteRoot) elements = nullptr;
}
void GuiBuilder::create(LuaGuiElement& element, std::shared_ptr<GuiComponent> parent, glm::ivec2 bounds) {
if (element.get_or<bool>("visible", true)) {
auto component = createComponent(element, bounds);
if (!component) throw std::runtime_error("GuiBuilder failed to create component: " + element.key);
parent->add(component);
for (auto &child : element.children) create(*child, component, component->getScale());
}
if (element.get_or<bool>("visible", true)) {
auto component = createComponent(element, bounds);
if (!component) throw std::runtime_error("GuiBuilder failed to create component: " + element.key);
parent->add(component);
for (auto& child : element.children) create(*child, component, component->getScale());
}
}
std::shared_ptr<GuiComponent> GuiBuilder::createComponent(LuaGuiElement& elem, glm::ivec2 bounds) {
std::shared_ptr<GuiComponent> c = nullptr;
switch (Util::hash(elem.type.c_str())) {
default: break;
case Util::hash("Body"): {
auto body = GuiRect::fromSerialized(elem, textures, bounds);
body->setScale(bounds);
c = body;
break;
}
case Util::hash("Rect"):
c = GuiRect::fromSerialized(elem, textures, bounds);
break;
case Util::hash("Button"):
c = GuiImageButton::fromSerialized(elem, textures, bounds);
break;
case Util::hash("Text"):
c = GuiText::fromSerialized(elem, textures, bounds);
break;
case Util::hash("Model"):
c = GuiModel::fromSerialized(elem, textures, models, bounds);
break;
}
if (!c) return nullptr;
elem.updateFunction = std::bind(&GuiBuilder::elementUpdated, this);
std::shared_ptr<GuiComponent> c = nullptr;
switch (Util::hash(elem.type.c_str())) {
default: break;
case Util::hash("Body"): {
auto body = GuiRect::fromSerialized(elem, textures, bounds);
body->setScale(bounds);
c = body;
break;
}
case Util::hash("Rect"):c = GuiRect::fromSerialized(elem, textures, bounds);
break;
case Util::hash("Button"):c = GuiImageButton::fromSerialized(elem, textures, bounds);
break;
case Util::hash("Text"):c = GuiText::fromSerialized(elem, textures, bounds);
break;
case Util::hash("Model"):c = GuiModel::fromSerialized(elem, textures, models, bounds);
break;
}
if (!c) return nullptr;
elem.updateFunction = std::bind(&GuiBuilder::elementUpdated, this);
// if (elem.callbacks.count("primary")) c->setCallback(GuiComponent::CallbackType::PRIMARY, [=](bool b, glm::vec2 v) {
// elem.callbacks.at("primary")(b, LuaParser::luaVec(elem.callbacks.at("primary").lua_state(), {v.x, v.y, 0})); });
@ -83,22 +79,22 @@ std::shared_ptr<GuiComponent> GuiBuilder::createComponent(LuaGuiElement& elem, g
//
// if (elem.callbacks.count("hover")) c->setCallback(GuiComponent::CallbackType::HOVER, [=](bool b, glm::vec2 v) {
// elem.callbacks.at("hover")(b, LuaParser::luaVec(elem.callbacks.at("hover").lua_state(), {v.x, v.y, 0})); });
return c;
return c;
}
void GuiBuilder::clearCallbacks(std::shared_ptr<GuiComponent> component) {
component->setCallback(GuiComponent::CallbackType::PRIMARY, nullptr);
component->setCallback(GuiComponent::CallbackType::SECONDARY, nullptr);
component->setCallback(GuiComponent::CallbackType::HOVER, nullptr);
for (auto& child : component->getChildren()) clearCallbacks(child);
component->setCallback(GuiComponent::CallbackType::PRIMARY, nullptr);
component->setCallback(GuiComponent::CallbackType::SECONDARY, nullptr);
component->setCallback(GuiComponent::CallbackType::HOVER, nullptr);
for (auto& child : component->getChildren()) clearCallbacks(child);
}
void GuiBuilder::elementUpdated() {
dirty = true;
dirty = true;
}
GuiBuilder::~GuiBuilder() {
clear();
clear();
}

View File

@ -12,32 +12,41 @@
class GuiContainer;
class GuiBuilder {
public:
struct ComponentCallbacks { GuiComponent::callback left {}, right {}, hover {}; };
GuiBuilder(TextureAtlas& textures, ModelStore& models, std::shared_ptr<GuiContainer> root);
void setGuiRoot(std::shared_ptr<LuaGuiElement> menu);
void update();
void build(glm::ivec2 winBounds = {});
void clear(bool deleteRoot = true);
~GuiBuilder();
protected:
void create(LuaGuiElement& element, std::shared_ptr<GuiComponent> parent, glm::ivec2 bounds);
virtual std::shared_ptr<GuiComponent> createComponent(LuaGuiElement& elem, glm::ivec2 bounds);
static void clearCallbacks(std::shared_ptr<GuiComponent> component);
void elementUpdated();
TextureAtlas& textures;
ModelStore& models;
std::shared_ptr<GuiContainer> root = nullptr;
std::shared_ptr<LuaGuiElement> elements = nullptr;
unsigned int keyInd = 0;
bool dirty = false;
glm::ivec2 winBounds {};
public:
struct ComponentCallbacks {
GuiComponent::callback left{}, right{}, hover{};
};
GuiBuilder(TextureAtlas& textures, ModelStore& models, std::shared_ptr<GuiContainer> root);
void setGuiRoot(std::shared_ptr<LuaGuiElement> menu);
void update();
void build(glm::ivec2 winBounds = {});
void clear(bool deleteRoot = true);
~GuiBuilder();
protected:
void create(LuaGuiElement& element, std::shared_ptr<GuiComponent> parent, glm::ivec2 bounds);
virtual std::shared_ptr<GuiComponent> createComponent(LuaGuiElement& elem, glm::ivec2 bounds);
static void clearCallbacks(std::shared_ptr<GuiComponent> component);
void elementUpdated();
TextureAtlas& textures;
ModelStore& models;
std::shared_ptr<GuiContainer> root = nullptr;
std::shared_ptr<LuaGuiElement> elements = nullptr;
unsigned int keyInd = 0;
bool dirty = false;
glm::ivec2 winBounds{};
};

View File

@ -9,174 +9,174 @@
#include "client/graph/Renderer.h"
GuiComponent::GuiComponent(const std::string& key) :
key(key) {}
key(key) {}
void GuiComponent::update(double delta) {
for (const auto& child : children) {
child->update(delta);
}
for (const auto& child : children) {
child->update(delta);
}
}
const std::string& GuiComponent::getKey() {
return key;
return key;
}
glm::ivec2 GuiComponent::getPos() {
return pos;
return pos;
}
void GuiComponent::setPos(glm::ivec2 pos) {
this->pos = pos;
if (parent != nullptr) {
glm::vec3 parentPos = parent->entity.getPos();
pos += glm::vec2 {parentPos.x, parentPos.y};
pos += glm::vec2 {parent->getPadding().w, parent->getPadding().x};
}
entity.setPos({pos.x, pos.y, 0});
for (const auto& child : children) {
child->updatePos();
}
this->pos = pos;
if (parent != nullptr) {
glm::vec3 parentPos = parent->entity.getPos();
pos += glm::vec2{ parentPos.x, parentPos.y };
pos += glm::vec2{ parent->getPadding().w, parent->getPadding().x };
}
entity.setPos({ pos.x, pos.y, 0 });
for (const auto& child : children) {
child->updatePos();
}
}
glm::vec2 GuiComponent::getScale() {
return scale;
return scale;
}
void GuiComponent::setScale(glm::vec2 scale) {
this->scale = scale;
entity.setScale({scale.x, scale.y, scale.x});
this->scale = scale;
entity.setScale({ scale.x, scale.y, scale.x });
}
glm::vec4 GuiComponent::getPadding() {
return padding;
return padding;
}
void GuiComponent::setPadding(glm::vec4 padding) {
this->padding = padding;
this->padding = padding;
}
void GuiComponent::setOverflows(bool overflows) {
this->overflows = overflows;
this->overflows = overflows;
}
void GuiComponent::setVisible(bool visible) {
Drawable::setVisible(visible);
entity.setVisible(visible);
for (const auto& child : children) {
child->setVisible(visible);
}
Drawable::setVisible(visible);
entity.setVisible(visible);
for (const auto& child : children) {
child->setVisible(visible);
}
}
void GuiComponent::setCallback(GuiComponent::CallbackType type, const callback& cb) {
callbacks[static_cast<unsigned int>(type)] = cb;
callbacks[static_cast<unsigned int>(type)] = cb;
}
void GuiComponent::handleMouseInput(Window &window) {
auto mousePos = window.input.mousePos();
window.setCursorHand(mouseActivity(mousePos));
if (window.input.mousePressed(GLFW_MOUSE_BUTTON_LEFT)) clickEvent(true, true, mousePos);
if (window.input.mouseReleased(GLFW_MOUSE_BUTTON_LEFT)) clickEvent(true, false, mousePos);
if (window.input.mousePressed(GLFW_MOUSE_BUTTON_RIGHT)) clickEvent(false, true, mousePos);
if (window.input.mouseReleased(GLFW_MOUSE_BUTTON_RIGHT)) clickEvent(false, false, mousePos);
void GuiComponent::handleMouseInput(Window& window) {
auto mousePos = window.input.mousePos();
window.setCursorHand(mouseActivity(mousePos));
if (window.input.mousePressed(GLFW_MOUSE_BUTTON_LEFT)) clickEvent(true, true, mousePos);
if (window.input.mouseReleased(GLFW_MOUSE_BUTTON_LEFT)) clickEvent(true, false, mousePos);
if (window.input.mousePressed(GLFW_MOUSE_BUTTON_RIGHT)) clickEvent(false, true, mousePos);
if (window.input.mouseReleased(GLFW_MOUSE_BUTTON_RIGHT)) clickEvent(false, false, mousePos);
}
bool GuiComponent::mouseActivity(glm::ivec2 pos) {
bool isHovering = false;
for (auto& child : children) {
glm::ivec2 cp = pos - child->getPos() - glm::ivec2(child->getPadding().y, child->getPadding().x);
if (child->mouseActivity(cp)) isHovering = true;
}
auto& callback = callbacks[static_cast<unsigned int>(CallbackType::HOVER)];
if (pos.x >= 0 && pos.y >= 0 && pos.x <= hitbox.x && pos.y <= hitbox.y) {
if (callback) {
callback(true, pos);
hovered = true;
return true;
}
return isHovering;
}
else {
if (callback) {
callback(false, pos);
hovered = false;
}
}
return isHovering;
bool isHovering = false;
for (auto& child : children) {
glm::ivec2 cp = pos - child->getPos() - glm::ivec2(child->getPadding().y, child->getPadding().x);
if (child->mouseActivity(cp)) isHovering = true;
}
auto& callback = callbacks[static_cast<unsigned int>(CallbackType::HOVER)];
if (pos.x >= 0 && pos.y >= 0 && pos.x <= hitbox.x && pos.y <= hitbox.y) {
if (callback) {
callback(true, pos);
hovered = true;
return true;
}
return isHovering;
}
else {
if (callback) {
callback(false, pos);
hovered = false;
}
}
return isHovering;
}
std::shared_ptr<GuiComponent> GuiComponent::insert(unsigned int index, std::shared_ptr<GuiComponent> component) {
component->parent = this;
component->updatePos();
children.insert(std::next(children.begin(), index), std::move(component));
return component;
component->parent = this;
component->updatePos();
children.insert(std::next(children.begin(), index), std::move(component));
return component;
}
std::shared_ptr<GuiComponent> GuiComponent::add(std::shared_ptr<GuiComponent> component) {
component->parent = this;
component->updatePos();
children.push_back(component);
return component;
component->parent = this;
component->updatePos();
children.push_back(component);
return component;
}
void GuiComponent::remove(const std::string& key) {
for (auto it = children.cbegin(); it != children.cend(); it++) {
if (it->get()->key == key) {
children.erase(it);
return;
}
}
for (auto it = children.cbegin(); it != children.cend(); it++) {
if (it->get()->key == key) {
children.erase(it);
return;
}
}
}
void GuiComponent::empty() {
for (auto it = children.cbegin(); it != children.cend();) {
it = children.erase(it);
}
for (auto it = children.cbegin(); it != children.cend();) {
it = children.erase(it);
}
}
void GuiComponent::draw(Renderer& renderer) {
entity.draw(renderer);
for (const auto& child : children) {
renderer.setClipBounds(overflows ? glm::vec4 {} : glm::vec4 {entity.getPos().x, entity.getPos().y,
entity.getPos().x + scale.x, entity.getPos().y + scale.y});
child->draw(renderer);
}
entity.draw(renderer);
for (const auto& child : children) {
renderer.setClipBounds(overflows ? glm::vec4{} : glm::vec4{ entity.getPos().x, entity.getPos().y,
entity.getPos().x + scale.x, entity.getPos().y + scale.y });
child->draw(renderer);
}
}
bool GuiComponent::clickEvent(bool left, bool state, glm::ivec2 pos) {
for (auto& child : children) {
glm::ivec2 cp = pos - child->getPos() - glm::ivec2(child->getPadding().y, child->getPadding().x);
if (child->clickEvent(left, state, cp)) return true;
}
auto& callback = callbacks[static_cast<unsigned int>(left ? CallbackType::PRIMARY : CallbackType::SECONDARY)];
if (pos.x >= 0 && pos.y >= 0 && pos.x <= hitbox.x && pos.y <= hitbox.y && callback) {
callback(state, pos);
return true;
}
return false;
for (auto& child : children) {
glm::ivec2 cp = pos - child->getPos() - glm::ivec2(child->getPadding().y, child->getPadding().x);
if (child->clickEvent(left, state, cp)) return true;
}
auto& callback = callbacks[static_cast<unsigned int>(left ? CallbackType::PRIMARY : CallbackType::SECONDARY)];
if (pos.x >= 0 && pos.y >= 0 && pos.x <= hitbox.x && pos.y <= hitbox.y && callback) {
callback(state, pos);
return true;
}
return false;
}
void GuiComponent::updatePos() {
glm::vec2 realPos(pos);
if (parent != nullptr) {
glm::vec3 parentPos = parent->entity.getPos();
realPos += glm::vec2 {parentPos.x, parentPos.y};
realPos += glm::vec2 {parent->getPadding().w, parent->getPadding().x};
}
entity.setPos({realPos.x, realPos.y, 0});
for (const auto& child : children) {
child->updatePos();
}
glm::vec2 realPos(pos);
if (parent != nullptr) {
glm::vec3 parentPos = parent->entity.getPos();
realPos += glm::vec2{ parentPos.x, parentPos.y };
realPos += glm::vec2{ parent->getPadding().w, parent->getPadding().x };
}
entity.setPos({ realPos.x, realPos.y, 0 });
for (const auto& child : children) {
child->updatePos();
}
}
std::list<std::shared_ptr<GuiComponent>> GuiComponent::getChildren() {
return children;
return children;
}

View File

@ -14,69 +14,85 @@
class Window;
class GuiComponent : public Drawable {
public:
enum class CallbackType { PRIMARY, SECONDARY, HOVER };
typedef std::function<void(bool, glm::ivec2)> callback;
GuiComponent() = default;
explicit GuiComponent(const std::string& key);
virtual void update(double delta) override;
const std::string& getKey();
virtual glm::ivec2 getPos();
virtual void setPos(glm::ivec2 pos);
virtual glm::vec2 getScale();
virtual void setScale(glm::vec2 scale);
virtual glm::vec4 getPadding();
virtual void setPadding(glm::vec4 padding);
void setOverflows(bool overflows);
void setVisible(bool visible) override;
virtual void setCallback(CallbackType type, const callback& cb);
void handleMouseInput(Window& window);
template<class T> std::shared_ptr<T> get(const std::string &key) {
for (auto &it : children) {
if (it.get()->key == key) {
return std::static_pointer_cast<T>(it);
}
}
return nullptr;
};
std::shared_ptr<GuiComponent> insert(unsigned int index, std::shared_ptr<GuiComponent> component);
std::shared_ptr<GuiComponent> add(std::shared_ptr<GuiComponent> component);
std::list<std::shared_ptr<GuiComponent>> getChildren();
void remove(const std::string& key);
void empty();
void draw(Renderer& renderer) override;
protected:
bool mouseActivity(glm::ivec2 pos);
bool clickEvent(bool left, bool state, glm::ivec2 pos);
std::string key = "";
GuiComponent* parent = nullptr;
std::list<std::shared_ptr<GuiComponent>> children;
glm::ivec2 pos {};
glm::vec2 scale {};
glm::vec4 padding {};
glm::ivec2 hitbox {};
bool visible = true;
bool hovered = false;
bool overflows = false;
DrawableEntity entity;
std::array<callback, 3> callbacks;
private:
void updatePos();
public:
enum class CallbackType {
PRIMARY, SECONDARY, HOVER
};
typedef std::function<void(bool, glm::ivec2)> callback;
GuiComponent() = default;
explicit GuiComponent(const std::string& key);
virtual void update(double delta) override;
const std::string& getKey();
virtual glm::ivec2 getPos();
virtual void setPos(glm::ivec2 pos);
virtual glm::vec2 getScale();
virtual void setScale(glm::vec2 scale);
virtual glm::vec4 getPadding();
virtual void setPadding(glm::vec4 padding);
void setOverflows(bool overflows);
void setVisible(bool visible) override;
virtual void setCallback(CallbackType type, const callback& cb);
void handleMouseInput(Window& window);
template<class T>
std::shared_ptr<T> get(const std::string& key) {
for (auto& it : children) {
if (it.get()->key == key) {
return std::static_pointer_cast<T>(it);
}
}
return nullptr;
};
std::shared_ptr<GuiComponent> insert(unsigned int index, std::shared_ptr<GuiComponent> component);
std::shared_ptr<GuiComponent> add(std::shared_ptr<GuiComponent> component);
std::list<std::shared_ptr<GuiComponent>> getChildren();
void remove(const std::string& key);
void empty();
void draw(Renderer& renderer) override;
protected:
bool mouseActivity(glm::ivec2 pos);
bool clickEvent(bool left, bool state, glm::ivec2 pos);
std::string key = "";
GuiComponent* parent = nullptr;
std::list<std::shared_ptr<GuiComponent>> children;
glm::ivec2 pos{};
glm::vec2 scale{};
glm::vec4 padding{};
glm::ivec2 hitbox{};
bool visible = true;
bool hovered = false;
bool overflows = false;
DrawableEntity entity;
std::array<callback, 3> callbacks;
private:
void updatePos();
};

View File

@ -20,71 +20,76 @@
#include "../../lua/usertype/LuaGuiElement.h"
namespace SerialGui {
const float SCALE_MODIFIER = 3;
const float PERCENT_DIFF = 10000;
namespace {
static std::vector<std::string> split(const std::string& value, unsigned int targetCount = 0) {
std::vector<std::string> vec {};
if (value == "") throw std::runtime_error("expected one or more values to split");
size_t count = std::count(value.begin(), value.end(), ' ');
if (count + 1 > targetCount) throw std::runtime_error("expected less values");
// Split the values into the vector.
size_t begin = 0;
for (int i = 0; i < count; i++) {
size_t end = value.find(' ', begin);
vec.push_back(value.substr(begin, end - begin));
begin = end + 1;
}
vec.push_back(value.substr(begin));
// Duplicate values until we meet or surpass the expected values.
while (vec.size() < targetCount) for (auto& v: vec) vec.push_back(v);
if (vec.size() > targetCount) throw std::runtime_error("values are not a division of expectation");
return std::move(vec);
}
static double toDouble(const std::string& input) {
char* e;
errno = 0;
if (input.find('%') == input.length() - 1) {
double v = std::strtod(input.substr(0, input.find("%")).c_str(), &e) / 100;
if (*e != '\0' || errno != 0) throw std::runtime_error("error decoding num from string");
return v - PERCENT_DIFF; // Percentages are going to be stored in negatives. Ew.
}
double v = round(std::strtod(input.c_str(), &e));
if (*e != '\0' || errno != 0) throw std::runtime_error("error decoding num from string");
return v;
}
static double convertNum(float input, unsigned int multiple) {
if (input >= -PERCENT_DIFF - 100 && input < -PERCENT_DIFF + 100) {
if (!multiple) return input + PERCENT_DIFF;
else return (((input + PERCENT_DIFF) * multiple / SCALE_MODIFIER) * SCALE_MODIFIER);
}
return input * SCALE_MODIFIER;
}
}
template <typename T> static T calcNumbers(const T in, glm::ivec2 multiple = {}) {};
template <typename T> static T get(const LuaGuiElement& elem, const std::string& req, glm::ivec2 multiple = {}) {
if (!elem.has<T>(req)) return T{};
return calcNumbers<T>(elem.get<T>(req), multiple);
}
template <> glm::vec2 calcNumbers<glm::vec2>(const glm::vec2 in, glm::ivec2 multiple) {
return {convertNum(in.x, multiple.x), convertNum(in.y, multiple.y)};
}
template <> glm::vec4 calcNumbers<glm::vec4>(const glm::vec4 in, glm::ivec2 multiple) {
return {convertNum(in.x, multiple.x), convertNum(in.y, multiple.y), convertNum(in.z, multiple.x), convertNum(in.w, multiple.y)};
}
const float SCALE_MODIFIER = 3;
const float PERCENT_DIFF = 10000;
namespace {
static std::vector<std::string> split(const std::string& value, unsigned int targetCount = 0) {
std::vector<std::string> vec{};
if (value == "") throw std::runtime_error("expected one or more values to split");
size_t count = std::count(value.begin(), value.end(), ' ');
if (count + 1 > targetCount) throw std::runtime_error("expected less values");
// Split the values into the vector.
size_t begin = 0;
for (int i = 0; i < count; i++) {
size_t end = value.find(' ', begin);
vec.push_back(value.substr(begin, end - begin));
begin = end + 1;
}
vec.push_back(value.substr(begin));
// Duplicate values until we meet or surpass the expected values.
while (vec.size() < targetCount) for (auto& v: vec) vec.push_back(v);
if (vec.size() > targetCount) throw std::runtime_error("values are not a division of expectation");
return std::move(vec);
}
static double toDouble(const std::string& input) {
char* e;
errno = 0;
if (input.find('%') == input.length() - 1) {
double v = std::strtod(input.substr(0, input.find("%")).c_str(), &e) / 100;
if (*e != '\0' || errno != 0) throw std::runtime_error("error decoding num from string");
return v - PERCENT_DIFF; // Percentages are going to be stored in negatives. Ew.
}
double v = round(std::strtod(input.c_str(), &e));
if (*e != '\0' || errno != 0) throw std::runtime_error("error decoding num from string");
return v;
}
static double convertNum(float input, unsigned int multiple) {
if (input >= -PERCENT_DIFF - 100 && input < -PERCENT_DIFF + 100) {
if (!multiple) return input + PERCENT_DIFF;
else return (((input + PERCENT_DIFF) * multiple / SCALE_MODIFIER) * SCALE_MODIFIER);
}
return input * SCALE_MODIFIER;
}
}
template<typename T>
static T calcNumbers(const T in, glm::ivec2 multiple = {}) {};
template<typename T>
static T get(const LuaGuiElement& elem, const std::string& req, glm::ivec2 multiple = {}) {
if (!elem.has<T>(req)) return T{};
return calcNumbers<T>(elem.get<T>(req), multiple);
}
template<>
glm::vec2 calcNumbers<glm::vec2>(const glm::vec2 in, glm::ivec2 multiple) {
return { convertNum(in.x, multiple.x), convertNum(in.y, multiple.y) };
}
template<>
glm::vec4 calcNumbers<glm::vec4>(const glm::vec4 in, glm::ivec2 multiple) {
return { convertNum(in.x, multiple.x), convertNum(in.y, multiple.y), convertNum(in.z, multiple.x),
convertNum(in.w, multiple.y) };
}
};

View File

@ -4,10 +4,10 @@
#include "GuiContainer.h"
GuiContainer::GuiContainer(const std::string &key) : GuiComponent(key) {}
GuiContainer::GuiContainer(const std::string& key) : GuiComponent(key) {}
void GuiContainer::draw(Renderer &renderer) {
for (const auto& child : children) {
child->draw(renderer);
}
void GuiContainer::draw(Renderer& renderer) {
for (const auto& child : children) {
child->draw(renderer);
}
}

View File

@ -7,10 +7,11 @@
#include "client/gui/GuiComponent.h"
class GuiContainer : public GuiComponent {
public:
GuiContainer() = default;
explicit GuiContainer(const std::string& key);
void draw(Renderer& renderer) override;
public:
GuiContainer() = default;
explicit GuiContainer(const std::string& key);
void draw(Renderer& renderer) override;
};

View File

@ -8,99 +8,103 @@
#include "client/graph/Model.h"
#include "game/atlas/asset/AtlasRef.h"
GuiGraph::GuiGraph(const std::string &key) : GuiComponent(key) {}
GuiGraph::GuiGraph(const std::string& key) : GuiComponent(key) {}
void GuiGraph::create(glm::vec2 scale, glm::vec4 padding, std::shared_ptr <AtlasRef> texture,
unsigned int length, float maxValue, bool editInPlace) {
this->scale = scale;
this->padding = padding;
setScale({scale.x + padding.w + padding.y, scale.y + padding.x + padding.z});
this->length = length;
this->maxVal = maxValue;
this->dynamicMax = maxValue <= 0;
this->editInPlace = editInPlace;
this->texture = std::move(texture);
history = std::vector<float>(static_cast<unsigned long>(length));
entity.setModel(std::make_shared<Model>());
void GuiGraph::create(glm::vec2 scale, glm::vec4 padding, std::shared_ptr<AtlasRef> texture,
unsigned int length, float maxValue, bool editInPlace) {
this->scale = scale;
this->padding = padding;
setScale({ scale.x + padding.w + padding.y, scale.y + padding.x + padding.z });
this->length = length;
this->maxVal = maxValue;
this->dynamicMax = maxValue <= 0;
this->editInPlace = editInPlace;
this->texture = std::move(texture);
history = std::vector<float>(static_cast<unsigned long>(length));
entity.setModel(std::make_shared<Model>());
}
void GuiGraph::pushValue(float value) {
if (editInPlace) {
insertionPoint++;
if (insertionPoint >= length) insertionPoint = 0;
history[insertionPoint] = value;
}
else {
if (insertionPoint < length - 1) insertionPoint++;
else {
for (int i = 0; i < length; i++) {
history[i] = history[i + 1];
}
}
history[insertionPoint] = value;
}
if (dynamicMax) {
maxVal = 0;
for (float i : history) {
if (i > maxVal) maxVal = i;
}
}
buildHistogramMesh();
if (editInPlace) {
insertionPoint++;
if (insertionPoint >= length) insertionPoint = 0;
history[insertionPoint] = value;
}
else {
if (insertionPoint < length - 1) insertionPoint++;
else {
for (int i = 0; i < length; i++) {
history[i] = history[i + 1];
}
}
history[insertionPoint] = value;
}
if (dynamicMax) {
maxVal = 0;
for (float i : history) {
if (i > maxVal) maxVal = i;
}
}
buildHistogramMesh();
}
void GuiGraph::setMax(float max) {
maxVal = max;
maxVal = max;
}
void GuiGraph::buildHistogramMesh() {
std::vector<EntityVertex> vertices {};
std::vector<unsigned int> indices {};
auto uv = texture->uv;
uv.z -= uv.x;
uv.w -= uv.y;
unsigned int indOffset = 0;
float xOffset = 0;
for (float num : history) {
float distFromPointer = (xOffset <= insertionPoint) ? insertionPoint - xOffset : insertionPoint + length - xOffset;
float age = std::round((90 - (distFromPointer / length)*90)) / 100.0f;
float h = num / maxVal;
float sec = (float)std::round(9 - fmin(h, 1)*9) * 0.1f;
auto columnVerts = std::vector<EntityVertex> {
{{xOffset, -h, 0}, {uv.x + age * uv.z, uv.y + sec * uv.w, 0, 1}, {1, 1, 1}, true, {}, {}, {}},
{{xOffset + 1,-h, 0}, {uv.x + (age+0.01f) * uv.z, uv.y + sec * uv.w, 0, 1}, {1, 1, 1}, true, {}, {}, {}},
{{xOffset + 1, 0, 0}, {uv.x + (age+0.01f) * uv.z, uv.y + (sec+0.10f) * uv.w, 0, 1}, {1, 1, 1}, true, {}, {}, {}},
{{xOffset, 0, 0}, {uv.x + age * uv.z, uv.y + (sec+0.10f) * uv.w, 0, 1}, {1, 1, 1}, true, {}, {}, {}},
};
vertices.insert(vertices.end(), columnVerts.begin(), columnVerts.end());
indices.push_back( indOffset);
indices.push_back(3 + indOffset);
indices.push_back(1 + indOffset);
indices.push_back(3 + indOffset);
indices.push_back(2 + indOffset);
indices.push_back(1 + indOffset);
xOffset ++;
indOffset += 4;
}
auto m = std::make_unique<EntityMesh>();
m->create(vertices, indices);
auto model = std::make_shared<Model>();
model->fromMesh(std::move(m));
entity.setModel(model);
std::vector<EntityVertex> vertices{};
std::vector<unsigned int> indices{};
auto uv = texture->uv;
uv.z -= uv.x;
uv.w -= uv.y;
unsigned int indOffset = 0;
float xOffset = 0;
for (float num : history) {
float distFromPointer = (xOffset <= insertionPoint) ? insertionPoint - xOffset : insertionPoint + length -
xOffset;
float age = std::round((90 - (distFromPointer / length) * 90)) / 100.0f;
float h = num / maxVal;
float sec = (float) std::round(9 - fmin(h, 1) * 9) * 0.1f;
auto columnVerts = std::vector<EntityVertex>{
{{ xOffset, -h, 0 }, { uv.x + age * uv.z, uv.y + sec * uv.w, 0, 1 }, { 1, 1, 1 }, true, {}, {}, {}},
{{ xOffset + 1, -h, 0 }, { uv.x + (age + 0.01f) * uv.z, uv.y + sec * uv.w, 0, 1 }, { 1, 1, 1 }, true, {},
{}, {}},
{{ xOffset + 1, 0, 0 }, { uv.x + (age + 0.01f) * uv.z, uv.y + (sec + 0.10f) * uv.w, 0, 1 }, { 1, 1, 1 },
true, {}, {}, {}},
{{ xOffset, 0, 0 }, { uv.x + age * uv.z, uv.y + (sec + 0.10f) * uv.w, 0, 1 }, { 1, 1, 1 }, true, {}, {},
{}},
};
vertices.insert(vertices.end(), columnVerts.begin(), columnVerts.end());
indices.push_back(indOffset);
indices.push_back(3 + indOffset);
indices.push_back(1 + indOffset);
indices.push_back(3 + indOffset);
indices.push_back(2 + indOffset);
indices.push_back(1 + indOffset);
xOffset++;
indOffset += 4;
}
auto m = std::make_unique<EntityMesh>();
m->create(vertices, indices);
auto model = std::make_shared<Model>();
model->fromMesh(std::move(m));
entity.setModel(model);
}

View File

@ -9,26 +9,31 @@
class AtlasRef;
class GuiGraph : public GuiComponent {
public:
GuiGraph() = default;
GuiGraph(const std::string& key);
void create(glm::vec2 scale, glm::vec4 padding, std::shared_ptr<AtlasRef> texture, unsigned int length, float maxValue, bool editInPlace);
void setMax(float max);
void pushValue(float value);
private:
void buildHistogramMesh();
bool editInPlace = false;
unsigned int insertionPoint = 0;
unsigned int length = 60;
bool dynamicMax = true;
float maxVal = 0;
std::shared_ptr<AtlasRef> texture;
std::vector<float> history;
public:
GuiGraph() = default;
GuiGraph(const std::string& key);
void
create(glm::vec2 scale, glm::vec4 padding, std::shared_ptr<AtlasRef> texture, unsigned int length, float maxValue,
bool editInPlace);
void setMax(float max);
void pushValue(float value);
private:
void buildHistogramMesh();
bool editInPlace = false;
unsigned int insertionPoint = 0;
unsigned int length = 60;
bool dynamicMax = true;
float maxVal = 0;
std::shared_ptr<AtlasRef> texture;
std::vector<float> history;
};

View File

@ -11,41 +11,41 @@
#include "game/def/BlockDef.h"
#include "game/def/CraftItemDef.h"
GuiInventoryItem::GuiInventoryItem(const std::string &key) : GuiContainer(key) {}
GuiInventoryItem::GuiInventoryItem(const std::string& key) : GuiContainer(key) {}
void GuiInventoryItem::create(glm::vec2 scale, unsigned short count, ItemDef& def, Font f) {
if (def.type == ItemDef::Type::CRAFTITEM) {
auto texture = static_cast<CraftItemDef&>(def).textureRefs[0];
auto shadow = std::make_shared<GuiRect>("shadow");
shadow->create(scale * 16.f, {}, texture, {0, 0, 0, 0.2});
add(shadow);
shadow->setPos(scale);
auto item = std::make_shared<GuiRect>("mesh");
item->create(scale * 16.f, {}, texture);
add(item);
}
else {
auto& model = static_cast<BlockDef&>(def).entityModel;
auto item = std::make_shared<GuiModel>("mesh");
item->create(scale * 10.5f, model);
item->setPos(glm::vec2{8, 8} * scale);
item->setRotationX(180.f - 30.f);
item->setRotationY(45.f);
item->setRotationZ(0.f);
add(item);
}
if (count > 1) {
auto text = std::make_shared<GuiText>("count");
text->create(scale, {}, {}, {1, 1, 1, 1}, f);
text->setText(std::to_string(count));
add(text);
text->setPos({(19 - text->getWidth()) * scale.x, 9 * scale.y});
}
if (def.type == ItemDef::Type::CRAFTITEM) {
auto texture = static_cast<CraftItemDef&>(def).textureRefs[0];
auto shadow = std::make_shared<GuiRect>("shadow");
shadow->create(scale * 16.f, {}, texture, { 0, 0, 0, 0.2 });
add(shadow);
shadow->setPos(scale);
auto item = std::make_shared<GuiRect>("mesh");
item->create(scale * 16.f, {}, texture);
add(item);
}
else {
auto& model = static_cast<BlockDef&>(def).entityModel;
auto item = std::make_shared<GuiModel>("mesh");
item->create(scale * 10.5f, model);
item->setPos(glm::vec2{ 8, 8 } * scale);
item->setRotationX(180.f - 30.f);
item->setRotationY(45.f);
item->setRotationZ(0.f);
add(item);
}
if (count > 1) {
auto text = std::make_shared<GuiText>("count");
text->create(scale, {}, {}, { 1, 1, 1, 1 }, f);
text->setText(std::to_string(count));
add(text);
text->setPos({ (19 - text->getWidth()) * scale.x, 9 * scale.y });
}
}

View File

@ -7,12 +7,14 @@
#include "GuiContainer.h"
class ItemDef;
class Font;
class GuiInventoryItem : public GuiContainer {
public:
GuiInventoryItem() = default;
GuiInventoryItem(const std::string& key);
void create(glm::vec2 scale, unsigned short itemCount, ItemDef& def, Font font);
public:
GuiInventoryItem() = default;
GuiInventoryItem(const std::string& key);
void create(glm::vec2 scale, unsigned short itemCount, ItemDef& def, Font font);
};

View File

@ -11,61 +11,62 @@
#include "game/atlas/asset/ModelStore.h"
#include "game/atlas/TextureAtlas.h"
GuiModel::GuiModel(const std::string &key) : GuiComponent(key) {}
GuiModel::GuiModel(const std::string& key) : GuiComponent(key) {}
std::shared_ptr<GuiModel> GuiModel::fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, ModelStore& models, glm::ivec2 bounds) {
glm::vec2 pos = SerialGui::get<glm::vec2>(elem, "position", bounds);
glm::vec2 scale = SerialGui::get<glm::vec2>(elem, "scale");
glm::vec2 anim_range = SerialGui::get<glm::vec2>(elem, "anim_range");
if (scale == glm::vec2{0, 0}) scale = {1, 1};
std::string type = elem.get_or<std::string>("type", "model");
std::string source = elem.get_or<std::string>("source", "");
std::string texture = elem.get_or<std::string>("texture", "");
auto m = std::make_shared<Model>();
if (type == "model") m->fromSerialized(models.models[source], {textures[texture]});
auto model = std::make_shared<GuiModel>(elem.key);
model->create(scale, m);
model->setPos(pos);
if (anim_range.y != 0) model->animate(anim_range);
return model;
std::shared_ptr<GuiModel>
GuiModel::fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, ModelStore& models, glm::ivec2 bounds) {
glm::vec2 pos = SerialGui::get<glm::vec2>(elem, "position", bounds);
glm::vec2 scale = SerialGui::get<glm::vec2>(elem, "scale");
glm::vec2 anim_range = SerialGui::get<glm::vec2>(elem, "anim_range");
if (scale == glm::vec2{ 0, 0 }) scale = { 1, 1 };
std::string type = elem.get_or<std::string>("type", "model");
std::string source = elem.get_or<std::string>("source", "");
std::string texture = elem.get_or<std::string>("texture", "");
auto m = std::make_shared<Model>();
if (type == "model") m->fromSerialized(models.models[source], { textures[texture] });
auto model = std::make_shared<GuiModel>(elem.key);
model->create(scale, m);
model->setPos(pos);
if (anim_range.y != 0) model->animate(anim_range);
return model;
}
void GuiModel::create(glm::vec2 scale, std::shared_ptr<Model> model) {
entity.setModel(model);
setScale({scale.x + padding.w + padding.y, scale.y + padding.x + padding.z});
setRotationX(180);
setRotationY(215);
entity.setModel(model);
setScale({ scale.x + padding.w + padding.y, scale.y + padding.x + padding.z });
setRotationX(180);
setRotationY(215);
}
void GuiModel::update(double delta) {
entity.update(delta);
entity.update(delta);
}
void GuiModel::animate(glm::vec2 range) {
entity.animation.setAnim(range, 0, true);
entity.animation.setAnim(range, 0, true);
}
void GuiModel::setRotationX(float x) {
entity.setRotateX(x);
entity.setRotateX(x);
}
void GuiModel::setRotationY(float y) {
entity.setRotateY(y);
entity.setRotateY(y);
}
void GuiModel::setRotationZ(float z) {
entity.setRotateZ(z);
entity.setRotateZ(z);
}
void GuiModel::draw(Renderer &renderer) {
renderer.toggleDepthTest(true);
renderer.clearDepthBuffer();
GuiComponent::draw(renderer);
renderer.toggleDepthTest(false);
void GuiModel::draw(Renderer& renderer) {
renderer.toggleDepthTest(true);
renderer.clearDepthBuffer();
GuiComponent::draw(renderer);
renderer.toggleDepthTest(false);
}

View File

@ -9,27 +9,36 @@
#include "GuiContainer.h"
class LocalSubgame;
class ModelStore;
class TextureAtlas;
class LuaGuiElement;
class GuiModel : public GuiComponent {
public:
GuiModel() = default;
GuiModel(const std::string& key);
static std::shared_ptr<GuiModel> fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, ModelStore& models, glm::ivec2 bounds);
void create(glm::vec2 scale, std::shared_ptr<Model> model);
void update(double delta) override;
void animate(glm::vec2 range);
void setRotationX(float x);
void setRotationY(float x);
void setRotationZ(float x);
void draw(Renderer& renderer) override;
protected:
float depth = 300;
public:
GuiModel() = default;
GuiModel(const std::string& key);
static std::shared_ptr<GuiModel>
fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, ModelStore& models, glm::ivec2 bounds);
void create(glm::vec2 scale, std::shared_ptr<Model> model);
void update(double delta) override;
void animate(glm::vec2 range);
void setRotationX(float x);
void setRotationY(float x);
void setRotationZ(float x);
void draw(Renderer& renderer) override;
protected:
float depth = 300;
};

View File

@ -10,111 +10,111 @@
#include "game/atlas/TextureAtlas.h"
#include "game/atlas/asset/AtlasRef.h"
GuiRect::GuiRect(const std::string &key) : GuiComponent(key) {}
GuiRect::GuiRect(const std::string& key) : GuiComponent(key) {}
std::shared_ptr<GuiRect> GuiRect::fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, glm::ivec2 bounds) {
glm::vec2 pos = SerialGui::get<glm::vec2>(elem, "position", bounds);
glm::vec2 offset = SerialGui::get<glm::vec2>(elem, "position_anchor");
glm::vec2 size = SerialGui::get<glm::vec2>(elem, "size", bounds);
glm::vec4 padding = SerialGui::get<glm::vec4>(elem, "padding", bounds);
pos -= offset * size;
size -= glm::vec2 {padding.y + padding.w, padding.x + padding.z};
std::string background = elem.get_or<std::string>("background", "");
bool hideOverflow = elem.get_or<std::string>("overflow", "visible") == "hidden";
auto rect = std::make_shared<GuiRect>(elem.key);
if (background[0] == '#') rect->create(size, padding, Util::hexToColorVec(background));
else if (background.size() > 0) rect->create(size, padding, textures[background]);
else rect->create(size, padding, glm::vec4 {});
rect->setOverflows(!hideOverflow);
rect->setPos(pos);
return rect;
glm::vec2 pos = SerialGui::get<glm::vec2>(elem, "position", bounds);
glm::vec2 offset = SerialGui::get<glm::vec2>(elem, "position_anchor");
glm::vec2 size = SerialGui::get<glm::vec2>(elem, "size", bounds);
glm::vec4 padding = SerialGui::get<glm::vec4>(elem, "padding", bounds);
pos -= offset * size;
size -= glm::vec2{ padding.y + padding.w, padding.x + padding.z };
std::string background = elem.get_or<std::string>("background", "");
bool hideOverflow = elem.get_or<std::string>("overflow", "visible") == "hidden";
auto rect = std::make_shared<GuiRect>(elem.key);
if (background[0] == '#') rect->create(size, padding, Util::hexToColorVec(background));
else if (background.size() > 0) rect->create(size, padding, textures[background]);
else rect->create(size, padding, glm::vec4{});
rect->setOverflows(!hideOverflow);
rect->setPos(pos);
return rect;
}
// Single Color Constructor
// Creates a GuiRect object whose background
// is a flat color defined by 'color'.
void GuiRect::create(glm::vec2 scale, glm::vec4 padding, glm::vec4 color) {
this->scale = scale;
this->padding = padding;
auto mesh = std::make_unique<EntityMesh>();
mesh->create({{{0, 0, 0}, color, {1, 1, 1}, false, {}, {}, {}},
{{0, 1, 0}, color, {1, 1, 1}, false, {}, {}, {}},
{{1, 1, 0}, color, {1, 1, 1}, false, {}, {}, {}},
{{1, 0, 0}, color, {1, 1, 1}, false, {}, {}, {}}
}, {0, 1, 2, 2, 3, 0});
auto model = std::make_shared<Model>();
model->fromMesh(std::move(mesh));
entity.setModel(model);
setScale({scale.x + padding.w + padding.y, scale.y + padding.x + padding.z});
this->scale = scale;
this->padding = padding;
auto mesh = std::make_unique<EntityMesh>();
mesh->create({{{ 0, 0, 0 }, color, { 1, 1, 1 }, false, {}, {}, {}},
{{ 0, 1, 0 }, color, { 1, 1, 1 }, false, {}, {}, {}},
{{ 1, 1, 0 }, color, { 1, 1, 1 }, false, {}, {}, {}},
{{ 1, 0, 0 }, color, { 1, 1, 1 }, false, {}, {}, {}}
}, { 0, 1, 2, 2, 3, 0 });
auto model = std::make_shared<Model>();
model->fromMesh(std::move(mesh));
entity.setModel(model);
setScale({ scale.x + padding.w + padding.y, scale.y + padding.x + padding.z });
}
// Multiple Color Constructor
// Creates a GuiRect object with a gradient background
// defined by 'tl', 'tr', 'bl', and 'br'.
void GuiRect::create(glm::vec2 scale, glm::vec4 padding, glm::vec4 tl, glm::vec4 tr, glm::vec4 bl, glm::vec4 br) {
this->scale = scale;
this->padding = padding;
auto mesh = std::make_unique<EntityMesh>();
mesh->create({
{{0, 0, 0}, tl, {1, 1, 1}, false, {}, {}, {}},
{{0, 1, 0}, bl, {1, 1, 1}, false, {}, {}, {}},
{{1, 1, 0}, br, {1, 1, 1}, false, {}, {}, {}},
{{1, 0, 0}, tr, {1, 1, 1}, false, {}, {}, {}}
}, {0, 1, 2, 2, 3, 0});
auto model = std::make_shared<Model>();
model->fromMesh(std::move(mesh));
entity.setModel(model);
setScale({scale.x + padding.w + padding.y, scale.y + padding.x + padding.z});
this->scale = scale;
this->padding = padding;
auto mesh = std::make_unique<EntityMesh>();
mesh->create({
{{ 0, 0, 0 }, tl, { 1, 1, 1 }, false, {}, {}, {}},
{{ 0, 1, 0 }, bl, { 1, 1, 1 }, false, {}, {}, {}},
{{ 1, 1, 0 }, br, { 1, 1, 1 }, false, {}, {}, {}},
{{ 1, 0, 0 }, tr, { 1, 1, 1 }, false, {}, {}, {}}
}, { 0, 1, 2, 2, 3, 0 });
auto model = std::make_shared<Model>();
model->fromMesh(std::move(mesh));
entity.setModel(model);
setScale({ scale.x + padding.w + padding.y, scale.y + padding.x + padding.z });
}
// Texture Constructor
// Creates a GuiRect object with a textured background
// defined by the 'texture' reference.
void GuiRect::create(glm::vec2 scale, glm::vec4 padding, std::shared_ptr<AtlasRef> texture) {
this->scale = scale;
this->padding = padding;
this->texture = texture;
this->hitbox = scale + glm::vec2{padding.y + padding.w, padding.x + padding.z};
auto mesh = std::make_unique<EntityMesh>();
mesh->create({
{{0, 0, 0}, {this->texture->uv.x, this->texture->uv.y, 0, 1}, {1, 1, 1}, true, {}, {}, {}},
{{0, 1, 0}, {this->texture->uv.x, this->texture->uv.w, 0, 1}, {1, 1, 1}, true, {}, {}, {}},
{{1, 1, 0}, {this->texture->uv.z, this->texture->uv.w, 0, 1}, {1, 1, 1}, true, {}, {}, {}},
{{1, 0, 0}, {this->texture->uv.z, this->texture->uv.y, 0, 1}, {1, 1, 1}, true, {}, {}, {}}
}, {0, 1, 2, 2, 3, 0});
auto model = std::make_shared<Model>();
model->fromMesh(std::move(mesh));
entity.setModel(model);
setScale({scale.x + padding.w + padding.y, scale.y + padding.x + padding.z});
this->scale = scale;
this->padding = padding;
this->texture = texture;
this->hitbox = scale + glm::vec2{ padding.y + padding.w, padding.x + padding.z };
auto mesh = std::make_unique<EntityMesh>();
mesh->create({
{{ 0, 0, 0 }, { this->texture->uv.x, this->texture->uv.y, 0, 1 }, { 1, 1, 1 }, true, {}, {}, {}},
{{ 0, 1, 0 }, { this->texture->uv.x, this->texture->uv.w, 0, 1 }, { 1, 1, 1 }, true, {}, {}, {}},
{{ 1, 1, 0 }, { this->texture->uv.z, this->texture->uv.w, 0, 1 }, { 1, 1, 1 }, true, {}, {}, {}},
{{ 1, 0, 0 }, { this->texture->uv.z, this->texture->uv.y, 0, 1 }, { 1, 1, 1 }, true, {}, {}, {}}
}, { 0, 1, 2, 2, 3, 0 });
auto model = std::make_shared<Model>();
model->fromMesh(std::move(mesh));
entity.setModel(model);
setScale({ scale.x + padding.w + padding.y, scale.y + padding.x + padding.z });
}
// Texture Constructor
// Creates a GuiRect object with a textured background
// defined by the 'texture' reference.
void GuiRect::create(glm::vec2 scale, glm::vec4 padding, std::shared_ptr<AtlasRef> texture, glm::vec4 tint) {
this->scale = scale;
this->padding = padding;
this->texture = std::move(texture);
auto mesh = std::make_unique<EntityMesh>();
mesh->create({
{{0, 0, 0}, {this->texture->uv.x, this->texture->uv.y, 0, tint.w}, glm::vec3{tint}, true, {}, {}, {}},
{{0, 1, 0}, {this->texture->uv.x, this->texture->uv.w, 0, tint.w}, glm::vec3{tint}, true, {}, {}, {}},
{{1, 1, 0}, {this->texture->uv.z, this->texture->uv.w, 0, tint.w}, glm::vec3{tint}, true, {}, {}, {}},
{{1, 0, 0}, {this->texture->uv.z, this->texture->uv.y, 0, tint.w}, glm::vec3{tint}, true, {}, {}, {}}
}, {0, 1, 2, 2, 3, 0});
auto model = std::make_shared<Model>();
model->fromMesh(std::move(mesh));
entity.setModel(model);
setScale({scale.x + padding.w + padding.y, scale.y + padding.x + padding.z});
this->scale = scale;
this->padding = padding;
this->texture = std::move(texture);
auto mesh = std::make_unique<EntityMesh>();
mesh->create({
{{ 0, 0, 0 }, { this->texture->uv.x, this->texture->uv.y, 0, tint.w }, glm::vec3{ tint }, true, {}, {}, {}},
{{ 0, 1, 0 }, { this->texture->uv.x, this->texture->uv.w, 0, tint.w }, glm::vec3{ tint }, true, {}, {}, {}},
{{ 1, 1, 0 }, { this->texture->uv.z, this->texture->uv.w, 0, tint.w }, glm::vec3{ tint }, true, {}, {}, {}},
{{ 1, 0, 0 }, { this->texture->uv.z, this->texture->uv.y, 0, tint.w }, glm::vec3{ tint }, true, {}, {}, {}}
}, { 0, 1, 2, 2, 3, 0 });
auto model = std::make_shared<Model>();
model->fromMesh(std::move(mesh));
entity.setModel(model);
setScale({ scale.x + padding.w + padding.y, scale.y + padding.x + padding.z });
}

View File

@ -7,23 +7,31 @@
#include "client/gui/GuiComponent.h"
class AtlasRef;
class LocalSubgame;
class TextureAtlas;
class LuaGuiElement;
class GuiRect : public GuiComponent {
public:
GuiRect() = default;
GuiRect(const std::string& key);
static std::shared_ptr<GuiRect> fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, glm::ivec2 bounds);
void create(glm::vec2 scale, glm::vec4 padding, glm::vec4 color);
void create(glm::vec2 scale, glm::vec4 padding, glm::vec4 tl, glm::vec4 tr, glm::vec4 bl, glm::vec4 br);
void create(glm::vec2 scale, glm::vec4 padding, std::shared_ptr<AtlasRef> texture);
void create(glm::vec2 scale, glm::vec4 padding, std::shared_ptr<AtlasRef> texture, glm::vec4 tint);
protected:
std::shared_ptr<AtlasRef> texture = nullptr;
public:
GuiRect() = default;
GuiRect(const std::string& key);
static std::shared_ptr<GuiRect>
fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, glm::ivec2 bounds);
void create(glm::vec2 scale, glm::vec4 padding, glm::vec4 color);
void create(glm::vec2 scale, glm::vec4 padding, glm::vec4 tl, glm::vec4 tr, glm::vec4 bl, glm::vec4 br);
void create(glm::vec2 scale, glm::vec4 padding, std::shared_ptr<AtlasRef> texture);
void create(glm::vec2 scale, glm::vec4 padding, std::shared_ptr<AtlasRef> texture, glm::vec4 tint);
protected:
std::shared_ptr<AtlasRef> texture = nullptr;
};

View File

@ -12,170 +12,178 @@
#include "game/atlas/asset/AtlasRef.h"
#include "world/dim/ent/AnimationSegment.h"
GuiText::GuiText(const std::string &key) : GuiComponent(key) {}
GuiText::GuiText(const std::string& key) : GuiComponent(key) {}
void GuiText::create(glm::vec2 scale, glm::vec4 padding, glm::vec4 bgcolor, glm::vec4 color, Font font) {
// Text Constructor
// Creates a GuiText object.
this->scale = scale;
this->padding = padding;
this->font = std::move(font);
this->bgcolor = bgcolor;
this->color = color;
setScale(scale);
setText("");
// Text Constructor
// Creates a GuiText object.
this->scale = scale;
this->padding = padding;
this->font = std::move(font);
this->bgcolor = bgcolor;
this->color = color;
setScale(scale);
setText("");
}
std::shared_ptr<GuiText> GuiText::fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, glm::ivec2 bounds) {
glm::vec2 pos = SerialGui::get<glm::vec2>(elem, "position", bounds);
glm::vec2 offset = SerialGui::get<glm::vec2>(elem, "position_anchor");
glm::vec2 size = SerialGui::get<glm::vec2>(elem, "size", bounds);
glm::vec4 padding = SerialGui::get<glm::vec4>(elem, "padding", bounds);
glm::vec2 scale = SerialGui::get<glm::vec2>(elem, "scale");
if (scale == glm::vec2{0, 0}) scale = {1, 1};
pos -= offset * size;
glm::vec4 background_color = Util::hexToColorVec(elem.get_or<std::string>("background", "#0000"));
glm::vec4 color = Util::hexToColorVec(elem.get_or<std::string>("color", "#fff"));
std::string content = elem.get_or<std::string>("content", "");
auto text = std::make_shared<GuiText>(elem.key);
text->create(scale * SerialGui::SCALE_MODIFIER, padding, background_color, color, {textures, textures["font"]});
text->setText(content);
text->setPos(pos);
return text;
glm::vec2 pos = SerialGui::get<glm::vec2>(elem, "position", bounds);
glm::vec2 offset = SerialGui::get<glm::vec2>(elem, "position_anchor");
glm::vec2 size = SerialGui::get<glm::vec2>(elem, "size", bounds);
glm::vec4 padding = SerialGui::get<glm::vec4>(elem, "padding", bounds);
glm::vec2 scale = SerialGui::get<glm::vec2>(elem, "scale");
if (scale == glm::vec2{ 0, 0 }) scale = { 1, 1 };
pos -= offset * size;
glm::vec4 background_color = Util::hexToColorVec(elem.get_or<std::string>("background", "#0000"));
glm::vec4 color = Util::hexToColorVec(elem.get_or<std::string>("color", "#fff"));
std::string content = elem.get_or<std::string>("content", "");
auto text = std::make_shared<GuiText>(elem.key);
text->create(scale * SerialGui::SCALE_MODIFIER, padding, background_color, color, { textures, textures["font"] });
text->setText(content);
text->setPos(pos);
return text;
}
void GuiText::setText(std::string text) {
this->text = std::move(text);
unsigned int indOffset = 0;
maxLineWidth = 0;
std::vector<EntityVertex> textVertices;
textVertices.reserve(text.length()*8 + 200);
std::vector<unsigned int> textIndices;
textIndices.reserve(text.length()*12 + 240);
//Draw background & Measure Line Width
int lineWidth = 0;
int xOffset = 0, yOffset = 0;
int h = Font::charHeight;
for (unsigned int i = 0; i < this->text.length() + 1; i++) {
char c = this->text[i];
//TODO: Proper font handling.
if (c == '\t') c = ' ';
if (c == '\n' || i == this->text.length()) {
if (lineWidth > 0) {
lineWidth += 2;
if (lineWidth > maxLineWidth) maxLineWidth = lineWidth;
if (bgcolor.w != 0) {
textVertices.emplace_back(glm::vec3 {-1, yOffset - 1, 0}, bgcolor, glm::vec3(1), 0.f, glm::vec3 {}, glm::ivec4 {}, glm::vec4 {});
textVertices.emplace_back(glm::vec3 {-1, yOffset + h + 1, 0}, bgcolor, glm::vec3(1), 0.f, glm::vec3 {}, glm::ivec4 {}, glm::vec4 {});
textVertices.emplace_back(glm::vec3 {lineWidth + 1, yOffset + h + 1, 0}, bgcolor, glm::vec3(1), 0.f, glm::vec3 {}, glm::ivec4 {}, glm::vec4 {});
textVertices.emplace_back(glm::vec3 {lineWidth + 1, yOffset - 1, 0}, bgcolor, glm::vec3(1), 0.f, glm::vec3 {}, glm::ivec4 {}, glm::vec4 {});
textIndices.emplace_back(indOffset);
textIndices.emplace_back(indOffset + 1);
textIndices.emplace_back(indOffset + 2);
textIndices.emplace_back(indOffset + 2);
textIndices.emplace_back(indOffset + 3);
textIndices.emplace_back(indOffset);
indOffset += 4;
}
yOffset += h + 2;
}
else {
yOffset += h / 2; //Pad out the height if using just newlines.
}
lineWidth = 0;
}
else lineWidth += font.getCharWidth(c) + 1;
}
//Draw Characters
bool emptyLine = true;
xOffset = 0;
yOffset = 0;
for (unsigned int i = 0; i < this->text.length() + 1; i++) {
char c = this->text[i];
//TODO: Proper font handling.
if (c == '\t') c = ' ';
unsigned int h = Font::charHeight;
if (c == '\n' || i == this->text.length()) {
yOffset += (emptyLine) ? h / 2 : h + 2;
xOffset = 0;
emptyLine = true;
continue;
}
else {
emptyLine = false;
}
auto charWidth = font.getCharWidth(c) + 1;
auto charUVs = font.getCharUVs(c);
for (unsigned int j = 0; j <= 1; j++) {
glm::vec3 c = {this->color.x, this->color.y, this->color.z};
if (j == 0) {
c *= glm::vec3 {0.4, 0.4, 0.45};
xOffset += 1;
yOffset += 1;
}
else {
xOffset -= 1;
yOffset -= 1;
}
textVertices.emplace_back(glm::vec3 {xOffset, yOffset, 0}, glm::vec4 {charUVs.x, charUVs.y, 0, color.w}, c, 1.f, glm::vec3 {}, glm::ivec4 {}, glm::vec4 {});
textVertices.emplace_back(glm::vec3 {xOffset, yOffset + h, 0}, glm::vec4 {charUVs.x, charUVs.w, 0, color.w}, c, 1.f, glm::vec3 {}, glm::ivec4 {}, glm::vec4 {});
textVertices.emplace_back(glm::vec3 {xOffset + charWidth, yOffset + h, 0}, glm::vec4 {charUVs.z, charUVs.w, 0, color.w}, c, 1.f, glm::vec3 {}, glm::ivec4 {}, glm::vec4 {});
textVertices.emplace_back(glm::vec3 {xOffset + charWidth, yOffset, 0}, glm::vec4 {charUVs.z, charUVs.y, 0, color.w}, c, 1.f, glm::vec3 {}, glm::ivec4 {}, glm::vec4 {});
textIndices.emplace_back(indOffset);
textIndices.emplace_back(indOffset + 1);
textIndices.emplace_back(indOffset + 2);
textIndices.emplace_back(indOffset + 2);
textIndices.emplace_back(indOffset + 3);
textIndices.emplace_back(indOffset);
indOffset += 4;
}
xOffset += charWidth;
}
auto m = std::make_unique<EntityMesh>();
m->create(textVertices, textIndices);
auto model = std::make_shared<Model>();
model->fromMesh(std::move(m));
entity.setModel(model);
this->text = std::move(text);
unsigned int indOffset = 0;
maxLineWidth = 0;
std::vector<EntityVertex> textVertices;
textVertices.reserve(text.length() * 8 + 200);
std::vector<unsigned int> textIndices;
textIndices.reserve(text.length() * 12 + 240);
//Draw background & Measure Line Width
int lineWidth = 0;
int xOffset = 0, yOffset = 0;
int h = Font::charHeight;
for (unsigned int i = 0; i < this->text.length() + 1; i++) {
char c = this->text[i];
//TODO: Proper font handling.
if (c == '\t') c = ' ';
if (c == '\n' || i == this->text.length()) {
if (lineWidth > 0) {
lineWidth += 2;
if (lineWidth > maxLineWidth) maxLineWidth = lineWidth;
if (bgcolor.w != 0) {
textVertices.emplace_back(glm::vec3{ -1, yOffset - 1, 0 }, bgcolor, glm::vec3(1), 0.f, glm::vec3{},
glm::ivec4{}, glm::vec4{});
textVertices.emplace_back(glm::vec3{ -1, yOffset + h + 1, 0 }, bgcolor, glm::vec3(1), 0.f,
glm::vec3{}, glm::ivec4{}, glm::vec4{});
textVertices.emplace_back(glm::vec3{ lineWidth + 1, yOffset + h + 1, 0 }, bgcolor, glm::vec3(1),
0.f, glm::vec3{}, glm::ivec4{}, glm::vec4{});
textVertices.emplace_back(glm::vec3{ lineWidth + 1, yOffset - 1, 0 }, bgcolor, glm::vec3(1), 0.f,
glm::vec3{}, glm::ivec4{}, glm::vec4{});
textIndices.emplace_back(indOffset);
textIndices.emplace_back(indOffset + 1);
textIndices.emplace_back(indOffset + 2);
textIndices.emplace_back(indOffset + 2);
textIndices.emplace_back(indOffset + 3);
textIndices.emplace_back(indOffset);
indOffset += 4;
}
yOffset += h + 2;
}
else {
yOffset += h / 2; //Pad out the height if using just newlines.
}
lineWidth = 0;
}
else lineWidth += font.getCharWidth(c) + 1;
}
//Draw Characters
bool emptyLine = true;
xOffset = 0;
yOffset = 0;
for (unsigned int i = 0; i < this->text.length() + 1; i++) {
char c = this->text[i];
//TODO: Proper font handling.
if (c == '\t') c = ' ';
unsigned int h = Font::charHeight;
if (c == '\n' || i == this->text.length()) {
yOffset += (emptyLine) ? h / 2 : h + 2;
xOffset = 0;
emptyLine = true;
continue;
}
else {
emptyLine = false;
}
auto charWidth = font.getCharWidth(c) + 1;
auto charUVs = font.getCharUVs(c);
for (unsigned int j = 0; j <= 1; j++) {
glm::vec3 c = { this->color.x, this->color.y, this->color.z };
if (j == 0) {
c *= glm::vec3{ 0.4, 0.4, 0.45 };
xOffset += 1;
yOffset += 1;
}
else {
xOffset -= 1;
yOffset -= 1;
}
textVertices.emplace_back(glm::vec3{ xOffset, yOffset, 0 }, glm::vec4{ charUVs.x, charUVs.y, 0, color.w },
c, 1.f, glm::vec3{}, glm::ivec4{}, glm::vec4{});
textVertices.emplace_back(glm::vec3{ xOffset, yOffset + h, 0 },
glm::vec4{ charUVs.x, charUVs.w, 0, color.w }, c, 1.f, glm::vec3{}, glm::ivec4{}, glm::vec4{});
textVertices.emplace_back(glm::vec3{ xOffset + charWidth, yOffset + h, 0 },
glm::vec4{ charUVs.z, charUVs.w, 0, color.w }, c, 1.f, glm::vec3{}, glm::ivec4{}, glm::vec4{});
textVertices.emplace_back(glm::vec3{ xOffset + charWidth, yOffset, 0 },
glm::vec4{ charUVs.z, charUVs.y, 0, color.w }, c, 1.f, glm::vec3{}, glm::ivec4{}, glm::vec4{});
textIndices.emplace_back(indOffset);
textIndices.emplace_back(indOffset + 1);
textIndices.emplace_back(indOffset + 2);
textIndices.emplace_back(indOffset + 2);
textIndices.emplace_back(indOffset + 3);
textIndices.emplace_back(indOffset);
indOffset += 4;
}
xOffset += charWidth;
}
auto m = std::make_unique<EntityMesh>();
m->create(textVertices, textIndices);
auto model = std::make_shared<Model>();
model->fromMesh(std::move(m));
entity.setModel(model);
}
std::string GuiText::getText() {
return text;
return text;
}
unsigned int GuiText::getWidth() {
return maxLineWidth;
return maxLineWidth;
}

View File

@ -9,27 +9,32 @@
#include "client/graph/Font.h"
class TextureAtlas;
class LuaGuiElement;
class GuiText : public GuiComponent {
public:
GuiText() = default;
explicit GuiText(const std::string& key);
static std::shared_ptr<GuiText> fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, glm::ivec2 bounds);
void create(glm::vec2 scale, glm::vec4 padding, glm::vec4 bgcolor, glm::vec4 color, Font font);
unsigned int getWidth();
void setText(std::string text);
std::string getText();
private:
Font font;
glm::vec4 bgcolor {};
glm::vec4 color {};
std::string text;
unsigned int maxLineWidth = 0;
public:
GuiText() = default;
explicit GuiText(const std::string& key);
static std::shared_ptr<GuiText>
fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, glm::ivec2 bounds);
void create(glm::vec2 scale, glm::vec4 padding, glm::vec4 bgcolor, glm::vec4 color, Font font);
unsigned int getWidth();
void setText(std::string text);
std::string getText();
private:
Font font;
glm::vec4 bgcolor{};
glm::vec4 color{};
std::string text;
unsigned int maxLineWidth = 0;
};

View File

@ -9,73 +9,75 @@
#include "client/gui/basic/GuiText.h"
#include "game/atlas/asset/AtlasRef.h"
GuiImageButton::GuiImageButton(const std::string &key) : GuiRect(key) {}
GuiImageButton::GuiImageButton(const std::string& key) : GuiRect(key) {}
std::shared_ptr<GuiImageButton> GuiImageButton::fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, glm::ivec2 bounds) {
glm::vec2 pos = SerialGui::get<glm::vec2>(elem, "position", bounds);
glm::vec2 offset = SerialGui::get<glm::vec2>(elem, "position_anchor");
glm::vec2 size = SerialGui::get<glm::vec2>(elem, "size", bounds);
glm::vec4 padding = SerialGui::get<glm::vec4>(elem, "padding", bounds);
pos -= offset * size;
size -= glm::vec2 {padding.y + padding.w, padding.x + padding.z};
std::string background = elem.get_or<std::string>("background", "");
std::string background_hover = elem.get_or<std::string>("background_hover", background);
bool hideOverflow = elem.get_or<std::string>("overflow", "visible") == "hidden";
std::string content = elem.get_or<std::string>("content", "");
auto button = std::make_shared<GuiImageButton>(elem.key);
button->create(size, padding, textures[background], textures[background_hover]);
button->setOverflows(!hideOverflow);
button->setPos(pos);
if (content != "") {
auto text = std::make_shared<GuiText>(elem.key + "__TEXT");
text->create(glm::vec2(SerialGui::SCALE_MODIFIER), padding, {}, {1, 1, 1, 1}, {textures, textures["font"]});
text->setPos({6 * SerialGui::SCALE_MODIFIER, size.y / 2 - 4.5 * SerialGui::SCALE_MODIFIER});
text->setText(content);
button->add(text);
}
return button;
std::shared_ptr<GuiImageButton>
GuiImageButton::fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, glm::ivec2 bounds) {
glm::vec2 pos = SerialGui::get<glm::vec2>(elem, "position", bounds);
glm::vec2 offset = SerialGui::get<glm::vec2>(elem, "position_anchor");
glm::vec2 size = SerialGui::get<glm::vec2>(elem, "size", bounds);
glm::vec4 padding = SerialGui::get<glm::vec4>(elem, "padding", bounds);
pos -= offset * size;
size -= glm::vec2{ padding.y + padding.w, padding.x + padding.z };
std::string background = elem.get_or<std::string>("background", "");
std::string background_hover = elem.get_or<std::string>("background_hover", background);
bool hideOverflow = elem.get_or<std::string>("overflow", "visible") == "hidden";
std::string content = elem.get_or<std::string>("content", "");
auto button = std::make_shared<GuiImageButton>(elem.key);
button->create(size, padding, textures[background], textures[background_hover]);
button->setOverflows(!hideOverflow);
button->setPos(pos);
if (content != "") {
auto text = std::make_shared<GuiText>(elem.key + "__TEXT");
text->create(glm::vec2(SerialGui::SCALE_MODIFIER), padding, {}, { 1, 1, 1, 1 }, { textures, textures["font"] });
text->setPos({ 6 * SerialGui::SCALE_MODIFIER, size.y / 2 - 4.5 * SerialGui::SCALE_MODIFIER });
text->setText(content);
button->add(text);
}
return button;
}
// Texture Constructor
// Creates a GuiImageButton object with two textures
// defined by the 'texture' & 'hoverTexture' reference.
void GuiImageButton::create(glm::vec2 scale, glm::vec4 padding, std::shared_ptr<AtlasRef> texture, std::shared_ptr<AtlasRef> hoverTexture) {
this->hoverTexture = hoverTexture;
GuiRect::create(scale, padding, texture);
setCallback(GuiComponent::CallbackType::HOVER, nullptr);
void GuiImageButton::create(glm::vec2 scale, glm::vec4 padding, std::shared_ptr<AtlasRef> texture,
std::shared_ptr<AtlasRef> hoverTexture) {
this->hoverTexture = hoverTexture;
GuiRect::create(scale, padding, texture);
setCallback(GuiComponent::CallbackType::HOVER, nullptr);
}
void GuiImageButton::setCallback(GuiComponent::CallbackType type, const GuiComponent::callback &cb) {
if (type == CallbackType::HOVER) {
GuiComponent::setCallback(type, [&, cb](bool nowHovered, glm::ivec2 pos) {
if (cb) cb(nowHovered, pos);
if (nowHovered != hovered) this->rebuild(nowHovered);
});
}
else GuiComponent::setCallback(type, cb);
void GuiImageButton::setCallback(GuiComponent::CallbackType type, const GuiComponent::callback& cb) {
if (type == CallbackType::HOVER) {
GuiComponent::setCallback(type, [&, cb](bool nowHovered, glm::ivec2 pos) {
if (cb) cb(nowHovered, pos);
if (nowHovered != hovered) this->rebuild(nowHovered);
});
}
else GuiComponent::setCallback(type, cb);
}
void GuiImageButton::rebuild(bool hover) {
auto tex = (hover) ? (hoverTexture != nullptr) ? hoverTexture : texture : texture;
auto mesh = std::make_unique<EntityMesh>();
mesh->create({
{{0, 0, 0}, {tex->uv.x, tex->uv.y, 0, 1}, {1, 1, 1}, true, {}, {}, {}},
{{0, 1, 0}, {tex->uv.x, tex->uv.w, 0, 1}, {1, 1, 1}, true, {}, {}, {}},
{{1, 1, 0}, {tex->uv.z, tex->uv.w, 0, 1}, {1, 1, 1}, true, {}, {}, {}},
{{1, 0, 0}, {tex->uv.z, tex->uv.y, 0, 1}, {1, 1, 1}, true, {}, {}, {}}
}, {0, 1, 2, 2, 3, 0});
auto model = std::make_shared<Model>();
model->fromMesh(std::move(mesh));
entity.setModel(model);
setScale({scale.x + padding.w + padding.y, scale.y + padding.x + padding.z});
auto tex = (hover) ? (hoverTexture != nullptr) ? hoverTexture : texture : texture;
auto mesh = std::make_unique<EntityMesh>();
mesh->create({
{{ 0, 0, 0 }, { tex->uv.x, tex->uv.y, 0, 1 }, { 1, 1, 1 }, true, {}, {}, {}},
{{ 0, 1, 0 }, { tex->uv.x, tex->uv.w, 0, 1 }, { 1, 1, 1 }, true, {}, {}, {}},
{{ 1, 1, 0 }, { tex->uv.z, tex->uv.w, 0, 1 }, { 1, 1, 1 }, true, {}, {}, {}},
{{ 1, 0, 0 }, { tex->uv.z, tex->uv.y, 0, 1 }, { 1, 1, 1 }, true, {}, {}, {}}
}, { 0, 1, 2, 2, 3, 0 });
auto model = std::make_shared<Model>();
model->fromMesh(std::move(mesh));
entity.setModel(model);
setScale({ scale.x + padding.w + padding.y, scale.y + padding.x + padding.z });
}

View File

@ -7,16 +7,21 @@
#include "../basic/GuiRect.h"
class GuiImageButton : public GuiRect {
public:
GuiImageButton() = default;
GuiImageButton(const std::string& key);
static std::shared_ptr<GuiImageButton> fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, glm::ivec2 bounds);
void create(glm::vec2 scale, glm::vec4 padding, std::shared_ptr<AtlasRef> texture, std::shared_ptr<AtlasRef> hoverTexture);
void setCallback(CallbackType type, const callback& cb) override;
private:
void rebuild(bool hover);
std::shared_ptr<AtlasRef> hoverTexture = nullptr;
public:
GuiImageButton() = default;
GuiImageButton(const std::string& key);
static std::shared_ptr<GuiImageButton>
fromSerialized(const LuaGuiElement& elem, TextureAtlas& textures, glm::ivec2 bounds);
void create(glm::vec2 scale, glm::vec4 padding, std::shared_ptr<AtlasRef> texture,
std::shared_ptr<AtlasRef> hoverTexture);
void setCallback(CallbackType type, const callback& cb) override;
private:
void rebuild(bool hover);
std::shared_ptr<AtlasRef> hoverTexture = nullptr;
};

View File

@ -12,138 +12,139 @@
#include "game/atlas/LocalDefinitionAtlas.h"
#include "client/gui/basic/GuiInventoryItem.h"
GuiInventoryList::GuiInventoryList(const std::string &key) : GuiContainer(key) {}
GuiInventoryList::GuiInventoryList(const std::string& key) : GuiContainer(key) {}
std::shared_ptr<GuiInventoryList> GuiInventoryList::fromSerialized(const LuaGuiElement& elem,
SubgamePtr game, glm::ivec2 bounds, InventoryRefsPtr refs) {
glm::vec2 pos = SerialGui::get<glm::vec2>(elem, "position", bounds);
SubgamePtr game, glm::ivec2 bounds, InventoryRefsPtr refs) {
glm::vec2 pos = SerialGui::get<glm::vec2>(elem, "position", bounds);
// glm::vec2 offset = SerialGui::get<glm::vec2>(elem, "position_anchor");
// glm::vec2 size = SerialGui::deserializeToken<glm::vec2>(s.tokens, "size", bounds);
glm::vec4 padding = SerialGui::get<glm::vec4>(elem, "padding", bounds);
glm::vec2 slotspc = SerialGui::get<glm::vec2>(elem, "slot_spacing", bounds);
std::string source = elem.get_or<std::string>("source", "");
std::string list = elem.get_or<std::string>("list", "");
unsigned short start = static_cast<unsigned short>(elem.get_or<float>("start", 1) - 1);
unsigned short length = static_cast<unsigned short>(elem.get_or<float>("length", 0));
auto invList = refs->getInventory(source)->getList(list).l();
auto inv = std::make_shared<GuiInventoryList>(elem.key);
inv->create(glm::vec2(SerialGui::SCALE_MODIFIER), padding * SerialGui::SCALE_MODIFIER,
slotspc * SerialGui::SCALE_MODIFIER, invList, refs.l()->getCursorList(), game, start, length);
inv->setPos(pos);
return inv;
glm::vec4 padding = SerialGui::get<glm::vec4>(elem, "padding", bounds);
glm::vec2 slotspc = SerialGui::get<glm::vec2>(elem, "slot_spacing", bounds);
std::string source = elem.get_or<std::string>("source", "");
std::string list = elem.get_or<std::string>("list", "");
unsigned short start = static_cast<unsigned short>(elem.get_or<float>("start", 1) - 1);
unsigned short length = static_cast<unsigned short>(elem.get_or<float>("length", 0));
auto invList = refs->getInventory(source)->getList(list).l();
auto inv = std::make_shared<GuiInventoryList>(elem.key);
inv->create(glm::vec2(SerialGui::SCALE_MODIFIER), padding * SerialGui::SCALE_MODIFIER,
slotspc * SerialGui::SCALE_MODIFIER, invList, refs.l()->getCursorList(), game, start, length);
inv->setPos(pos);
return inv;
}
void GuiInventoryList::create(glm::vec2 scale, glm::vec4 padding, glm::ivec2 innerPadding,
InventoryListPtr list, InventoryListPtr cursor, SubgamePtr defs,
unsigned short start, unsigned short length) {
this->list = list;
this->cursor = cursor;
this->defs = defs;
this->start = start;
this->length = length;
this->scale = scale;
this->padding = padding;
this->innerPadding = innerPadding;
this->hitbox = (list->getWidth() == 0 ? glm::ivec2 {} : glm::ivec2 {
padding.x + list->getWidth() * (innerPadding.x*scale.x),
padding.y + (list->getLength() / list->getWidth()) * (innerPadding.y*scale.y) });
drawContents();
myCallback = std::make_shared<std::function<void()>>(std::bind(&GuiInventoryList::drawContents, this));
list.l()->addGuiCallback(myCallback);
setCallback(CallbackType::PRIMARY, nullptr);
setCallback(CallbackType::SECONDARY, nullptr);
setCallback(CallbackType::HOVER, nullptr);
hoverRect->create({}, {}, {1, 1, 1, 0.1});
InventoryListPtr list, InventoryListPtr cursor, SubgamePtr defs,
unsigned short start, unsigned short length) {
this->list = list;
this->cursor = cursor;
this->defs = defs;
this->start = start;
this->length = length;
this->scale = scale;
this->padding = padding;
this->innerPadding = innerPadding;
this->hitbox = (list->getWidth() == 0 ? glm::ivec2{} : glm::ivec2{
padding.x + list->getWidth() * (innerPadding.x * scale.x),
padding.y + (list->getLength() / list->getWidth()) * (innerPadding.y * scale.y) });
drawContents();
myCallback = std::make_shared<std::function<void()>>(std::bind(&GuiInventoryList::drawContents, this));
list.l()->addGuiCallback(myCallback);
setCallback(CallbackType::PRIMARY, nullptr);
setCallback(CallbackType::SECONDARY, nullptr);
setCallback(CallbackType::HOVER, nullptr);
hoverRect->create({}, {}, { 1, 1, 1, 0.1 });
}
void GuiInventoryList::setCallback(CallbackType type, const callback& cb) {
GuiComponent::setCallback(type, [&, cb, type](bool down, glm::ivec2 pos) {
if (cb) cb(down, pos);
if (type == GuiComponent::CallbackType::HOVER) this->hoverEvent(down, pos);
else if (down) this->interactEvent(pos, type == GuiComponent::CallbackType::PRIMARY);
});
GuiComponent::setCallback(type, [&, cb, type](bool down, glm::ivec2 pos) {
if (cb) cb(down, pos);
if (type == GuiComponent::CallbackType::HOVER) this->hoverEvent(down, pos);
else if (down) this->interactEvent(pos, type == GuiComponent::CallbackType::PRIMARY);
});
}
void GuiInventoryList::hoverEvent(bool hovered, glm::ivec2 pos) {
pos += glm::ivec2(glm::vec2(this->padding.x, this->padding.y) * this->scale);
if (hovered) {
if (!this->hovered) hoverRect->setScale({16*scale.x, 16*scale.y});
glm::ivec2 slot = pos / (glm::ivec2(this->scale) * this->innerPadding);
slot.x = std::min(slot.x, static_cast<int>(list->getWidth() - 1));
slot.y = std::min(slot.y, list->getLength() / list->getWidth() - 1);
glm::ivec2 highlightPos = slot * glm::ivec2(this->scale) * this->innerPadding;
hoverRect->setPos(highlightPos);
}
else if (this->hovered) hoverRect->setScale({});
pos += glm::ivec2(glm::vec2(this->padding.x, this->padding.y) * this->scale);
if (hovered) {
if (!this->hovered) hoverRect->setScale({ 16 * scale.x, 16 * scale.y });
glm::ivec2 slot = pos / (glm::ivec2(this->scale) * this->innerPadding);
slot.x = std::min(slot.x, static_cast<int>(list->getWidth() - 1));
slot.y = std::min(slot.y, list->getLength() / list->getWidth() - 1);
glm::ivec2 highlightPos = slot * glm::ivec2(this->scale) * this->innerPadding;
hoverRect->setPos(highlightPos);
}
else if (this->hovered) hoverRect->setScale({});
}
void GuiInventoryList::interactEvent(glm::ivec2 pos, bool primary) {
if (list->getWidth() == 0) return;
pos += glm::ivec2(glm::vec2(this->padding.x, this->padding.y) * this->scale);
glm::ivec2 slot = pos / (glm::ivec2(this->scale) * this->innerPadding);
slot.x = std::min(slot.x, static_cast<int>(list->getWidth() - 1));
slot.y = std::min(slot.y, list->getLength() / list->getWidth() - 1);
unsigned short index = slot.x + slot.y * list->getWidth();
if (index >= list->getLength()) return;
list->interact(cursor, primary, index);
if (list->getWidth() == 0) return;
pos += glm::ivec2(glm::vec2(this->padding.x, this->padding.y) * this->scale);
glm::ivec2 slot = pos / (glm::ivec2(this->scale) * this->innerPadding);
slot.x = std::min(slot.x, static_cast<int>(list->getWidth() - 1));
slot.y = std::min(slot.y, list->getLength() / list->getWidth() - 1);
unsigned short index = slot.x + slot.y * list->getWidth();
if (index >= list->getLength()) return;
list->interact(cursor, primary, index);
}
void GuiInventoryList::drawContents() {
if (list->getWidth() == 0) return;
unsigned short length = this->length == 0 ? list->getLength() : this->length;
this->hitbox = glm::ivec2 {
padding.x + list->getWidth() * (innerPadding.x*scale.x),
padding.y + (list->getLength() / list->getWidth()) * (innerPadding.y*scale.y)
};
empty();
auto fontRef = defs.l()->textures["font"];
Font f(defs.l()->textures, fontRef);
for (unsigned short i = 0; i < list->getLength() / list->getWidth(); i++) {
for (unsigned short j = 0; j < list->getWidth(); j++) {
unsigned short stackInd = j + i * list->getWidth();
if (stackInd >= length) break;
if (list->getWidth() == 0) return;
unsigned short length = this->length == 0 ? list->getLength() : this->length;
this->hitbox = glm::ivec2{
padding.x + list->getWidth() * (innerPadding.x * scale.x),
padding.y + (list->getLength() / list->getWidth()) * (innerPadding.y * scale.y)
};
empty();
auto fontRef = defs.l()->textures["font"];
Font f(defs.l()->textures, fontRef);
for (unsigned short i = 0; i < list->getLength() / list->getWidth(); i++) {
for (unsigned short j = 0; j < list->getWidth(); j++) {
unsigned short stackInd = j + i * list->getWidth();
if (stackInd >= length) break;
// auto bg = std::make_shared<GuiRect>("background_" + to_string(i) + "_" + to_string(j));
// bg->create(scale * 16.f, {}, {1, 0, 0, 0.3});
// add(bg);
// bg->setPos({padding.x + j * (16*scale.x+innerPadding.x/scale.x), padding.y + i * (16*scale.y+innerPadding.y/scale.y)});
auto stack = list->getStack(stackInd);
if (stack.id == 0) continue;
auto item = std::make_shared<GuiInventoryItem>("item_" + std::to_string(i) + "_" + std::to_string(j));
item->create(scale, stack.count, defs->getDefs().fromId(stack.id), f);
add(item);
item->setPos({padding.x + j * (16*scale.x+innerPadding.x/scale.x), padding.y + i * (16*scale.y+innerPadding.y/scale.y)});
}
}
add(hoverRect);
auto stack = list->getStack(stackInd);
if (stack.id == 0) continue;
auto item = std::make_shared<GuiInventoryItem>("item_" + std::to_string(i) + "_" + std::to_string(j));
item->create(scale, stack.count, defs->getDefs().fromId(stack.id), f);
add(item);
item->setPos({ padding.x + j * (16 * scale.x + innerPadding.x / scale.x),
padding.y + i * (16 * scale.y + innerPadding.y / scale.y) });
}
}
add(hoverRect);
}
GuiInventoryList::~GuiInventoryList() {
if (list) list.l()->removeGuiCallback(myCallback);
if (list) list.l()->removeGuiCallback(myCallback);
}

View File

@ -9,39 +9,47 @@
#include "util/CovariantPtr.h"
class LocalSubgame;
class LuaGuiElement;
class LocalInventoryRefs;
class LocalInventoryList;
class GuiInventoryList : public GuiContainer {
public:
GuiInventoryList() = default;
GuiInventoryList(const std::string& key);
~GuiInventoryList() override;
static std::shared_ptr<GuiInventoryList> fromSerialized(const LuaGuiElement& elem,
SubgamePtr game, glm::ivec2 bounds, InventoryRefsPtr refs);
void create(glm::vec2 scale, glm::vec4 padding, glm::ivec2 innerPadding,
InventoryListPtr list, InventoryListPtr cursor, SubgamePtr defs,
unsigned short start = 0, unsigned short length = 0);
void setCallback(CallbackType type, const callback& cb) override;
void hoverEvent(bool hovered, glm::ivec2 pos);
void interactEvent(glm::ivec2 pos, bool primary);
void drawContents();
private:
std::shared_ptr<GuiRect> hoverRect = std::make_shared<GuiRect>("hover_rect");
std::shared_ptr<std::function<void()>> myCallback = nullptr;
InventoryListPtr list;
InventoryListPtr cursor;
unsigned short start = 0;
unsigned short length = 0;
glm::ivec2 innerPadding;
SubgamePtr defs = SubgamePtr();
public:
GuiInventoryList() = default;
GuiInventoryList(const std::string& key);
~GuiInventoryList() override;
static std::shared_ptr<GuiInventoryList> fromSerialized(const LuaGuiElement& elem,
SubgamePtr game, glm::ivec2 bounds, InventoryRefsPtr refs);
void create(glm::vec2 scale, glm::vec4 padding, glm::ivec2 innerPadding,
InventoryListPtr list, InventoryListPtr cursor, SubgamePtr defs,
unsigned short start = 0, unsigned short length = 0);
void setCallback(CallbackType type, const callback& cb) override;
void hoverEvent(bool hovered, glm::ivec2 pos);
void interactEvent(glm::ivec2 pos, bool primary);
void drawContents();
private:
std::shared_ptr<GuiRect> hoverRect = std::make_shared<GuiRect>("hover_rect");
std::shared_ptr<std::function<void()>> myCallback = nullptr;
InventoryListPtr list;
InventoryListPtr cursor;
unsigned short start = 0;
unsigned short length = 0;
glm::ivec2 innerPadding;
SubgamePtr defs = SubgamePtr();
};

View File

@ -4,52 +4,54 @@
#include "GuiLabelledGraph.h"
GuiLabelledGraph::GuiLabelledGraph(const std::string &key) : GuiContainer(key) {}
GuiLabelledGraph::GuiLabelledGraph(const std::string& key) : GuiContainer(key) {}
void GuiLabelledGraph::create(glm::vec2 scale, glm::vec4 padding, const std::string &title,
unsigned int graphLength, unsigned int graphScale,
std::shared_ptr<AtlasRef> graphTextureRef, Font font) {
const static int GRAPH_PAD_X = 2;
const static int GRAPH_PAD_Y = 62;
const static int TEXT_PAD_X = 4;
const static int TEXT_PAD_Y = 8;
this->scale = scale;
this->padding = padding;
this->title = title;
this->font = std::move(font);
this->graphTextureRef = std::move(graphTextureRef);
auto background = std::make_shared<GuiRect>("background");
background->create(scale, {}, {0.1, 0.1, 0.1, 0.2}, {0.1, 0.1, 0.1, 0.2}, {0.1, 0.1, 0.1, 0.7}, {0.1, 0.1, 0.1, 0.7});
add(background);
background->setPos({0, 0});
auto graph = std::make_shared<GuiGraph>("graph");
graph->create({scale.x / (graphLength + GRAPH_PAD_X), scale.y * 0.4}, {}, this->graphTextureRef, graphLength, graphScale, true);
add(graph);
graph->setPos({GRAPH_PAD_X, GRAPH_PAD_Y});
auto label = std::make_shared<GuiText>("label");
label->create({2, 2}, {}, {}, {1, 1, 1, 1}, this->font);
add(label);
label->setPos({TEXT_PAD_X, TEXT_PAD_Y});
for (float &i : history) i = 0;
void GuiLabelledGraph::create(glm::vec2 scale, glm::vec4 padding, const std::string& title,
unsigned int graphLength, unsigned int graphScale,
std::shared_ptr<AtlasRef> graphTextureRef, Font font) {
const static int GRAPH_PAD_X = 2;
const static int GRAPH_PAD_Y = 62;
const static int TEXT_PAD_X = 4;
const static int TEXT_PAD_Y = 8;
this->scale = scale;
this->padding = padding;
this->title = title;
this->font = std::move(font);
this->graphTextureRef = std::move(graphTextureRef);
auto background = std::make_shared<GuiRect>("background");
background->create(scale, {}, { 0.1, 0.1, 0.1, 0.2 }, { 0.1, 0.1, 0.1, 0.2 }, { 0.1, 0.1, 0.1, 0.7 },
{ 0.1, 0.1, 0.1, 0.7 });
add(background);
background->setPos({ 0, 0 });
auto graph = std::make_shared<GuiGraph>("graph");
graph->create({ scale.x / (graphLength + GRAPH_PAD_X), scale.y * 0.4 }, {}, this->graphTextureRef, graphLength,
graphScale, true);
add(graph);
graph->setPos({ GRAPH_PAD_X, GRAPH_PAD_Y });
auto label = std::make_shared<GuiText>("label");
label->create({ 2, 2 }, {}, {}, { 1, 1, 1, 1 }, this->font);
add(label);
label->setPos({ TEXT_PAD_X, TEXT_PAD_Y });
for (float& i : history) i = 0;
}
void GuiLabelledGraph::pushValue(float value) {
get<GuiGraph>("graph")->pushValue(value);
history[ind] = value;
if (++ind >= 5) {
ind = 0;
std::string stringVal = (value == static_cast<int>(value))
? std::to_string(static_cast<int>(value))
: Util::floatToString(value);
get<GuiText>("label")->setText(title + ": " + stringVal);
}
get<GuiGraph>("graph")->pushValue(value);
history[ind] = value;
if (++ind >= 5) {
ind = 0;
std::string stringVal = (value == static_cast<int>(value))
? std::to_string(static_cast<int>(value))
: Util::floatToString(value);
get<GuiText>("label")->setText(title + ": " + stringVal);
}
}

View File

@ -12,22 +12,24 @@
#include "world/dim/ent/DrawableEntity.h"
class GuiLabelledGraph : public GuiContainer {
public:
GuiLabelledGraph() = default;
GuiLabelledGraph(const std::string& key);
void create(glm::vec2 scale, glm::vec4 padding, const std::string& title,
unsigned int graphLength, unsigned int graphScale,
std::shared_ptr<AtlasRef> graphTextureRef, Font font);
void pushValue(float value);
private:
std::string title;
std::shared_ptr<AtlasRef> graphTextureRef;
Font font;
int ind = 0;
float history[5] {};
public:
GuiLabelledGraph() = default;
GuiLabelledGraph(const std::string& key);
void create(glm::vec2 scale, glm::vec4 padding, const std::string& title,
unsigned int graphLength, unsigned int graphScale,
std::shared_ptr<AtlasRef> graphTextureRef, Font font);
void pushValue(float value);
private:
std::string title;
std::shared_ptr<AtlasRef> graphTextureRef;
Font font;
int ind = 0;
float history[5]{};
};

View File

@ -17,189 +17,190 @@
#include "lua/modules/mSetGui.h"
#include "lua/modules/mStartGame.h"
MenuSandbox::MenuSandbox(glm::ivec2 &win, Client& client, std::shared_ptr<GuiContainer> container) :
LuaParser(*client.game),
win(win),
client(client),
container(container),
luaContainer(std::dynamic_pointer_cast<GuiContainer>(container->add(std::make_shared<GuiContainer>("__lua")))),
builder(client.game->textures, client.game->models, luaContainer) {}
MenuSandbox::MenuSandbox(glm::ivec2& win, Client& client, std::shared_ptr<GuiContainer> container) :
LuaParser(*client.game),
win(win),
client(client),
container(container),
luaContainer(std::dynamic_pointer_cast<GuiContainer>(container->add(std::make_shared<GuiContainer>("__lua")))),
builder(client.game->textures, client.game->models, luaContainer) {}
void MenuSandbox::reset() {
container->remove("error");
builder.clear(true);
core = {};
mod = {};
lua = sol::state {};
lua.open_libraries(sol::lib::base, sol::lib::string, sol::lib::math, sol::lib::table, sol::lib::debug);
loadApi();
container->remove("error");
builder.clear(true);
core = {};
mod = {};
lua = sol::state{};
lua.open_libraries(sol::lib::base, sol::lib::string, sol::lib::math, sol::lib::table, sol::lib::debug);
loadApi();
}
void MenuSandbox::loadApi() {
//Create Zepha Table
core = lua.create_table();
lua["zepha"] = core;
core["__builtin"] = lua.create_table();
modules.emplace_back(std::make_unique<Api::Module::Time>(Api::State::CLIENT, lua, core));
ClientApi::gui_element(lua);
MenuApi::set_gui (builder, win, lua, core);
MenuApi::start_game (client, core);
bindModules();
// Create sandboxed runfile()
lua["dofile"] = lua["loadfile"] = sol::nil;
lua.set_function("runfile", &MenuSandbox::runFileSandboxed, this);
//Create Zepha Table
core = lua.create_table();
lua["zepha"] = core;
core["__builtin"] = lua.create_table();
modules.emplace_back(std::make_unique<Api::Module::Time>(Api::State::CLIENT, lua, core));
ClientApi::gui_element(lua);
MenuApi::set_gui(builder, win, lua, core);
MenuApi::start_game(client, core);
bindModules();
// Create sandboxed runfile()
lua["dofile"] = lua["loadfile"] = sol::nil;
lua.set_function("runfile", &MenuSandbox::runFileSandboxed, this);
}
void MenuSandbox::load(const SubgameDef& subgame) {
reset();
try {
loadAndRunMod(subgame.subgamePath + "/../../assets/base");
loadAndRunMod(subgame.subgamePath + "/menu");
}
catch (const std::runtime_error& e) {
showError(e.what(), subgame.config.name);
}
reset();
try {
loadAndRunMod(subgame.subgamePath + "/../../assets/base");
loadAndRunMod(subgame.subgamePath + "/menu");
}
catch (const std::runtime_error& e) {
showError(e.what(), subgame.config.name);
}
}
void MenuSandbox::windowResized() {
builder.build(win);
builder.build(win);
}
void MenuSandbox::update(double delta) {
builder.update();
core["__builtin"]["update_delayed_functions"]();
builder.update();
core["__builtin"]["update_delayed_functions"]();
}
sol::protected_function_result MenuSandbox::runFileSandboxed(const std::string& file) {
for (LuaMod::File& f : mod.files) {
if (f.path != file) continue;
sol::environment env(lua, sol::create, lua.globals());
env["_PATH"] = f.path.substr(0, f.path.find_last_of('/') + 1);
env["_FILE"] = f.path;
env["_MODNAME"] = mod.config.name;
return lua.safe_script(f.file, env, std::bind(&MenuSandbox::errorCallback,
this, std::placeholders::_2), "@" + f.path, sol::load_mode::text);
}
throw std::runtime_error("Error opening '" + file + "', file not found.");
for (LuaMod::File& f : mod.files) {
if (f.path != file) continue;
sol::environment env(lua, sol::create, lua.globals());
env["_PATH"] = f.path.substr(0, f.path.find_last_of('/') + 1);
env["_FILE"] = f.path;
env["_MODNAME"] = mod.config.name;
return lua.safe_script(f.file, env, std::bind(&MenuSandbox::errorCallback,
this, std::placeholders::_2), "@" + f.path, sol::load_mode::text);
}
throw std::runtime_error("Error opening '" + file + "', file not found.");
}
void MenuSandbox::loadAndRunMod(const std::string &modPath) {
if (!cf_file_exists(modPath.data())) throw std::runtime_error("Directory not found.");
LuaMod mod;
std::string root = modPath + "/script";
std::list<std::string> dirsToScan {root};
std::list<std::string> luaFiles {};
cf_dir_t dir;
while (!dirsToScan.empty()) {
std::string dirStr = *dirsToScan.begin();
dirsToScan.erase(dirsToScan.begin());
if (!cf_file_exists(dirStr.data())) throw std::runtime_error("Missing 'script' directory.");
cf_dir_open(&dir, dirStr.data());
while (dir.has_next) {
// Read through files in the directory
cf_file_t scannedFile;
cf_read_file(&dir, &scannedFile);
if (strncmp(scannedFile.name, ".", 1) != 0) {
if (scannedFile.is_dir) dirsToScan.emplace_back(scannedFile.path);
else {
auto path = std::string_view(scannedFile.path);
if (path.rfind('.') != std::string::npos && path.rfind('.') == path.rfind(".lua"))
luaFiles.emplace_back(scannedFile.path);
}
}
cf_dir_next(&dir);
}
cf_dir_close(&dir);
}
mod.modPath = modPath;
for (std::string& file : luaFiles) {
size_t rootPos = file.find(root);
std::string modPath = file;
if (rootPos == std::string::npos)
throw std::runtime_error("Attempted to access file \"" + file + "\", which is outside of the mod root.");
modPath.erase(rootPos, root.length() + 1);
modPath.resize(modPath.size() - 4);
std::ifstream t(file);
std::string fileStr((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
LuaMod::File f {modPath, fileStr};
mod.files.push_back(f);
}
std::string texPath = modPath + "/textures";
if (cf_file_exists(texPath.data())) {
this->modAssets = client.game->textures.loadDirectory(texPath, false, true);
}
this->mod = mod;
runFileSandboxed("init");
void MenuSandbox::loadAndRunMod(const std::string& modPath) {
if (!cf_file_exists(modPath.data())) throw std::runtime_error("Directory not found.");
LuaMod mod;
std::string root = modPath + "/script";
std::list<std::string> dirsToScan{ root };
std::list<std::string> luaFiles{};
cf_dir_t dir;
while (!dirsToScan.empty()) {
std::string dirStr = *dirsToScan.begin();
dirsToScan.erase(dirsToScan.begin());
if (!cf_file_exists(dirStr.data())) throw std::runtime_error("Missing 'script' directory.");
cf_dir_open(&dir, dirStr.data());
while (dir.has_next) {
// Read through files in the directory
cf_file_t scannedFile;
cf_read_file(&dir, &scannedFile);
if (strncmp(scannedFile.name, ".", 1) != 0) {
if (scannedFile.is_dir) dirsToScan.emplace_back(scannedFile.path);
else {
auto path = std::string_view(scannedFile.path);
if (path.rfind('.') != std::string::npos && path.rfind('.') == path.rfind(".lua"))
luaFiles.emplace_back(scannedFile.path);
}
}
cf_dir_next(&dir);
}
cf_dir_close(&dir);
}
mod.modPath = modPath;
for (std::string& file : luaFiles) {
size_t rootPos = file.find(root);
std::string modPath = file;
if (rootPos == std::string::npos)
throw std::runtime_error("Attempted to access file \"" + file + "\", which is outside of the mod root.");
modPath.erase(rootPos, root.length() + 1);
modPath.resize(modPath.size() - 4);
std::ifstream t(file);
std::string fileStr((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
LuaMod::File f{ modPath, fileStr };
mod.files.push_back(f);
}
std::string texPath = modPath + "/textures";
if (cf_file_exists(texPath.data())) {
this->modAssets = client.game->textures.loadDirectory(texPath, false, true);
}
this->mod = mod;
runFileSandboxed("init");
}
void MenuSandbox::showError(const std::string& what, const std::string& subgame) {
const std::string errPrefixText = "Encountered an error while loading the menu for " + subgame + " ;-;";
Font f(client.game->textures, client.game->textures["font"]);
auto errWrap = std::make_shared<GuiContainer>("error");
container->add(errWrap);
auto errPrefix = std::make_shared<GuiText>("error_text");
errPrefix->create({3, 3}, {}, {0.7, 0, 0.3, 1}, {1, 1, 1, 1}, f);
errPrefix->setText(errPrefixText);
errPrefix->setPos({8, 16});
errWrap->add(errPrefix);
auto errMsg = std::make_shared<GuiText>("error_text");
errMsg->create({3, 3}, {}, {}, {1, 0.5, 0.6, 1}, f);
errMsg->setText(what);
errMsg->setPos({8, 52});
errWrap->add(errMsg);
const std::string errPrefixText = "Encountered an error while loading the menu for " + subgame + " ;-;";
Font f(client.game->textures, client.game->textures["font"]);
auto errWrap = std::make_shared<GuiContainer>("error");
container->add(errWrap);
auto errPrefix = std::make_shared<GuiText>("error_text");
errPrefix->create({ 3, 3 }, {}, { 0.7, 0, 0.3, 1 }, { 1, 1, 1, 1 }, f);
errPrefix->setText(errPrefixText);
errPrefix->setPos({ 8, 16 });
errWrap->add(errPrefix);
auto errMsg = std::make_shared<GuiText>("error_text");
errMsg->create({ 3, 3 }, {}, {}, { 1, 0.5, 0.6, 1 }, f);
errMsg->setText(what);
errMsg->setPos({ 8, 52 });
errWrap->add(errMsg);
}
sol::protected_function_result MenuSandbox::errorCallback(sol::protected_function_result r) const {
sol::error err = r;
std::string errString = err.what();
try {
std::string::size_type lineNumStart = errString.find(':');
if (lineNumStart == std::string::npos) throw std::out_of_range("Improperly formatted error. [0]");
std::string::size_type lineNumEnd = errString.find(':', lineNumStart + 1);
if (lineNumEnd == std::string::npos) throw std::out_of_range("Improperly formatted error. [1]");
std::string fileName = errString.substr(0, lineNumStart);
int lineNum = std::stoi(errString.substr(lineNumStart + 1, lineNumEnd - lineNumStart - 1));
for (const LuaMod::File& file : mod.files) if (file.path == fileName)
throw std::runtime_error(ErrorFormatter::formatError(fileName, lineNum, errString, file.file));
throw std::out_of_range("Error thrown outside of handled files. [2]");
}
catch (const std::runtime_error& e) {
std::cout << Log::err << e.what() << std::endl;
throw;
}
catch (const std::out_of_range& e) {
std::cout << Log::err << "Failed to format error, " << e.what() << Log::endl;
throw std::runtime_error(errString);
}
sol::error err = r;
std::string errString = err.what();
try {
std::string::size_type lineNumStart = errString.find(':');
if (lineNumStart == std::string::npos) throw std::out_of_range("Improperly formatted error. [0]");
std::string::size_type lineNumEnd = errString.find(':', lineNumStart + 1);
if (lineNumEnd == std::string::npos) throw std::out_of_range("Improperly formatted error. [1]");
std::string fileName = errString.substr(0, lineNumStart);
int lineNum = std::stoi(errString.substr(lineNumStart + 1, lineNumEnd - lineNumStart - 1));
for (const LuaMod::File& file : mod.files)
if (file.path == fileName)
throw std::runtime_error(ErrorFormatter::formatError(fileName, lineNum, errString, file.file));
throw std::out_of_range("Error thrown outside of handled files. [2]");
}
catch (const std::runtime_error& e) {
std::cout << Log::err << e.what() << std::endl;
throw;
}
catch (const std::out_of_range& e) {
std::cout << Log::err << "Failed to format error, " << e.what() << Log::endl;
throw std::runtime_error(errString);
}
}

View File

@ -10,37 +10,46 @@
#include "client/gui/GuiBuilder.h"
class Client;
class Subgame;
class AtlasRef;
class SubgameDef;
class GuiContainer;
class MenuSandbox : LuaParser {
public:
MenuSandbox(glm::ivec2& window, Client& client, std::shared_ptr<GuiContainer> container);
void load(const SubgameDef& subgame);
void update(double delta) override;
void windowResized();
using LuaParser::update;
private:
void reset();
void loadApi();
void loadAndRunMod(const std::string& modPath);
void showError(const std::string& what, const std::string& subgame);
sol::protected_function_result runFileSandboxed(const std::string& file);
virtual sol::protected_function_result errorCallback(sol::protected_function_result r) const override;
LuaMod mod {};
std::vector<std::shared_ptr<AtlasRef>> modAssets {};
std::shared_ptr<GuiContainer> container = nullptr;
std::shared_ptr<GuiContainer> luaContainer = nullptr;
GuiBuilder builder;
Client& client;
glm::ivec2& win;
public:
MenuSandbox(glm::ivec2& window, Client& client, std::shared_ptr<GuiContainer> container);
void load(const SubgameDef& subgame);
void update(double delta) override;
void windowResized();
using LuaParser::update;
private:
void reset();
void loadApi();
void loadAndRunMod(const std::string& modPath);
void showError(const std::string& what, const std::string& subgame);
sol::protected_function_result runFileSandboxed(const std::string& file);
virtual sol::protected_function_result errorCallback(sol::protected_function_result r) const override;
LuaMod mod{};
std::vector<std::shared_ptr<AtlasRef>> modAssets{};
std::shared_ptr<GuiContainer> container = nullptr;
std::shared_ptr<GuiContainer> luaContainer = nullptr;
GuiBuilder builder;
Client& client;
glm::ivec2& win;
};

View File

@ -7,7 +7,7 @@
#include <string>
struct SubgameConfig {
std::string name;
std::string description;
std::string version;
std::string name;
std::string description;
std::string version;
};

View File

@ -11,8 +11,8 @@
class AtlasRef;
class SubgameDef {
public:
std::shared_ptr<AtlasRef> iconRef = nullptr;
SubgameConfig config {};
std::string subgamePath = "";
public:
std::shared_ptr<AtlasRef> iconRef = nullptr;
SubgameConfig config{};
std::string subgamePath = "";
};

View File

@ -25,228 +25,222 @@
* @param addr - The server address to connect to.
*/
ConnectScene::ConnectScene(Client &client, Address addr) : Scene(client),
connection(client.connection) {
client.renderer.setClearColor(10, 10, 10);
Font f(client.game->textures, client.game->textures["font"]);
auto statusText = std::make_shared<GuiText>("statusText");
statusText->create({2, 2}, {}, {}, {1, 1, 1, 1}, f);
statusText->setText("Connecting...");
statusText->setPos({32, 24});
components.add(statusText);
auto loadBar = std::make_shared<GuiRect>("loadBar");
loadBar->create({1, 32}, {}, {0.17, 0.75, 0.93, 1});
loadBar->setPos({0, client.renderer.window.getSize().y - 32});
components.add(loadBar);
connection.attemptConnect(std::move(addr));
client.renderer.window.addResizeCallback("scene", [&](glm::ivec2 win) {
components.get<GuiRect>("loadBar")->setPos({0, win.y - 32});
});
ConnectScene::ConnectScene(Client& client, Address addr) : Scene(client),
connection(client.connection) {
client.renderer.setClearColor(10, 10, 10);
Font f(client.game->textures, client.game->textures["font"]);
auto statusText = std::make_shared<GuiText>("statusText");
statusText->create({ 2, 2 }, {}, {}, { 1, 1, 1, 1 }, f);
statusText->setText("Connecting...");
statusText->setPos({ 32, 24 });
components.add(statusText);
auto loadBar = std::make_shared<GuiRect>("loadBar");
loadBar->create({ 1, 32 }, {}, { 0.17, 0.75, 0.93, 1 });
loadBar->setPos({ 0, client.renderer.window.getSize().y - 32 });
components.add(loadBar);
connection.attemptConnect(std::move(addr));
client.renderer.window.addResizeCallback("scene", [&](glm::ivec2 win) {
components.get<GuiRect>("loadBar")->setPos({ 0, win.y - 32 });
});
}
void ConnectScene::update() {
client.game->textures.update();
switch (connectState) {
default:
throw std::runtime_error("Invalid connection state.");
case State::DONE:
case State::FAILED_CONNECT:
break;
case State::CONNECTING:
handleConnecting();
break;
case State::PROPERTIES: {
components.get<GuiRect>("loadBar")->setScale({client.renderer.window.getSize().x * 0.1, 32});
ENetEvent e;
if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) {
PacketView p(e.packet);
if (p.type == Packet::Type::SERVER_INFO) {
auto statusText = components.get<GuiText>("statusText");
statusText->setText(statusText->getText() + "Received server properties.\n");
// TODO: Reimplement this somewhere or something.
client.game->textures.update();
switch (connectState) {
default:throw std::runtime_error("Invalid connection state.");
case State::DONE:
case State::FAILED_CONNECT:break;
case State::CONNECTING:handleConnecting();
break;
case State::PROPERTIES: {
components.get<GuiRect>("loadBar")->setScale({ client.renderer.window.getSize().x * 0.1, 32 });
ENetEvent e;
if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) {
PacketView p(e.packet);
if (p.type == Packet::Type::SERVER_INFO) {
auto statusText = components.get<GuiText>("statusText");
statusText->setText(statusText->getText() + "Received server properties.\n");
// TODO: Reimplement this somewhere or something.
// state.seed = p.d.read<unsigned int>();
connectState = State::IDENTIFIER_LIST;
Packet resp(Packet::Type::BLOCK_IDENTIFIER_LIST);
resp.sendTo(connection.getPeer(), Packet::Channel::CONNECT);
}
}
break;
}
case State::IDENTIFIER_LIST: {
components.get<GuiRect>("loadBar")->setScale({client.renderer.window.getSize().x * 0.2, 32});
ENetEvent e;
if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) {
PacketView p(e.packet);
if (p.type == Packet::Type::BLOCK_IDENTIFIER_LIST) {
auto statusText = components.get<GuiText>("statusText");
statusText->setText(statusText->getText() + "Received block index-identifier table.\n");
client.game->getDefs().setIdentifiers(p.d.read<std::vector<std::string>>());
Packet resp(Packet::Type::BIOME_IDENTIFIER_LIST);
resp.sendTo(connection.getPeer(), Packet::Channel::CONNECT);
}
else if (p.type == Packet::Type::BIOME_IDENTIFIER_LIST) {
auto statusText = components.get<GuiText>("statusText");
statusText->setText(statusText->getText() + "Received biome index-identifier table.\nDownloading mods...\n");
client.game->getBiomes().setIdentifiers(p.d.read<std::vector<std::string>>());
connectState = State::MODS;
Packet resp(Packet::Type::MODS);
resp.sendTo(connection.getPeer(), Packet::Channel::CONNECT);
}
}
break;
}
case State::MODS: {
components.get<GuiRect>("loadBar")->setScale({client.renderer.window.getSize().x * 0.4, 32});
ENetEvent e;
if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) {
PacketView p(e.packet);
auto statusText = components.get<GuiText>("statusText");
if (p.type == Packet::Type::MODS) {
auto luaMod = LuaMod::fromPacket(p);
statusText->setText(statusText->getText() + "Received mod " + luaMod.config.name + ".\n");
client.game->getParser().getHandler().addLuaMod(std::move(luaMod));
}
else if (p.type == Packet::Type::MOD_ORDER) {
client.game->getParser().getHandler().setModsOrder(p.d.read<std::vector<std::string>>());
statusText->setText(statusText->getText() + "Done downloading mods.\nReceived the mods order.\nDownloading media...\n");
connectState = State::MEDIA;
Packet resp(Packet::Type::MEDIA);
resp.sendTo(connection.getPeer(), Packet::Channel::CONNECT);
}
}
break;
}
case State::MEDIA: {
components.get<GuiRect>("loadBar")->setScale({client.renderer.window.getSize().x * 0.6, 32});
ENetEvent e;
if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) {
PacketView p(e.packet);
auto statusText = components.get<GuiText>("statusText");
if (p.type == Packet::Type::MEDIA) {
AssetType t = static_cast<AssetType>(p.d.read<int>());
unsigned int count = 0;
while (t != AssetType::END) {
std::string assetName = p.d.read<std::string>();
if (t == AssetType::TEXTURE) {
int width = p.d.read<unsigned int>();
int height = p.d.read<unsigned int>();
std::string data = p.d.read<std::string>();
std::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);
}
else if (t == AssetType::MODEL) {
std::string format = p.d.read<std::string>();
std::string data = p.d.read<std::string>();
client.game->models.models.insert({assetName, SerializedModel{assetName, data, format}});
}
t = static_cast<AssetType>(p.d.read<int>());
count++;
}
statusText->setText(statusText->getText() + "Received " + std::to_string(count) + "x media files.\n");
}
else if (p.type == Packet::Type::MEDIA_DONE) {
components.get<GuiRect>("loadBar")->setScale({client.renderer.window.getSize().x, 32});
statusText->setText(statusText->getText() + "Done downloading media.\nJoining world...\n");
connectState = State::DONE;
client.scene.setScene(std::make_unique<GameScene>(client));
}
}
break;
}
}
connectState = State::IDENTIFIER_LIST;
Packet resp(Packet::Type::BLOCK_IDENTIFIER_LIST);
resp.sendTo(connection.getPeer(), Packet::Channel::CONNECT);
}
}
break;
}
case State::IDENTIFIER_LIST: {
components.get<GuiRect>("loadBar")->setScale({ client.renderer.window.getSize().x * 0.2, 32 });
ENetEvent e;
if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) {
PacketView p(e.packet);
if (p.type == Packet::Type::BLOCK_IDENTIFIER_LIST) {
auto statusText = components.get<GuiText>("statusText");
statusText->setText(statusText->getText() + "Received block index-identifier table.\n");
client.game->getDefs().setIdentifiers(p.d.read<std::vector<std::string>>());
Packet resp(Packet::Type::BIOME_IDENTIFIER_LIST);
resp.sendTo(connection.getPeer(), Packet::Channel::CONNECT);
}
else if (p.type == Packet::Type::BIOME_IDENTIFIER_LIST) {
auto statusText = components.get<GuiText>("statusText");
statusText->setText(
statusText->getText() + "Received biome index-identifier table.\nDownloading mods...\n");
client.game->getBiomes().setIdentifiers(p.d.read<std::vector<std::string>>());
connectState = State::MODS;
Packet resp(Packet::Type::MODS);
resp.sendTo(connection.getPeer(), Packet::Channel::CONNECT);
}
}
break;
}
case State::MODS: {
components.get<GuiRect>("loadBar")->setScale({ client.renderer.window.getSize().x * 0.4, 32 });
ENetEvent e;
if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) {
PacketView p(e.packet);
auto statusText = components.get<GuiText>("statusText");
if (p.type == Packet::Type::MODS) {
auto luaMod = LuaMod::fromPacket(p);
statusText->setText(statusText->getText() + "Received mod " + luaMod.config.name + ".\n");
client.game->getParser().getHandler().addLuaMod(std::move(luaMod));
}
else if (p.type == Packet::Type::MOD_ORDER) {
client.game->getParser().getHandler().setModsOrder(p.d.read<std::vector<std::string>>());
statusText->setText(
statusText->getText() + "Done downloading mods.\nReceived the mods order.\nDownloading media...\n");
connectState = State::MEDIA;
Packet resp(Packet::Type::MEDIA);
resp.sendTo(connection.getPeer(), Packet::Channel::CONNECT);
}
}
break;
}
case State::MEDIA: {
components.get<GuiRect>("loadBar")->setScale({ client.renderer.window.getSize().x * 0.6, 32 });
ENetEvent e;
if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) {
PacketView p(e.packet);
auto statusText = components.get<GuiText>("statusText");
if (p.type == Packet::Type::MEDIA) {
AssetType t = static_cast<AssetType>(p.d.read<int>());
unsigned int count = 0;
while (t != AssetType::END) {
std::string assetName = p.d.read<std::string>();
if (t == AssetType::TEXTURE) {
int width = p.d.read<unsigned int>();
int height = p.d.read<unsigned int>();
std::string data = p.d.read<std::string>();
std::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);
}
else if (t == AssetType::MODEL) {
std::string format = p.d.read<std::string>();
std::string data = p.d.read<std::string>();
client.game->models.models.insert({ assetName, SerializedModel{ assetName, data, format }});
}
t = static_cast<AssetType>(p.d.read<int>());
count++;
}
statusText->setText(statusText->getText() + "Received " + std::to_string(count) + "x media files.\n");
}
else if (p.type == Packet::Type::MEDIA_DONE) {
components.get<GuiRect>("loadBar")->setScale({ client.renderer.window.getSize().x, 32 });
statusText->setText(statusText->getText() + "Done downloading media.\nJoining world...\n");
connectState = State::DONE;
client.scene.setScene(std::make_unique<GameScene>(client));
}
}
break;
}
}
}
void ConnectScene::handleConnecting() {
Packet resp(Packet::Type::SERVER_INFO);
auto statusText = components.get<GuiText>("statusText");
switch (connection.getConnectionStatus()) {
default:
throw std::runtime_error("Uncaught connection error.");
case ServerConnection::State::ENET_ERROR:
throw std::runtime_error("Enet Initialization error.");
break;
case ServerConnection::State::FAILED_CONNECT:
connectState = State::FAILED_CONNECT;
statusText->setText(statusText->getText() + "\nFailed to connect :(\n");
break;
case ServerConnection::State::ATTEMPTING_CONNECT:
connection.processConnecting();
dotsTime += client.getDelta();
if (dotsTime > 1) {
dotsTime -= 1;
statusText->setText(statusText->getText() + ".");
}
break;
case ServerConnection::State::CONNECTED:
connectState = State::PROPERTIES;
statusText->setText(statusText->getText() + " Connected!~\n");
resp.sendTo(connection.getPeer(), Packet::Channel::CONNECT);
break;
}
Packet resp(Packet::Type::SERVER_INFO);
auto statusText = components.get<GuiText>("statusText");
switch (connection.getConnectionStatus()) {
default:throw std::runtime_error("Uncaught connection error.");
case ServerConnection::State::ENET_ERROR:throw std::runtime_error("Enet Initialization error.");
break;
case ServerConnection::State::FAILED_CONNECT:connectState = State::FAILED_CONNECT;
statusText->setText(statusText->getText() + "\nFailed to connect :(\n");
break;
case ServerConnection::State::ATTEMPTING_CONNECT:connection.processConnecting();
dotsTime += client.getDelta();
if (dotsTime > 1) {
dotsTime -= 1;
statusText->setText(statusText->getText() + ".");
}
break;
case ServerConnection::State::CONNECTED:connectState = State::PROPERTIES;
statusText->setText(statusText->getText() + " Connected!~\n");
resp.sendTo(connection.getPeer(), Packet::Channel::CONNECT);
break;
}
}
void ConnectScene::draw() {
Renderer& renderer = client.renderer;
renderer.beginChunkDeferredCalls();
renderer.endDeferredCalls();
renderer.beginGUIDrawCalls();
renderer.enableTexture(&client.game->textures.atlasTexture);
components.draw(renderer);
renderer.swapBuffers();
Renderer& renderer = client.renderer;
renderer.beginChunkDeferredCalls();
renderer.endDeferredCalls();
renderer.beginGUIDrawCalls();
renderer.enableTexture(&client.game->textures.atlasTexture);
components.draw(renderer);
renderer.swapBuffers();
}
void ConnectScene::cleanup() {
client.renderer.window.removeResizeCallback("scene");
client.renderer.window.removeResizeCallback("scene");
}

View File

@ -9,33 +9,36 @@
#include "client/gui/basic/GuiContainer.h"
class ServerConnection;
class Address;
class ConnectScene : public Scene {
public:
enum class State {
CONNECTING,
FAILED_CONNECT,
PROPERTIES,
IDENTIFIER_LIST,
MODS,
MEDIA,
DONE
};
ConnectScene(Client& state, Address addr);
void update() override;
void draw() override;
void cleanup() override;
void handleConnecting();
private:
State connectState = State::CONNECTING;
ServerConnection& connection;
GuiContainer components;
double dotsTime = 0;
public:
enum class State {
CONNECTING,
FAILED_CONNECT,
PROPERTIES,
IDENTIFIER_LIST,
MODS,
MEDIA,
DONE
};
ConnectScene(Client& state, Address addr);
void update() override;
void draw() override;
void cleanup() override;
void handleConnecting();
private:
State connectState = State::CONNECTING;
ServerConnection& connection;
GuiContainer components;
double dotsTime = 0;
};

View File

@ -9,73 +9,73 @@
#include "client/graph/Renderer.h"
GameScene::GameScene(Client& client) : Scene(client),
world(std::make_shared<LocalWorld>(client.game, client.connection, client.renderer)),
debugGui(client.renderer.window.getSize(), client.game, world) {
Packet r(Packet::Type::CONNECT_DATA_RECVD);
r.sendTo(client.connection.getPeer(), Packet::Channel::CONNECT);
world.l()->connect();
client.game->init(world, world.l()->getPlayer(), client);
world.l()->updatePlayerDimension();
client.renderer.window.addResizeCallback("gamescene", Util::bind_this(&debugGui, &DebugGui::bufferResized));
client.renderer.setClearColor(148, 194, 240);
client.renderer.window.input.lockMouse(true);
world(std::make_shared<LocalWorld>(client.game, client.connection, client.renderer)),
debugGui(client.renderer.window.getSize(), client.game, world) {
Packet r(Packet::Type::CONNECT_DATA_RECVD);
r.sendTo(client.connection.getPeer(), Packet::Channel::CONNECT);
world.l()->connect();
client.game->init(world, world.l()->getPlayer(), client);
world.l()->updatePlayerDimension();
client.renderer.window.addResizeCallback("gamescene", Util::bind_this(&debugGui, &DebugGui::bufferResized));
client.renderer.setClearColor(148, 194, 240);
client.renderer.window.input.lockMouse(true);
}
void GameScene::update() {
Window& window = client.renderer.window;
client.game->update(client.getDelta());
world->update(client.getDelta());
for (auto entity : entities) entity->update(client.getDelta());
double lastFps = 1 / client.getDelta();
debugGui.update(world.l()->getPlayer().l(), lastFps, world.l()->getActiveDimension().l()->getMeshChunkCount(),
drawCalls, world.l()->getNet().serverSideChunkGens, world.l()->getNet().recvPackets);
world.l()->getNet().serverSideChunkGens = 0;
world.l()->getNet().recvPackets = 0;
if (window.input.keyPressed(GLFW_KEY_F1)) {
hudVisible = !hudVisible;
debugGui.changeVisibilityState(hudVisible ? debugVisible ? 0 : 2 : 1);
world.l()->getPlayer().l()->setHudVisible(hudVisible);
}
if (window.input.keyPressed(GLFW_KEY_F3)) {
debugVisible = !debugVisible;
debugGui.changeVisibilityState(hudVisible ? debugVisible ? 0 : 2 : 1);
}
Window& window = client.renderer.window;
client.game->update(client.getDelta());
world->update(client.getDelta());
for (auto entity : entities) entity->update(client.getDelta());
double lastFps = 1 / client.getDelta();
debugGui.update(world.l()->getPlayer().l(), lastFps, world.l()->getActiveDimension().l()->getMeshChunkCount(),
drawCalls, world.l()->getNet().serverSideChunkGens, world.l()->getNet().recvPackets);
world.l()->getNet().serverSideChunkGens = 0;
world.l()->getNet().recvPackets = 0;
if (window.input.keyPressed(GLFW_KEY_F1)) {
hudVisible = !hudVisible;
debugGui.changeVisibilityState(hudVisible ? debugVisible ? 0 : 2 : 1);
world.l()->getPlayer().l()->setHudVisible(hudVisible);
}
if (window.input.keyPressed(GLFW_KEY_F3)) {
debugVisible = !debugVisible;
debugGui.changeVisibilityState(hudVisible ? debugVisible ? 0 : 2 : 1);
}
}
void GameScene::draw() {
Renderer& renderer = client.renderer;
Camera& camera = renderer.camera;
renderer.beginChunkDeferredCalls();
renderer.enableTexture(&client.game->textures.atlasTexture);
drawCalls = world.l()->renderChunks(renderer);
renderer.beginEntityDeferredCalls();
for (auto entity : entities) entity->draw(renderer);
world.l()->renderEntities(renderer);
renderer.endDeferredCalls();
renderer.beginGUIDrawCalls();
renderer.enableTexture(&client.game->textures.atlasTexture);
world.l()->getPlayer().l()->drawHud(renderer);
debugGui.draw(renderer);
world.l()->getPlayer().l()->drawMenu(renderer);
renderer.swapBuffers();
Renderer& renderer = client.renderer;
Camera& camera = renderer.camera;
renderer.beginChunkDeferredCalls();
renderer.enableTexture(&client.game->textures.atlasTexture);
drawCalls = world.l()->renderChunks(renderer);
renderer.beginEntityDeferredCalls();
for (auto entity : entities) entity->draw(renderer);
world.l()->renderEntities(renderer);
renderer.endDeferredCalls();
renderer.beginGUIDrawCalls();
renderer.enableTexture(&client.game->textures.atlasTexture);
world.l()->getPlayer().l()->drawHud(renderer);
debugGui.draw(renderer);
world.l()->getPlayer().l()->drawMenu(renderer);
renderer.swapBuffers();
}
void GameScene::cleanup() {
client.renderer.window.removeResizeCallback("gamescene");
client.renderer.window.removeResizeCallback("gamescene");
}

Some files were not shown because too many files have changed in this diff Show More